diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index 191bbcad73..106df495a9 100755 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -221,8 +221,19 @@ jobs: uses: actions/checkout@v4 - name: singularity setup uses: ./.github/actions/singularity-setup - - name: Run riscv-tests - run: ./do test:riscv_tests CONFIG=rv32 JOBS=4 + - name: Run RV32 riscv-tests + run: ./do test:riscv_tests CONFIG=rv32 IGNOREUNDEFINED=YES JOBS=4 + regress-riscv-tests-64: + runs-on: ubuntu-latest + env: + SINGULARITY: 1 + steps: + - name: Clone Github Repo Action + uses: actions/checkout@v4 + - name: singularity setup + uses: ./.github/actions/singularity-setup + - name: Run RV64 riscv-tests + run: ./do test:riscv_tests CONFIG=rv64 IGNOREUNDEFINED=YES JOBS=4 regress-xqci-doc: runs-on: ubuntu-latest env: diff --git a/.vscode/launch.json b/.vscode/launch.json index 7163deb3fa..402aa3d664 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,8 @@ "name": "ISS debug Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/gen/cpp_hart_gen/rv32_Debug/build/iss", - "args": ["-m", "rv32", "-c", "${workspaceFolder}/cfgs/rv32-riscv-tests.yaml", "${workspaceFolder}/ext/riscv-tests/isa/rv32ui-p-addi"], + "program": "${workspaceFolder}/gen/cpp_hart_gen/rv64_Debug/build/iss", + "args": ["-m", "rv64", "-c", "${workspaceFolder}/cfgs/rv64-riscv-tests.yaml", "${workspaceFolder}/ext/riscv-tests/isa/rv64ui-p-addi"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/backends/cpp_hart_gen/CMakeLists.txt b/backends/cpp_hart_gen/CMakeLists.txt index fd69846f9f..bd33a07823 100644 --- a/backends/cpp_hart_gen/CMakeLists.txt +++ b/backends/cpp_hart_gen/CMakeLists.txt @@ -118,6 +118,9 @@ add_library(hart # ../gen/iss/oryon/src/decode.cxx ) target_include_directories(hart PUBLIC ${CMAKE_SOURCE_DIR}/include) +if(IGNOREUNDEFINED STREQUAL "YES") +target_compile_definitions(hart PUBLIC IGNOREUNDEFINED) +endif() target_link_libraries(hart PUBLIC yaml-cpp::yaml-cpp nlohmann_json_schema_validator fmt::fmt ctre::ctre -lgmp -lgmpxx) # add_library(hart_c ${CMAKE_SOURCE_DIR}/src/libhart_c.cpp) @@ -135,6 +138,9 @@ add_executable(iss ${CMAKE_SOURCE_DIR}/src/iss.cpp ${CMAKE_SOURCE_DIR}/src/elf_reader.cpp ) +if(IGNOREUNDEFINED STREQUAL "YES") +target_compile_definitions(iss PUBLIC IGNOREUNDEFINED) +endif() target_link_libraries(iss PRIVATE hart elf CLI11::CLI11) diff --git a/backends/cpp_hart_gen/cpp/include/udb/bits.hpp b/backends/cpp_hart_gen/cpp/include/udb/bits.hpp index 6f6b71aebd..56eba6ad4c 100644 --- a/backends/cpp_hart_gen/cpp/include/udb/bits.hpp +++ b/backends/cpp_hart_gen/cpp/include/udb/bits.hpp @@ -60,6 +60,13 @@ static_assert(sizeof(1ull) == 8); #error "Compiler does not support __int128" #endif +#ifndef IGNOREUNDEFINED +#define UNDEFINED_VALUE_ERROR(s) throw UndefinedValueError(s) +#else +#define UNDEFINED_VALUE_ERROR(s) +#endif + + namespace udb { // helper to find the max of N unsigned values at compile time @@ -694,6 +701,10 @@ namespace udb { } } + constexpr std::conditional_t get_ignore_unknown() const { + return m_val; + } + constexpr const _Bits& to_defined() const { return *this; } // cast to other Bits types @@ -2408,7 +2419,7 @@ namespace udb { constexpr operator BitsType() const { if constexpr (!BitsType::PossiblyUnknown) { if (m_unknown_mask != 0) { - throw UndefinedValueError("Cannot convert value with unknowns to Bits type"); + UNDEFINED_VALUE_ERROR("Cannot convert value with unknowns to Bits type"); } } return BitsType{*this}; @@ -2416,19 +2427,17 @@ namespace udb { template > constexpr T get() const { - if (m_unknown_mask == 0_b) { - return m_val.get(); - } else { - throw UndefinedValueError("Cannot convert value with unknowns to a native C++ type"); + if (m_unknown_mask != 0_b) { + UNDEFINED_VALUE_ERROR("Cannot convert value with unknowns to a native C++ type"); } + return m_val.get(); } constexpr _Bits to_defined() const { - if (m_unknown_mask == 0_b) { - return m_val; - } else { - throw UndefinedValueError("Cannot convert value with unknowns to a defined type"); + if (m_unknown_mask != 0_b) { + UNDEFINED_VALUE_ERROR("Cannot convert value with unknowns to a defined type"); } + return m_val; } @@ -2480,7 +2489,7 @@ namespace udb { constexpr bool operator op(const BitsType &rhs) const { \ if (m_unknown_mask != 0_b || \ (BitsType::PossiblyUnknown && (rhs.unknown_mask() != 0_b))) { \ - throw UndefinedValueError("Cannot compare unknown value"); \ + UNDEFINED_VALUE_ERROR("Cannot compare unknown value"); \ } \ return get() op rhs.to_defined().get(); \ } @@ -2626,7 +2635,7 @@ namespace udb { constexpr _PossiblyUnknownBits operator<<(const BitsType &shamt) const { if constexpr (BitsType::PossiblyUnknown) { if (shamt.unknown_mask() != 0_b) { - throw UndefinedValueError("Cannot shift an unknown amount"); + UNDEFINED_VALUE_ERROR("Cannot shift an unknown amount"); } } if (shamt.get() >= N) { @@ -2641,7 +2650,7 @@ namespace udb { constexpr _PossiblyUnknownBits operator>>(const BitsClass &shamt) const { if constexpr (BitsClass::PossiblyUnknown) { if (shamt.unknown_mask() != 0_b) { - throw UndefinedValueError("Cannot shift an unknown amount"); + UNDEFINED_VALUE_ERROR("Cannot shift an unknown amount"); } } if (shamt.get() >= N) { @@ -2656,7 +2665,7 @@ namespace udb { constexpr _PossiblyUnknownBits sra(const BitsClass &shamt) const { if constexpr (BitsClass::PossiblyUnknown) { if (shamt.unknown_mask() != 0_b) { - throw UndefinedValueError("Cannot shift an unknown amount"); + UNDEFINED_VALUE_ERROR("Cannot shift an unknown amount"); } } if (shamt.get() >= N) { @@ -2715,7 +2724,7 @@ namespace udb { _Bits + 1, Signed> lhs{*this}; if (m_unknown_mask != 0_b || _rhs.unknown_mask() != 0_b) { - throw UndefinedValueError("Addition is not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Addition is not defined on undefined values"); } if constexpr (RhsBitsType::RuntimeWidth) { @@ -2738,7 +2747,7 @@ namespace udb { _Bits + 1, Signed> lhs{*this}; if (m_unknown_mask != 0_b || _rhs.unknown_mask() != 0_b) { - throw UndefinedValueError("Addition is not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Addition is not defined on undefined values"); } if constexpr (RhsBitsType::RuntimeWidth) { @@ -2767,7 +2776,7 @@ namespace udb { _Bits, Signed> lhs{*this}; if (m_unknown_mask != 0_b || _rhs.unknown_mask() != 0_b) { - throw UndefinedValueError("Addition is not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Addition is not defined on undefined values"); } if constexpr (RhsBitsType::RuntimeWidth) { @@ -3171,7 +3180,7 @@ namespace udb { m_val, result_width}; if (unknown_mask() != 0_b || other.unknown_mask() != 0_b) { - throw UndefinedValueError("Multiplication not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Multiplication not defined on undefined values"); } if constexpr (RhsBitsType, RhsSigned>::RuntimeWidth) { @@ -3194,7 +3203,7 @@ namespace udb { m_val, result_width}; if (unknown_mask() != 0_b || other.unknown_mask() != 0_b) { - throw UndefinedValueError("Addition not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Addition not defined on undefined values"); } if constexpr (RhsBitsType + 1, RhsSigned>::RuntimeWidth) { @@ -3217,7 +3226,7 @@ namespace udb { m_val, result_width}; if (unknown_mask() != 0_b || other.unknown_mask() != 0_b) { - throw UndefinedValueError("Subtraction not defined on undefined values"); + UNDEFINED_VALUE_ERROR("Subtraction not defined on undefined values"); } if constexpr (RhsBitsType + 1, RhsSigned>::RuntimeWidth) { @@ -3467,7 +3476,7 @@ struct fmt::formatter> : formatter::StorageType> { template auto format(BitsClass value, CONTEXT_TYPE &ctx) const { - return fmt::formatter::StorageType>::format(value.get(), ctx); + return fmt::formatter::StorageType>::format(value.get_ignore_unknown(), ctx); } }; diff --git a/backends/cpp_hart_gen/tasks.rake b/backends/cpp_hart_gen/tasks.rake index 1143c39d3d..064ae43d7a 100644 --- a/backends/cpp_hart_gen/tasks.rake +++ b/backends/cpp_hart_gen/tasks.rake @@ -202,9 +202,14 @@ rule %r{#{CPP_HART_GEN_DST}/[^/]+/build/Makefile} => [ "-DCONFIG_LIST=\"#{ENV['CONFIG'].gsub(',', ';')}\"", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DCMAKE_BUILD_TYPE=#{cmake_build_type}" - ].join(" ") + ] + if ENV["IGNOREUNDEFINED"].nil? + cmd.push("-DIGNOREUNDEFINED=NO") + else + cmd.push("-DIGNOREUNDEFINED=YES") + end - sh cmd + sh cmd.join(" ") end rule %r{#{CPP_HART_GEN_DST}/[^/]+/include/udb/[^/]+\.hpp} do |t| @@ -346,6 +351,15 @@ namespace :build do end end + task iss: ["gen:cpp_hart"] do + _, build_name = configs_build_name + + Rake::Task["#{CPP_HART_GEN_DST}/#{build_name}/build/Makefile"].invoke + Dir.chdir("#{CPP_HART_GEN_DST}/#{build_name}/build") do + sh "make -j #{$jobs} iss" + end + end + task renode_hart: ["gen:cpp_hart"] do _, build_name = configs_build_name @@ -395,7 +409,7 @@ namespace :test do end end - task riscv_tests: ["build_riscv_tests", "build:cpp_hart"] do + task riscv_tests: ["build_riscv_tests", "build:iss"] do configs_name, build_name = configs_build_name rv32uiTests = ["simple", "add", "addi", "and", "andi", "auipc", "beq", "bge", "bgeu", "blt", @@ -405,24 +419,62 @@ namespace :test do "sw", "st_ld", "sll", "slli", "slt", "slti", "sltiu", "sltu", "sra", "srai", "srl", "srli", "sub", "xor", "xori"] + rv64uiTests = ["add", "addi", "addiw", "addw", + "and", "andi", + "auipc", + "beq", "bge", "bgeu", "blt", "bltu", "bne", + "simple", + "fence_i", + "jal", "jalr", + "lb", "lbu", "lh", "lhu", "lw", "lwu", "ld", "ld_st", + "lui", + "ma_data", + "or", "ori", + "sb", "sh", "sw", "sd", "st_ld", + "sll", "slli", "slliw", "sllw", + "slt", "slti", "sltiu", "sltu", + "sra", "srai", "sraiw", "sraw", + "srl", "srli", "srliw", "srlw", + "sub", "subw", + "xor", "xori"] + + rv32umTests = [ "div", "divu", + "mul", "mulh", "mulhsu", "mulhu", + "rem", "remu" ] + rv64umTests = ["div", "divu", "divuw", "divw", + "mul", "mulh", "mulhsu", "mulhu", "mulw", + "rem", "remu", "remuw", "remw"] + + # compressed tests same for rv32 as rv64 + ucTests = [ "rvc" ] + + rv32siTests = ["csr", "dirty", "ma_fetch", "scall", "sbreak"] + rv64siTests = ["csr", "dirty", "icache-alias", "ma_fetch", "scall", "sbreak"] - rv32uiTests.each do |t| - 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}" + if configs_name[0] == "rv64" + uiTests = rv64uiTests + umTests = rv64umTests + siTests = rv64siTests + else + uiTests = rv32uiTests + umTests = rv32umTests + siTests = rv32siTests end - rv32umTests = [ "div", "divu", "mul", "mulh", "mulhsu", "mulhu", "rem", "remu" ] - rv32umTests.each do |t| - 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}" + uiTests.each do |t| + sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m #{configs_name[0]} -c #{$root}/cfgs/#{configs_name[0]}-riscv-tests.yaml ext/riscv-tests/isa/#{configs_name[0]}ui-p-#{t}" end - rv32ucTests = [ "rvc" ] - rv32ucTests.each do |t| - 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}" + umTests.each do |t| + sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m #{configs_name[0]} -c #{$root}/cfgs/#{configs_name[0]}-riscv-tests.yaml ext/riscv-tests/isa/#{configs_name[0]}um-p-#{t}" end - rv32siTests = ["csr", "dirty", "ma_fetch", "scall", "sbreak"] - rv32siTests.each do |t| - 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}" + ucTests.each do |t| + sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m #{configs_name[0]} -c #{$root}/cfgs/#{configs_name[0]}-riscv-tests.yaml ext/riscv-tests/isa/#{configs_name[0]}uc-p-#{t}" + end + + siTests.each do |t| + sh "#{CPP_HART_GEN_DST}/#{build_name}/build/iss -m #{configs_name[0]} -c #{$root}/cfgs/#{configs_name[0]}-riscv-tests.yaml ext/riscv-tests/isa/#{configs_name[0]}si-p-#{t}" end end end diff --git a/backends/cpp_hart_gen/templates/csrs.hxx.erb b/backends/cpp_hart_gen/templates/csrs.hxx.erb index 61f05f03cc..a4ba44afae 100644 --- a/backends/cpp_hart_gen/templates/csrs.hxx.erb +++ b/backends/cpp_hart_gen/templates/csrs.hxx.erb @@ -254,7 +254,7 @@ namespace udb { } else { udb_assert(xlen == 64_b, "Bad xlen"); <%- - field_cpp = fields_for_xlen32.map do |field| + field_cpp = fields_for_xlen64.map do |field| if field.dynamic_location? "((m_#{field.name}._hw_read() & 0x#{((1 << field.location(64).size) - 1).to_s(16)}_b).template widening_sll<#{field.location(64).begin}>())" else diff --git a/backends/cpp_hart_gen/templates/hart.hxx.erb b/backends/cpp_hart_gen/templates/hart.hxx.erb index 63502081d9..d7a534383a 100644 --- a/backends/cpp_hart_gen/templates/hart.hxx.erb +++ b/backends/cpp_hart_gen/templates/hart.hxx.erb @@ -402,12 +402,9 @@ namespace udb { _set_xreg(Bits<8>{num}, Bits{value}); } - template < - template class IdxType, unsigned IdxN, bool IdxSigned, - template class ValueType, unsigned ValueN, bool ValueSigned - > - requires (BitsType> && BitsType>) - void _set_xreg(const IdxType& num, const ValueType& value) { + template < template class IdxType, unsigned IdxN, bool IdxSigned > + requires (BitsType>) + void _set_xreg(const IdxType& num, const _PossiblyUnknownBits& value) { if (num != 0_b) { m_xregs[static_cast(num.get())] = value; } diff --git a/cfgs/rv64-riscv-tests.yaml b/cfgs/rv64-riscv-tests.yaml new file mode 100644 index 0000000000..b42f46a14a --- /dev/null +++ b/cfgs/rv64-riscv-tests.yaml @@ -0,0 +1,128 @@ +# yaml-language-server: $schema=../schemas/config_schema.json +--- +$schema: https://riscv.org/udb/schemas/config_schema-0.1.0.json +kind: architecture configuration +type: fully configured +name: rv64-riscv-tests +description: A compliant full config for rv64 riscv-tests +implemented_extensions: + - [Sm, "1.11.0"] + - [I, "2.1"] + - [C, "2.0"] + - [M, "2.0"] + - [Zicsr, "2.0"] + - [Zicntr, "2.0"] + - [Smrnmi, "1.0"] + - [S, "1.11.0"] + - [Smpmp, "1.11.0"] + - [U, "1.0.0"] + - [Zifencei, "2.0.0"] + - [Sv39, "1.11.0"] + +params: + MXLEN: 64 + ARCH_ID: 0 + IMP_ID: 0 + VENDOR_ID_BANK: 1 + VENDOR_ID_OFFSET: 1 + MISALIGNED_LDST: true + MISALIGNED_LDST_EXCEPTION_PRIORITY: low + MISALIGNED_MAX_ATOMICITY_GRANULE_SIZE: 4 + MISALIGNED_SPLIT_STRATEGY: by_byte + PRECISE_SYNCHRONOUS_EXCEPTIONS: true + TRAP_ON_ECALL_FROM_M: true + TRAP_ON_EBREAK: true + M_MODE_ENDIANNESS: little + TRAP_ON_ILLEGAL_WLRL: true + TRAP_ON_UNIMPLEMENTED_INSTRUCTION: true + TRAP_ON_RESERVED_INSTRUCTION: true + TRAP_ON_UNIMPLEMENTED_CSR: true + REPORT_VA_IN_MTVAL_ON_BREAKPOINT: true + REPORT_VA_IN_MTVAL_ON_LOAD_MISALIGNED: true + REPORT_VA_IN_MTVAL_ON_STORE_AMO_MISALIGNED: true + REPORT_VA_IN_MTVAL_ON_INSTRUCTION_MISALIGNED: true + REPORT_VA_IN_MTVAL_ON_LOAD_ACCESS_FAULT: true + REPORT_VA_IN_MTVAL_ON_STORE_AMO_ACCESS_FAULT: true + REPORT_VA_IN_MTVAL_ON_INSTRUCTION_ACCESS_FAULT: true + REPORT_ENCODING_IN_MTVAL_ON_ILLEGAL_INSTRUCTION: true + MTVAL_WIDTH: 32 + PMA_GRANULARITY: 12 + PHYS_ADDR_WIDTH: 57 + MISA_CSR_IMPLEMENTED: true + MTVEC_MODES: [0, 1] + MTVEC_BASE_ALIGNMENT_DIRECT: 4 + MTVEC_BASE_ALIGNMENT_VECTORED: 4 + MUTABLE_MISA_C: false + MUTABLE_MISA_M: false + TIME_CSR_IMPLEMENTED: false + MUTABLE_MISA_S: false + ASID_WIDTH: 5 + S_MODE_ENDIANNESS: little + SXLEN: 64 + REPORT_VA_IN_MTVAL_ON_LOAD_PAGE_FAULT: true + REPORT_VA_IN_MTVAL_ON_STORE_AMO_PAGE_FAULT: true + REPORT_VA_IN_MTVAL_ON_INSTRUCTION_PAGE_FAULT: true + REPORT_VA_IN_STVAL_ON_BREAKPOINT: true + REPORT_VA_IN_STVAL_ON_LOAD_MISALIGNED: true + REPORT_VA_IN_STVAL_ON_STORE_AMO_MISALIGNED: true + REPORT_VA_IN_STVAL_ON_INSTRUCTION_MISALIGNED: true + REPORT_VA_IN_STVAL_ON_LOAD_ACCESS_FAULT: true + REPORT_VA_IN_STVAL_ON_STORE_AMO_ACCESS_FAULT: true + REPORT_VA_IN_STVAL_ON_INSTRUCTION_ACCESS_FAULT: true + REPORT_VA_IN_STVAL_ON_LOAD_PAGE_FAULT: true + REPORT_VA_IN_STVAL_ON_STORE_AMO_PAGE_FAULT: true + REPORT_VA_IN_STVAL_ON_INSTRUCTION_PAGE_FAULT: true + REPORT_ENCODING_IN_STVAL_ON_ILLEGAL_INSTRUCTION: true + STVAL_WIDTH: 32 + SCOUNTENABLE_EN: + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + ] + STVEC_MODE_DIRECT: true + STVEC_MODE_VECTORED: true + SATP_MODE_BARE: true + TRAP_ON_ECALL_FROM_S: true + TRAP_ON_SFENCE_VMA_WHEN_SATP_MODE_IS_READ_ONLY: false + MSTATUS_FS_WRITABLE: false + MSTATUS_VS_WRITABLE: false + MSTATUS_VS_LEGAL_VALUES: [0] + MSTATUS_FS_LEGAL_VALUES: [0] + MSTATUS_TVM_IMPLEMENTED: false + NUM_PMP_ENTRIES: 16 + PMP_GRANULARITY: 12 + MUTABLE_MISA_U: false + U_MODE_ENDIANNESS: little + UXLEN: 64 + MSTATEEN_ENVCFG_TYPE: rw + HSTATEEN_ENVCFG_TYPE: rw diff --git a/spec/std/isa/csr/mstatus.yaml b/spec/std/isa/csr/mstatus.yaml index 877d646e0a..257d4de1c3 100644 --- a/spec/std/isa/csr/mstatus.yaml +++ b/spec/std/isa/csr/mstatus.yaml @@ -143,13 +143,13 @@ fields: description: | *S-mode XLEN* - Sets the effective XLEN for S-mode (0 = 32-bit, 1 = 64-bit, 2 = 128-bit [reserved]). + Sets the effective XLEN for S-mode (1 = 32-bit, 2 = 64-bit, 3 = 128-bit [reserved]). [when,"SXLEN==32"] - Since the CPU only supports SXLEN==32, this is hardwired to 0. + Since the CPU only supports SXLEN==32, this is hardwired to 1. - [when,"SXLEN==32"] - Since the CPU only supports SXLEN==64, this is hardwired to 1. + [when,"SXLEN==64"] + Since the CPU only supports SXLEN==64, this is hardwired to 2. [when,"SXLEN=3264"] -- @@ -164,26 +164,34 @@ fields: legal?(csr_value): | if (SXLEN == 32) { - # SXLEN == 32 is encoded as 0 - return csr_value.SXL == 0; - } else if (SXLEN == 64) { - # SXLEN == 64 is encoded as 1 + # SXLEN == 32 is encoded as 1 return csr_value.SXL == 1; + } else if (SXLEN == 64) { + # SXLEN == 64 is encoded as 2 + return csr_value.SXL == 2; } else { # SXLEN could be 32 or 64 - return csr_value.SXL <= 1; + return (csr_value.SXL >= 1 && csr_value.SXL <= 2); } sw_write(csr_value): | if (csr_value.SXL < csr_value.UXL) { - return UNDEFINED_LEGAL_DETERMINISTIC; - } else if (csr_value.SXL > 1) { - # SXL != [0, 1] is not defined (2 reserved for RV128, but that isn't ratified) - return UNDEFINED_LEGAL_DETERMINISTIC; + return CSR[mstatus].SXL; + } else if (csr_value.SXL < 1 || csr_value.SXL > 2) { + # SXL != [1, 2] is not defined (3 reserved for RV128, but that isn't ratified) + return CSR[mstatus].SXL; } else { return csr_value.SXL; } - reset_value: UNDEFINED_LEGAL + + reset_value(): | + if (SXLEN == 32) { + return 1; + } else if (SXLEN == 64) { + return 2; + } else { + return 2; + } UXL: location: 33-32 @@ -192,13 +200,13 @@ fields: description: | U-mode XLEN. - Sets the effective XLEN for U-mode (0 = 32-bit, 1 = 64-bit, 2 = 128-bit [reserved]). + Sets the effective XLEN for U-mode (1 = 32-bit, 2 = 64-bit, 3 = 128-bit [reserved]). [when,"UXLEN == 32"] - Since the CPU only supports UXLEN==32, this is hardwired to 0. + Since the CPU only supports UXLEN==32, this is hardwired to 1. [when,"UXLEN == 64"] - Since the CPU only supports UXLEN==64, this is hardwired to 1. + Since the CPU only supports UXLEN==64, this is hardwired to 2. [when,"UXLEN == 3264"] @@ -214,30 +222,30 @@ fields: sw_write(csr_value): | if (csr_value.SXL < csr_value.UXL) { - return UNDEFINED_LEGAL_DETERMINISTIC; - } else if (csr_value.UXL > 1) { - # UXL != [0, 1] is not defined (2 reserved for RV128, but that isn't ratified) - return UNDEFINED_LEGAL_DETERMINISTIC; + return CSR[mstatus].UXL; + } else if (csr_value.UXL < 1 || csr_value.UXL > 2) { + # UXL != [1, 2] is not defined (3 reserved for RV128, but that isn't ratified) + return CSR[mstatus].UXL; } else { return csr_value.UXL; } legal?(csr_value): | if (UXLEN == 32) { - return csr_value.UXL == 0; - } else if (UXLEN == 64) { return csr_value.UXL == 1; + } else if (UXLEN == 64) { + return csr_value.UXL == 2; } else { - return csr_value.UXL <= 1; + return (csr_value.UXL >= 1 && csr_value.UXL <= 2); } reset_value(): | if (UXLEN == 32) { - return 0; - } else if (UXLEN == 64) { return 1; + } else if (UXLEN == 64) { + return 2; } else { - return UNDEFINED_LEGAL; + return 2; } TSR: diff --git a/spec/std/isa/csr/sstatus.yaml b/spec/std/isa/csr/sstatus.yaml index 5505be7a2d..4bab9661fd 100644 --- a/spec/std/isa/csr/sstatus.yaml +++ b/spec/std/isa/csr/sstatus.yaml @@ -33,14 +33,14 @@ fields: UXL: location: 33-32 base: 64 - alias: mstatus.MXR + alias: mstatus.UXL description: | *U-mode XLEN* Alias of `mstatus.UXL`. type: RO - reset_value: UNDEFINED_LEGAL + reset_value: 2 MXR: alias: mstatus.MXR location: 19 diff --git a/spec/std/isa/inst/C/c.addiw.yaml b/spec/std/isa/inst/C/c.addiw.yaml index ad4b743e3f..52f5481b59 100644 --- a/spec/std/isa/inst/C/c.addiw.yaml +++ b/spec/std/isa/inst/C/c.addiw.yaml @@ -36,4 +36,4 @@ operation(): | raise(ExceptionCode::IllegalInstruction, mode(), $encoding); } - X[xd] = sext((X[xd] + imm), 32); + X[xd] = sext((X[xd] + sext(imm, 6)), 32); diff --git a/spec/std/isa/inst/C/c.subw.yaml b/spec/std/isa/inst/C/c.subw.yaml index d32df7fe4f..b78441657a 100644 --- a/spec/std/isa/inst/C/c.subw.yaml +++ b/spec/std/isa/inst/C/c.subw.yaml @@ -32,7 +32,7 @@ access: operation(): | Bits<32> t0 = X[creg2reg(xd)][31:0]; Bits<32> t1 = X[creg2reg(xs2)][31:0]; - X[creg2reg(xd)] = sext(t0 - t1, 31); + X[creg2reg(xd)] = sext(t0 - t1, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/addiw.yaml b/spec/std/isa/inst/I/addiw.yaml index 574af8e778..cb77f3db59 100644 --- a/spec/std/isa/inst/I/addiw.yaml +++ b/spec/std/isa/inst/I/addiw.yaml @@ -30,8 +30,7 @@ pseudoinstructions: - when: imm == 0 to: sext.w xd,xs1 operation(): | - XReg operand = sext(X[xs1], 31); - X[xd] = sext(operand + imm, 31); + X[xd] = $signed((X[xs1] + $signed(imm))[31:0]); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/addw.yaml b/spec/std/isa/inst/I/addw.yaml index d5511ac158..0dd5cec5e5 100644 --- a/spec/std/isa/inst/I/addw.yaml +++ b/spec/std/isa/inst/I/addw.yaml @@ -29,9 +29,9 @@ access: vu: always data_independent_timing: true operation(): | - XReg operand1 = sext(X[xs1], 31); - XReg operand2 = sext(X[xs2], 31); - X[xd] = sext(operand1 + operand2, 31); + XReg operand1 = sext(X[xs1], 32); + XReg operand2 = sext(X[xs2], 32); + X[xd] = sext(operand1 + operand2, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/lui.yaml b/spec/std/isa/inst/I/lui.yaml index a5c90e0572..86b5bd70cc 100644 --- a/spec/std/isa/inst/I/lui.yaml +++ b/spec/std/isa/inst/I/lui.yaml @@ -24,7 +24,7 @@ access: vs: always vu: always data_independent_timing: true -operation(): X[xd] = imm; +operation(): X[xd] = $signed(imm); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/lw.yaml b/spec/std/isa/inst/I/lw.yaml index a53f09d9b4..86bf2eab46 100644 --- a/spec/std/isa/inst/I/lw.yaml +++ b/spec/std/isa/inst/I/lw.yaml @@ -30,7 +30,7 @@ access: operation(): | XReg virtual_address = X[xs1] + $signed(imm); - X[xd] = $signed(read_memory<32>(virtual_address, $encoding)); + X[xd] = sext(read_memory<32>(virtual_address, $encoding), 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/slliw.yaml b/spec/std/isa/inst/I/slliw.yaml index cea263865c..94f5d51a80 100644 --- a/spec/std/isa/inst/I/slliw.yaml +++ b/spec/std/isa/inst/I/slliw.yaml @@ -28,7 +28,7 @@ access: data_independent_timing: true operation(): | # shamt is between 0-32 - X[xd] = sext(X[xs1] << shamt, 31); + X[xd] = sext(X[xs1] << shamt, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/sllw.yaml b/spec/std/isa/inst/I/sllw.yaml index 9624ae6943..129c894964 100644 --- a/spec/std/isa/inst/I/sllw.yaml +++ b/spec/std/isa/inst/I/sllw.yaml @@ -27,7 +27,7 @@ access: vs: always vu: always data_independent_timing: true -operation(): X[xd] = sext(X[xs1] << X[xs2][4:0], 31); +operation(): X[xd] = sext(X[xs1] << X[xs2][4:0], 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/sraiw.yaml b/spec/std/isa/inst/I/sraiw.yaml index 5ad0b76be7..d2ba8d239c 100644 --- a/spec/std/isa/inst/I/sraiw.yaml +++ b/spec/std/isa/inst/I/sraiw.yaml @@ -30,8 +30,8 @@ access: data_independent_timing: true operation(): | # shamt is between 0-32 - XReg operand = sext(X[xs1], 31); - X[xd] = sext(operand >>> shamt, 31); + XReg operand = sext(X[xs1], 32); + X[xd] = sext(operand >>> shamt, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/sraw.yaml b/spec/std/isa/inst/I/sraw.yaml index fad49d844b..df33b57e3d 100644 --- a/spec/std/isa/inst/I/sraw.yaml +++ b/spec/std/isa/inst/I/sraw.yaml @@ -28,9 +28,9 @@ access: vu: always data_independent_timing: true operation(): | - XReg operand1 = sext(X[xs1], 31); + XReg operand1 = sext(X[xs1], 32); - X[xd] = sext(operand1 >>> X[xs2][4:0], 31); + X[xd] = sext(operand1 >>> X[xs2][4:0], 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/srliw.yaml b/spec/std/isa/inst/I/srliw.yaml index 48ea69ce34..94c2384279 100644 --- a/spec/std/isa/inst/I/srliw.yaml +++ b/spec/std/isa/inst/I/srliw.yaml @@ -30,7 +30,7 @@ operation(): | # shamt is between 0-31 XReg operand = X[xs1][31:0]; - X[xd] = sext(operand >> shamt, 31); + X[xd] = sext(operand >> shamt, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/srlw.yaml b/spec/std/isa/inst/I/srlw.yaml index 471066bb76..382afbcb27 100644 --- a/spec/std/isa/inst/I/srlw.yaml +++ b/spec/std/isa/inst/I/srlw.yaml @@ -27,7 +27,7 @@ access: vs: always vu: always data_independent_timing: true -operation(): X[xd] = sext(X[xs1][31:0] >> X[xs2][4:0], 31); +operation(): X[xd] = sext(X[xs1][31:0] >> X[xs2][4:0], 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/I/subw.yaml b/spec/std/isa/inst/I/subw.yaml index d9de0207a5..6163e570fe 100644 --- a/spec/std/isa/inst/I/subw.yaml +++ b/spec/std/isa/inst/I/subw.yaml @@ -32,7 +32,7 @@ pseudoinstructions: operation(): | Bits<32> t0 = X[xs1][31:0]; Bits<32> t1 = X[xs2][31:0]; - X[xd] = sext(t0 - t1, 31); + X[xd] = sext(t0 - t1, 32); # SPDX-SnippetBegin # SPDX-FileCopyrightText: 2017-2025 Contributors to the RISCV Sail Model diff --git a/spec/std/isa/inst/M/divw.yaml b/spec/std/isa/inst/M/divw.yaml index ab09de8b8b..56585f4696 100644 --- a/spec/std/isa/inst/M/divw.yaml +++ b/spec/std/isa/inst/M/divw.yaml @@ -47,17 +47,15 @@ operation(): | # to be -1 X[xd] = {MXLEN{1'b1}}; - } else if ((src1 == {33'b1, 31'b0}) && (src2 == 32'b1)) { - # signed overflow. Since RISC-V does not have arithmetic exceptions, the result is defined - # to be the most negative number (-2^(31)) - X[xd] = {33'b1, 31'b0}; + } else if ((src1 == 32'h80000000) && (src2 == 32'hFFFFFFFF)) { + #INT_MIN / -1 = INT_MIN + #signed overflow. Since RISC-V does not have arithmetic exceptions, the result is defined + #to be the most negative number (-2^(31)) + X[xd] = sext(32'h80000000, 32); } else { # no special case, just divide - Bits<32> result = $signed(src1) / $signed(src2); - Bits<1> sign_bit = result[31]; - - X[xd] = {{32{sign_bit}}, result}; + X[xd] = sext($signed(src1) / $signed(src2), 32); } # SPDX-SnippetBegin diff --git a/spec/std/isa/inst/M/remw.yaml b/spec/std/isa/inst/M/remw.yaml index ab3428f24e..78ffca58f8 100644 --- a/spec/std/isa/inst/M/remw.yaml +++ b/spec/std/isa/inst/M/remw.yaml @@ -45,7 +45,7 @@ operation(): | Bits<1> sign_bit = src1[31]; X[xd] = {{32{sign_bit}}, src1}; - } else if ((src1 == {33'b1, 31'b0}) && (src2 == 32'b1)) { + } else if ((src1 == 32'h80000000) && (src2 == 32'hFFFFFFFF)) { # signed overflow. Since RISC-V does not have arithmetic exceptions, the result is defined # to be zero X[xd] = 0; diff --git a/spec/std/isa/isa/globals.isa b/spec/std/isa/isa/globals.isa index e08e1cd1aa..1d22f5227e 100644 --- a/spec/std/isa/isa/globals.isa +++ b/spec/std/isa/isa/globals.isa @@ -120,8 +120,8 @@ generated enum ExceptionCode; # XLEN encoding, as defined in CSR[mstatus].mxl, etc. enum XRegWidth { - XLEN32 0 - XLEN64 1 + XLEN32 1 + XLEN64 2 } # enum ExceptionCode { @@ -1003,19 +1003,19 @@ function pmp_match_64 { # set up the default range limits, which will result in NoMatch when # compared to the access - Bits range_hi = 0; - Bits range_lo = 0; + Bits range_base = 0; + Bits range_limit = 0; if (cfg.A == $bits(PmpCfg_A::TOR)) { if (i == 0) { # when entry zero is TOR, zero is the lower address bound - range_lo = 0; + range_base = 0; } else { # otherwise, it's the address in the next lowest pmpaddr register Csr tor_pmpaddr_csr = direct_csr_lookup(pmpaddr_idx - 1); - range_lo = (csr_sw_read(tor_pmpaddr_csr) << 2)[PHYS_ADDR_WIDTH-1:0]; + range_base = (csr_sw_read(tor_pmpaddr_csr))[PHYS_ADDR_WIDTH-1:0]; } - range_hi = (pmpaddr_csr_value << 2)[PHYS_ADDR_WIDTH-1:0]; + range_limit = (pmpaddr_csr_value)[PHYS_ADDR_WIDTH-1:0] - 1; } else if (cfg.A == $bits(PmpCfg_A::NAPOT)) { # Example pmpaddr: 0b00010101111 @@ -1024,21 +1024,20 @@ function pmp_match_64 { # mask: 0b00000011111 # ~mask: 0b11111100000 # len = mask + 1: 0b00000100000 - Bits pmpaddr_value = pmpaddr_csr_value[PHYS_ADDR_WIDTH-3:0]; - Bits mask = pmpaddr_value ^ (pmpaddr_value + 1); - range_lo = (pmpaddr_value & ~mask) << 2; - Bits len = mask + 1; - range_hi = ((pmpaddr_value & ~mask) + len) << 2; + Bits pmpaddr_value = pmpaddr_csr_value[PHYS_ADDR_WIDTH-1:0]; + Bits mask = pmpaddr_value ^ (pmpaddr_value + 1); + range_base = (pmpaddr_value & ~mask); + range_limit = range_base + mask; } else if (cfg.A == $bits(PmpCfg_A::NA4)) { - range_lo = (pmpaddr_csr_value << 2)[PHYS_ADDR_WIDTH-1:0]; - range_hi = range_lo + 4; + range_base = pmpaddr_csr_value[PHYS_ADDR_WIDTH-1:0]; + range_limit = range_base + 3; } - if ((paddr >= range_lo) && ((paddr + (access_size/8)) < range_hi)) { + if (((paddr >> 2) >= range_base) && (((paddr + (access_size/8) - 1) >> 2) <= range_limit)) { # full match return PmpMatchResult::FullMatch, cfg; - } else if (!(((paddr + (access_size/8) - 1) < range_lo) || (paddr >= range_hi))) { + } else if (!(((paddr + (access_size/8) - 1) < range_base) || (paddr >= range_limit))) { # this is a partial match. By definition, the access must fail, regardless # of the pmp cfg settings return PmpMatchResult::PartialMatch, -; @@ -2104,8 +2103,8 @@ function stage1_page_walk { raise (page_fault_code, mode(), vaddr); } - for (U32 i = (LEVELS - 1); i >= 0; i--) { - U32 vpn = (vaddr >> (12 + VPN_SIZE*i)) & ((1 `<< VPN_SIZE) - 1); + for (U32 I = (LEVELS - 1); I >= 0; I--) { + U32 vpn = (vaddr >> (12 + VPN_SIZE*I)) & ((1 `<< VPN_SIZE) - 1); Bits pte_gpaddr = (ppn << 12) + (vpn * (PTESIZE/8)); @@ -2178,6 +2177,8 @@ function stage1_page_walk { if (pte_flags.R == 1 || pte_flags.X == 1) { # found a leaf PTE + Bits paddr_base = pte[PA_SIZE-3:I*VPN_SIZE + 10] `<< (I*VPN_SIZE + 12); + Bits offset = vaddr[I*VPN_SIZE + 11:0]; # see if there is permission to perform the access if (op == MemoryOperation::Read || op == MemoryOperation::ReadModifyWrite) { @@ -2214,7 +2215,7 @@ function stage1_page_walk { } # ensure remaining PPN bits are zero, otherwise there is a misaligned super page - raise (page_fault_code, mode(), vaddr) if ((i > 0) && (pte[i*VPN_SIZE + 10:10] != 0)); + raise (page_fault_code, mode(), vaddr) if ((I > 0) && (pte[I*VPN_SIZE + 10:10] != 0)); # check access and dirty bits if ((pte_flags.A == 0) # access is clear @@ -2267,12 +2268,12 @@ function stage1_page_walk { if (!success) { # the PTE changed between the read during the walk and the attempted atomic update # roll back, and try this level again - i = i + 1; + I = I + 1; } else { # successful translation and update - TranslationResult pte_phys = - translate_gstage( - {pte[PA_SIZE-3:i*VPN_SIZE + 10], vaddr[i*VPN_SIZE + 11:0]}, + + TranslationResult pte_phys = translate_gstage( + paddr_base + offset, vaddr, op, effective_mode, @@ -2292,7 +2293,7 @@ function stage1_page_walk { # translation succeeded TranslationResult pte_phys = translate_gstage( - {pte[PA_SIZE-3:i*VPN_SIZE + 10], vaddr[i*VPN_SIZE + 11:0]}, + paddr_base + offset, vaddr, op, effective_mode, @@ -2307,7 +2308,7 @@ function stage1_page_walk { } else { # found a pointer to the next level - if (i == 0) { + if (I == 0) { # a pointer can't exist on the last level raise (page_fault_code, mode(), vaddr); } @@ -2328,7 +2329,7 @@ function stage1_page_walk { } # fall through to next level - ppn = pte[PA_SIZE-3:10] << 12; + ppn = pte[PA_SIZE-3:10]; } } } @@ -2398,16 +2399,16 @@ function translate { if (translation_mode == SatpMode::Bare) { result.paddr = vaddr; - } else if (translation_mode == SatpMode::Sv32) { + } else if (xlen() == 32 && translation_mode == SatpMode::Sv32) { # Sv32 page table walk result = stage1_page_walk<32, 34, 32, 2>(vaddr, op, effective_mode, encoding); - } else if (translation_mode == SatpMode::Sv39) { + } else if (xlen() == 64 && translation_mode == SatpMode::Sv39) { # Sv39 page table walk result = stage1_page_walk<39, 56, 64, 3>(vaddr, op, effective_mode, encoding); - } else if (translation_mode == SatpMode::Sv48) { + } else if (xlen() == 64 && translation_mode == SatpMode::Sv48) { # Sv48 page table walk result = stage1_page_walk<48, 56, 64, 4>(vaddr, op, effective_mode, encoding); - } else if (translation_mode == SatpMode::Sv57) { + } else if (xlen() == 64 && translation_mode == SatpMode::Sv57) { # Sv57 page table walk result = stage1_page_walk<57, 56, 64, 5>(vaddr, op, effective_mode, encoding); } else { diff --git a/tools/ruby-gems/udb/lib/udb/obj/instruction.rb b/tools/ruby-gems/udb/lib/udb/obj/instruction.rb index 9c38f3e6b7..d2835ee79a 100644 --- a/tools/ruby-gems/udb/lib/udb/obj/instruction.rb +++ b/tools/ruby-gems/udb/lib/udb/obj/instruction.rb @@ -418,20 +418,23 @@ def fill_symtab(effective_xlen, ast) symtab end - # @param global_symtab [Idl::SymbolTable] Symbol table with global scope populated and a configuration loaded + # @param global_symtab [Idl::SymbolTable] Symbol table with global scope populated and a configuration loaded # @return [Idl::FunctionBodyAst] A pruned abstract syntax tree def pruned_operation_ast(effective_xlen) - defer :pruned_operation_ast do - return nil unless @data.key?("operation()") + @pruned_operation_ast ||= {} + @pruned_operation_ast[effective_xlen] ||= + begin + if @data.key?("operation()") - type_checked_ast = type_checked_operation_ast(effective_xlen) - symtab = fill_symtab(effective_xlen, type_checked_ast) - pruned_ast = type_checked_ast.prune(symtab) - pruned_ast.freeze_tree(symtab) + type_checked_ast = type_checked_operation_ast(effective_xlen) + symtab = fill_symtab(effective_xlen, type_checked_ast) + pruned_ast = type_checked_ast.prune(symtab) + pruned_ast.freeze_tree(symtab) - symtab.release - pruned_ast - end + symtab.release + pruned_ast + end + end end # @param symtab [Idl::SymbolTable] Symbol table with global scope populated