Skip to content

Commit 97c147e

Browse files
Merge branch 'main' into tags
2 parents b4cb645 + 5d6c397 commit 97c147e

File tree

13 files changed

+352
-116
lines changed

13 files changed

+352
-116
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"type": "cppdbg",
77
"request": "launch",
88
"program": "${workspaceFolder}/gen/cpp_hart_gen/rv32_Debug/build/iss",
9-
"args": ["-m", "rv32", "-c", "${workspaceFolder}/cfgs/mc100-32-riscv-tests.yaml", "${workspaceFolder}/ext/riscv-tests/isa/rv32ui-p-addi"],
9+
"args": ["-m", "rv32", "-c", "${workspaceFolder}/cfgs/rv32-riscv-tests.yaml", "${workspaceFolder}/ext/riscv-tests/isa/rv32ui-p-addi"],
1010
"stopAtEntry": true,
1111
"cwd": "${workspaceFolder}",
1212
"environment": [],

backends/cpp_hart_gen/cpp/include/udb/bitfield.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ namespace udb {
167167
template <template <unsigned, bool> class BitsClass, unsigned N, bool Signed>
168168
requires ((N >= Size) && (BitsClass<N, Signed>::IsABits))
169169
BitfieldMember<ParentSize, Start, Size>::template operator BitsClass<N, Signed>() const {
170-
return BitsClass<N, Signed> {static_cast<BitsType<ParentSize>>(m_parent) >> Bits<Size>(Start) & MaximumValue};
170+
return BitsClass<N, Signed> {(static_cast<BitsType<ParentSize>>(m_parent) >> Bits<ParentSize>(Start)) & MaximumValue};
171171
}
172172

173173
template <unsigned ParentSize, unsigned Start, unsigned Size>
@@ -185,7 +185,7 @@ namespace udb {
185185
&BitfieldMember<ParentSize, Start, Size>::template operator=(
186186
const BitfieldMember<ParentSize, Start, Size> &other) {
187187
m_parent = (static_cast<BitsType<ParentSize>>(m_parent) & ~Mask) |
188-
((static_cast<BitsType<Size>>(other).template widening_sll<Size>()) & Mask);
188+
((static_cast<BitsType<Size>>(other).template widening_sll<Start>()) & Mask);
189189
return *this;
190190
}
191191

backends/cpp_hart_gen/cpp/include/udb/bits.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,12 +2801,14 @@ namespace udb {
28012801
template <unsigned, bool> class MsbType, unsigned MsbN,
28022802
template <unsigned, bool> class LsbType, unsigned LsbN
28032803
>
2804-
constexpr _PossiblyUnknownBits<N, false> extract(const MsbType<MsbN, false>& msb, const LsbType<LsbN, false>& lsb) const {
2804+
constexpr _PossiblyUnknownRuntimeBits<constmax_v<MsbN, LsbN>, false> extract(const MsbType<MsbN, false>& msb, const LsbType<LsbN, false>& lsb) const {
28052805
udb_assert(msb >= lsb, "Negative range is not allowed");
28062806
udb_assert(lsb.get() <= width(), "Extract out of range");
28072807

2808-
_Bits<N, false> mask = (_Bits<N, false>{1} << (msb - lsb)) - _Bits<N, false>{1};
2809-
return _PossiblyUnknownBits<N, false>{m_val.extract(msb, lsb), m_unknown_mask.extract(msb, lsb)};
2808+
return _PossiblyUnknownRuntimeBits<constmax_v<MsbN, LsbN>, false>(
2809+
WidthArg(msb.get() - lsb.get() + 1),
2810+
ValueArg(_PossiblyUnknownBits<constmax_v<MsbN, LsbN>, false>(m_val.extract(msb, lsb), m_unknown_mask.extract(msb, lsb)))
2811+
);
28102812
}
28112813

28122814
template <unsigned Pos>
@@ -3018,8 +3020,8 @@ namespace udb {
30183020

30193021
constexpr explicit _PossiblyUnknownRuntimeBits(unsigned width) : m_width(width) {}
30203022
constexpr explicit _PossiblyUnknownRuntimeBits(const WidthArg& width) : m_width(width.width) {}
3021-
constexpr explicit _PossiblyUnknownRuntimeBits(const ValueArg<StorageType> val, const WidthArg& width) : m_val(val.value), m_width(width.width) {}
3022-
constexpr explicit _PossiblyUnknownRuntimeBits(const WidthArg& width, const ValueArg<StorageType> val) : m_val(val.value), m_width(width.width) {}
3023+
constexpr explicit _PossiblyUnknownRuntimeBits(const ValueArg<_PossiblyUnknownBits<MaxN, Signed>> val, const WidthArg& width) : m_val(val.value), m_width(width.width) {}
3024+
constexpr explicit _PossiblyUnknownRuntimeBits(const WidthArg& width, const ValueArg<_PossiblyUnknownBits<MaxN, Signed>> val) : m_val(val.value), m_width(width.width) {}
30233025

30243026
// template <std::integral T>
30253027
// constexpr _PossiblyUnknownRuntimeBits(const T &initial_value, unsigned width)

backends/cpp_hart_gen/tasks.rake

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -397,17 +397,32 @@ namespace :test do
397397

398398
task riscv_tests: ["build_riscv_tests", "build:cpp_hart"] do
399399
configs_name, build_name = configs_build_name
400-
tests = ["simple", "add", "addi", "and",
401-
"andi", "auipc", "beq", "bge", "bgeu", "blt",
402-
"bltu", "bne", "fence_i", "jal", "jalr",
403-
"lb", "lbu", "lh", "lhu", "lw", "ld_st",
404-
"lui", "ma_data", "or", "ori", "sb", "sh",
405-
"sw", "st_ld", "sll", "slli", "slt", "slti",
406-
"sltiu", "sltu", "sra", "srai", "srl",
407-
"srli", "sub", "xor", "xori"]
408-
409-
tests.each do |t|
410-
sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m rv32 -c #{$root}/cfgs/mc100-32-riscv-tests.yaml ext/riscv-tests/isa/rv32ui-p-#{t}"
400+
rv32uiTests = ["simple", "add", "addi", "and",
401+
"andi", "auipc", "beq", "bge", "bgeu", "blt",
402+
"bltu", "bne", "fence_i", "jal", "jalr",
403+
"lb", "lbu", "lh", "lhu", "lw", "ld_st",
404+
"lui", "ma_data", "or", "ori", "sb", "sh",
405+
"sw", "st_ld", "sll", "slli", "slt", "slti",
406+
"sltiu", "sltu", "sra", "srai", "srl",
407+
"srli", "sub", "xor", "xori"]
408+
409+
rv32uiTests.each do |t|
410+
sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m rv32 -c #{$root}/cfgs/rv32-riscv-tests.yaml ext/riscv-tests/isa/rv32ui-p-#{t}"
411+
end
412+
413+
rv32umTests = [ "div", "divu", "mul", "mulh", "mulhsu", "mulhu", "rem", "remu" ]
414+
rv32umTests.each do |t|
415+
sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m rv32 -c #{$root}/cfgs/rv32-riscv-tests.yaml ext/riscv-tests/isa/rv32um-p-#{t}"
416+
end
417+
418+
rv32ucTests = [ "rvc" ]
419+
rv32ucTests.each do |t|
420+
sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m rv32 -c #{$root}/cfgs/rv32-riscv-tests.yaml ext/riscv-tests/isa/rv32uc-p-#{t}"
421+
end
422+
423+
rv32siTests = ["csr", "dirty", "ma_fetch", "scall", "sbreak"]
424+
rv32siTests.each do |t|
425+
sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m rv32 -c #{$root}/cfgs/rv32-riscv-tests.yaml ext/riscv-tests/isa/rv32si-p-#{t}"
411426
end
412427
end
413428
end

backends/cpp_hart_gen/templates/enum.hxx.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace udb {
5656
}
5757

5858
constexpr bool operator!=(const <%= enum.name %>& rhs) const {
59-
return m_value == rhs.m_value;
59+
return m_value != rhs.m_value;
6060
}
6161

6262
constexpr bool operator<(const <%= enum.name %>& rhs) const {

backends/cpp_hart_gen/templates/hart_impl.hxx.erb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,20 @@ namespace udb {
138138
for (unsigned b = 0; b < bb_size; b++) {
139139
inst = current_bb->pop();
140140
141+
fmt::print("PC {:x} {}\n", m_pc, inst->disassemble());
142+
for (auto r : inst->srcRegs()) {
143+
fmt::print("R {} {:x}\n", r.to_string(), _xreg(r.get_num()));
144+
}
145+
141146
// set the fall-through next pc
142147
m_next_pc = m_pc + Bits<MXLEN>{inst->enc_len()};
143148
144149
inst->execute();
145150
151+
for (auto r : inst->dstRegs()) {
152+
fmt::print("R= {} {:x}\n", r.to_string(), _xreg(r.get_num()));
153+
}
154+
146155
advance_pc();
147156
if (this->m_exit_requested) {
148157
this->m_exit_requested = false; // reset the request

backends/generators/generator.py

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,105 @@ def check_requirement(req, exts):
1717
return False
1818

1919

20+
def build_match_from_format(format_field):
21+
"""
22+
Build a match string from the format field in the new schema.
23+
"""
24+
if not format_field or "opcodes" not in format_field:
25+
return None
26+
27+
# Determine instruction width by finding maximum bit position
28+
valid_locations = []
29+
30+
opcodes = format_field["opcodes"]
31+
# Check opcodes
32+
for field_data in opcodes.values():
33+
if isinstance(field_data, dict) and "location" in field_data:
34+
if isinstance(field_data["location"], str):
35+
try:
36+
location = field_data["location"]
37+
split_location = location.split("|")
38+
high = max(
39+
(
40+
int(location.split("-")[0])
41+
if "-" in location
42+
else int(location)
43+
)
44+
for location in split_location
45+
)
46+
valid_locations.append(high)
47+
except (ValueError, IndexError):
48+
raise ValueError(
49+
f"Invalid location format: {field_data['location']}"
50+
)
51+
elif isinstance(field_data["location"], int):
52+
try:
53+
valid_locations.append(field_data["location"])
54+
except (ValueError, IndexError):
55+
raise ValueError(
56+
f"Invalid location format: {field_data['location']}"
57+
)
58+
else:
59+
raise ValueError(f"Unknown location format: {field_data['location']}")
60+
61+
if "variables" in format_field:
62+
variables = format_field["variables"]
63+
# Check variables
64+
for var_data in variables.values():
65+
if isinstance(var_data, dict) and "location" in var_data:
66+
if isinstance(var_data["location"], str):
67+
try:
68+
location = var_data["location"]
69+
if "-" in location:
70+
high = int(location.split("-")[0])
71+
else:
72+
high = int(location)
73+
valid_locations.append(high)
74+
except (ValueError, IndexError):
75+
raise ValueError(
76+
f"Invalid location format: {var_data['location']}"
77+
)
78+
elif isinstance(var_data["location"], int):
79+
try:
80+
valid_locations.append(var_data["location"])
81+
except (ValueError, IndexError):
82+
raise ValueError(
83+
f"Invalid location format: {var_data['location']}"
84+
)
85+
else:
86+
raise ValueError(f"Invalid location format: {var_data['location']}")
87+
88+
if not valid_locations:
89+
raise ValueError("No valid bit locations found in format field")
90+
91+
max_bit = max(valid_locations)
92+
93+
# Set instruction width based on maximum bit position
94+
width = max_bit + 1
95+
match_bits = ["-"] * width
96+
97+
# Populate match string with opcode bits
98+
for field_data in opcodes.values():
99+
if isinstance(field_data, dict):
100+
try:
101+
location = field_data["location"]
102+
if isinstance(location, str) and "-" in location:
103+
high, low = map(int, location.split("-"))
104+
else:
105+
high = low = int(location)
106+
107+
if high < low or high >= width:
108+
logging.warning(f"Invalid bit range: {location}")
109+
continue # Skip invalid bit ranges
110+
111+
binary_value = format(field_data["value"], f"0{high - low + 1}b")
112+
match_bits[width - high - 1 : width - low] = binary_value
113+
except (ValueError, IndexError):
114+
raise ValueError(f"Error processing opcode field: {field_data}")
115+
116+
return "".join(match_bits)
117+
118+
20119
def parse_extension_requirements(extensions_spec):
21120
"""
22121
Parse the extension requirements from the definedBy field.
@@ -177,11 +276,27 @@ def load_instructions(
177276

178277
encoding = data.get("encoding", {})
179278
if not encoding:
180-
logging.error(
181-
f"Missing 'encoding' field in instruction {name} in {path}"
182-
)
183-
encoding_filtered += 1
184-
continue
279+
# Check if this instruction uses the new schema with a 'format' field
280+
format_field = data.get("format")
281+
if not format_field:
282+
logging.error(
283+
f"Missing 'encoding' field in instruction {name} in {path}"
284+
)
285+
encoding_filtered += 1
286+
continue
287+
288+
# Try to build a match string from the format field
289+
match_string = build_match_from_format(format_field)
290+
if not match_string:
291+
logging.error(
292+
f"Could not build encoding from format field in instruction {name} in {path}"
293+
)
294+
encoding_filtered += 1
295+
continue
296+
297+
# Create a synthetic encoding compatible with existing logic
298+
encoding = {"match": match_string, "variables": []}
299+
logging.debug(f"Built encoding from format field for {name}")
185300

186301
# Check if the instruction specifies a base architecture constraint
187302
base = data.get("base")

cfgs/mc100-32-riscv-tests.yaml renamed to cfgs/rv32-riscv-tests.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
$schema: https://riscv.org/udb/schemas/config_schema-0.1.0.json
44
kind: architecture configuration
55
type: fully configured
6-
name: MC100-32-riscv-tests
7-
description: An example MC100-32-compliant full config for riscv-tests
6+
name: rv32-riscv-tests
7+
description: A compliant full config for rv32 riscv-tests
88
implemented_extensions:
99
- [Sm, "1.11.0"]
1010
- [I, "2.1"]
@@ -17,6 +17,7 @@ implemented_extensions:
1717
- [Smpmp, "1.11.0"]
1818
- [U, "1.0.0"]
1919
- [Zifencei, "2.0.0"]
20+
- [Sv32, "1.11.0"]
2021

2122
params:
2223
MXLEN: 32
@@ -108,7 +109,7 @@ params:
108109
false,
109110
false,
110111
]
111-
STVEC_MODE_DIRECT: false
112+
STVEC_MODE_DIRECT: true
112113
STVEC_MODE_VECTORED: true
113114
SATP_MODE_BARE: true
114115
TRAP_ON_ECALL_FROM_S: true

spec/std/isa/csr/satp.yaml

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,39 @@ fields:
4545
reset_value(): |
4646
return 0;
4747
sw_write(csr_value): |
48-
if (SATP_MODE_BARE) {
49-
if (csr_value.MODE == 0) {
50-
# In Bare, ASID and PPN must be zero, else the entire write is ignored
51-
if (csr_value.ASID == 0 && csr_value.PPN == 0) {
52-
if (CSR[satp].MODE != 0) {
53-
# changes *to* Bare mode take effect immediately without needing sfence.vma
54-
# thus, an implicit sfence.vma occurs now
55-
VmaOrderType order_type;
56-
order_type.global = true;
57-
order_pgtbl_writes_before_vmafence(order_type);
58-
59-
invalidate_translations(order_type);
60-
61-
order_pgtbl_reads_after_vmafence(order_type);
62-
}
63-
return csr_value.MODE;
64-
} else {
65-
return UNDEFINED_LEGAL_DETERMINISTIC;
48+
if (SATP_MODE_BARE && (csr_value.MODE == 0)) {
49+
# In Bare, ASID and PPN must be zero, else the entire write is ignored
50+
if (csr_value.ASID == 0 && csr_value.PPN == 0) {
51+
if (CSR[satp].MODE != 0) {
52+
# changes *to* Bare mode take effect immediately without needing sfence.vma
53+
# thus, an implicit sfence.vma occurs now
54+
VmaOrderType order_type;
55+
order_type.global = true;
56+
order_pgtbl_writes_before_vmafence(order_type);
57+
58+
invalidate_translations(order_type);
59+
60+
order_pgtbl_reads_after_vmafence(order_type);
6661
}
62+
return csr_value.MODE;
63+
} else {
64+
return UNDEFINED_LEGAL_DETERMINISTIC;
6765
}
6866
}
69-
else if (implemented?(ExtensionName::Sv39) && csr_value.MODE == 8) {
67+
else if (implemented?(ExtensionName::Sv32) && csr_value.MODE == 1) {
68+
if (CSR[satp].MODE == 0) {
69+
# changes *from* Bare mode take effect immediately without needing sfence.vma
70+
# thus, an implicit sfence.vma occurs now
71+
VmaOrderType order_type;
72+
order_type.global = true;
73+
order_pgtbl_writes_before_vmafence(order_type);
74+
75+
invalidate_translations(order_type);
76+
77+
order_pgtbl_reads_after_vmafence(order_type);
78+
}
79+
return csr_value.MODE;
80+
}else if (implemented?(ExtensionName::Sv39) && csr_value.MODE == 8) {
7081
if (CSR[satp].MODE == 0) {
7182
# changes *from* Bare mode take effect immediately without needing sfence.vma
7283
# thus, an implicit sfence.vma occurs now

spec/std/isa/ext/Svrsw60t59b.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) Jordan Carlin, Harvey Mudd College.
2+
# SPDX-License-Identifier: BSD-3-Clause-Clear
3+
4+
# yaml-language-server: $schema=../../../schemas/ext_schema.json
5+
6+
$schema: "ext_schema.json#"
7+
kind: extension
8+
name: Svrsw60t59b
9+
long_name: PTE Reserved-for-Software Bits 60-59
10+
type: privileged
11+
description: |
12+
== "Svrsw60t59b" Extension for PTE Reserved-for-Software Bits 60-59, Version 1.0
13+
14+
If the Svrsw60t59b extension is implemented, then bits 60-59 of the page table
15+
entries (PTEs) are reserved for use by supervisor software and are ignored by
16+
the implementation.
17+
18+
If the Hypervisor (H) extension is also implemented, then bits 60-59 of the
19+
G-stage PTEs are reserved for use by supervisor software and are ignored by the
20+
implementation.
21+
22+
The Svrsw60t59b extension depends on Sv39.
23+
24+
[NOTE]
25+
====
26+
Operating systems frequently use reserved bits within PTEs to store metadata for
27+
advanced memory management features. Embedding these metadata bits directly within
28+
the PTEs allows for fast access with minimal overhead, avoiding costly lookups in
29+
auxiliary data structures. By default, Sv39 and Sv39x4 require a page fault and
30+
a guest-page fault exception, respectively, to be raised if bits 60-59 are not
31+
zero.
32+
====
33+
versions:
34+
- version: "1.0.0"
35+
state: ratified
36+
ratification_date: 2025-08
37+
requires:
38+
name: Sv39

0 commit comments

Comments
 (0)