diff --git a/backends/cpp_hart_gen/CMakeLists.txt b/backends/cpp_hart_gen/CMakeLists.txt index 0d1fd4fdfc..f0b1037ca5 100644 --- a/backends/cpp_hart_gen/CMakeLists.txt +++ b/backends/cpp_hart_gen/CMakeLists.txt @@ -235,6 +235,13 @@ add_executable(test_version target_include_directories(test_version PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(test_version PRIVATE hart Catch2::Catch2WithMain) +add_executable(test_regfile + ${CMAKE_SOURCE_DIR}/test/test_regfile.cpp + ${CMAKE_SOURCE_DIR}/src/NotificationHandler.cpp +) +target_include_directories(test_regfile PUBLIC ${CMAKE_SOURCE_DIR}/include) +target_link_libraries(test_regfile PRIVATE hart Catch2::Catch2WithMain) + # add_executable(test_decode # ${CMAKE_SOURCE_DIR}/test/test_decode.cpp # ) @@ -244,6 +251,7 @@ target_link_libraries(test_version PRIVATE hart Catch2::Catch2WithMain) include(CTest) include(Catch) catch_discover_tests(test_bits_directed) +catch_discover_tests(test_regfile) foreach (random_test IN LISTS RANDOM_TESTS) catch_discover_tests(${random_test}) diff --git a/backends/cpp_hart_gen/cpp/include/udb/hart.hpp b/backends/cpp_hart_gen/cpp/include/udb/hart.hpp index a77585f218..ea1be23e34 100644 --- a/backends/cpp_hart_gen/cpp/include/udb/hart.hpp +++ b/backends/cpp_hart_gen/cpp/include/udb/hart.hpp @@ -329,6 +329,19 @@ namespace udb { virtual uint64_t xreg(unsigned num) const = 0; virtual void set_xreg(unsigned num, uint64_t value) = 0; + virtual uint64_t freg(unsigned num) const { + throw std::runtime_error("No F register file in this configuration"); + } + virtual void set_freg(unsigned num, uint64_t value) { + throw std::runtime_error("No F register file in this configuration"); + } + virtual uint64_t vreg(unsigned num) const { + throw std::runtime_error("No V register file in this configuration"); + } + virtual void set_vreg(unsigned num, uint64_t value) { + throw std::runtime_error("No V register file in this configuration"); + } + virtual CsrBase* csr(unsigned address) = 0; virtual const CsrBase* csr(unsigned address) const = 0; diff --git a/backends/cpp_hart_gen/cpp/include/udb/inst.hpp b/backends/cpp_hart_gen/cpp/include/udb/inst.hpp index 7f5233fdc6..bdb8239d61 100644 --- a/backends/cpp_hart_gen/cpp/include/udb/inst.hpp +++ b/backends/cpp_hart_gen/cpp/include/udb/inst.hpp @@ -73,7 +73,39 @@ namespace udb { F29 = 61, F30 = 62, F31 = 63, - INVALID = 64 + V0 = 64, + V1 = 65, + V2 = 66, + V3 = 67, + V4 = 68, + V5 = 69, + V6 = 70, + V7 = 71, + V8 = 72, + V9 = 73, + V10 = 74, + V11 = 75, + V12 = 76, + V13 = 77, + V14 = 78, + V15 = 79, + V16 = 80, + V17 = 81, + V18 = 82, + V19 = 83, + V20 = 84, + V21 = 85, + V22 = 86, + V23 = 87, + V24 = 88, + V25 = 89, + V26 = 90, + V27 = 91, + V28 = 92, + V29 = 93, + V30 = 94, + V31 = 95, + INVALID = 96 }; Reg(Enum r) : m_reg(r) {} @@ -82,6 +114,16 @@ namespace udb { template requires (BitsClass::IsABits) Reg(const BitsClass& r, bool is_fp = false) : m_reg(Enum(is_fp ? r.get() + 32 : r.get())) {} + + template + static Reg from_rf_index(T idx, uint64_t base) { + if constexpr (requires { T::IsABits; }) { + return Reg(Enum(idx.get() + base)); + } else { + return Reg(Enum(static_cast(idx) + base)); + } + } + operator Enum() const { return m_reg; } bool operator==(const Reg &other) const { return m_reg == other.m_reg; } bool operator==(Enum other) const { return m_reg == other; } @@ -92,16 +134,18 @@ namespace udb { bool is_int() const { return m_reg <= X31; } bool is_fp() const { return m_reg >= F0 && m_reg <= F31; } + bool is_vec() const { return m_reg >= V0 && m_reg <= V31; } uint64_t get_num() const { uint64_t num = static_cast(m_reg); - return (m_reg <= X31) ? num : num - 32; // NOLINT + if (m_reg <= X31) return num; + if (m_reg <= F31) return num - 32u; // NOLINT + return num - 64u; // V // NOLINT } std::string to_string(uint64_t size = 64) const { - if (is_fp()) { - return "f" + std::to_string(get_num()); - } + if (is_fp()) return "f" + std::to_string(get_num()); + if (is_vec()) return "v" + std::to_string(get_num()); return "x" + std::to_string(get_num()); } diff --git a/backends/cpp_hart_gen/cpp/src/iss.cpp b/backends/cpp_hart_gen/cpp/src/iss.cpp index 1e0e5f7f5f..fcdf3be8d5 100644 --- a/backends/cpp_hart_gen/cpp/src/iss.cpp +++ b/backends/cpp_hart_gen/cpp/src/iss.cpp @@ -26,7 +26,6 @@ #define RISCV_REG_PC 0x20 #define RISCV_REG_FPR_FIRST 0x21 #define RISCV_REG_FPR_LAST 0x40 -#define RISCV_REG_FPR_LAST 0x40 #define RISCV_REG_CSR_FIRST 0x41 #define RISCV_REG_CSR_LAST 0x1040 @@ -419,8 +418,14 @@ int InstructionSetSimulator::OnReadSingleRegister(int reg, uint64_t& value) value = m_pHart->pc(); else if (reg >= RISCV_REG_FPR_FIRST && reg <= RISCV_REG_FPR_LAST) { - //no FP so far - return -1; + try + { + value = m_pHart->freg(reg - RISCV_REG_FPR_FIRST); + } + catch(...) + { + return -1; + } } else if (reg >= RISCV_REG_CSR_FIRST && reg <= RISCV_REG_CSR_LAST) { @@ -456,8 +461,14 @@ int InstructionSetSimulator::OnWriteSingleRegister(int reg, uint64_t& value) m_pHart->set_next_pc(value); else if (reg >= RISCV_REG_FPR_FIRST && reg <= RISCV_REG_FPR_LAST) { - //no FP so far - return -1; + try + { + m_pHart->set_freg(reg - RISCV_REG_FPR_FIRST, value); + } + catch(...) + { + return -1; + } } else if (reg >= RISCV_REG_CSR_FIRST && reg <= RISCV_REG_CSR_LAST) { diff --git a/backends/cpp_hart_gen/cpp/test/test_regfile.cpp b/backends/cpp_hart_gen/cpp/test/test_regfile.cpp new file mode 100644 index 0000000000..bf154373e4 --- /dev/null +++ b/backends/cpp_hart_gen/cpp/test/test_regfile.cpp @@ -0,0 +1,179 @@ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +// SPDX-License-Identifier: BSD-3-Clause-Clear + +// Tests for register file storage and accessor generation (Layer 4a–4c). + +#include +#include +#include +#include + +// Use the rv64-riscv-tests config (known-working fully-configured rv64 with F extension). +static const std::string cfg_yaml = R"( +$schema: https://riscv.org/udb/schemas/config_schema-0.1.0.json +kind: architecture configuration +type: fully configured +name: rv64-riscv-tests +description: For register file testing + +implemented_extensions: + - [Sm, "1.11.0"] + - [Smstateen, "1.0.0"] + - [I, "2.1"] + - [C, "2.0"] + - [M, "2.0"] + - [Zicsr, "2.0"] + - [Zicntr, "2.0"] + - [Smrnmi, "1.0"] + - [S, "1.11.0"] + - [U, "1.0.0"] + - [Zifencei, "2.0.0"] + - [Sv39, "1.11.0"] + - [Zca, "1.0.0"] + - [F, "2.2.0"] + +params: + MXLEN: 64 + MARCHID_IMPLEMENTED: true + ARCH_ID_VALUE: 1 + MIMPID_IMPLEMENTED: true + IMP_ID_VALUE: 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: sequential_bytes + 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_ACCESS: rw + MTVEC_MODES: [0, 1] + MTVEC_BASE_ALIGNMENT_DIRECT: 4 + MTVEC_BASE_ALIGNMENT_VECTORED: 4 + MTVEC_ILLEGAL_WRITE_BEHAVIOR: retain + 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 + MCOUNTENABLE_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] + 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] + COUNTINHIBIT_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_ECALL_FROM_U: true + MSTATUS_VS_LEGAL_VALUES: [0] + MSTATUS_FS_LEGAL_VALUES: [3, 2, 1, 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 + HW_MSTATUS_FS_DIRTY_UPDATE: precise + MUTABLE_MISA_F: false + HPM_COUNTER_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] + MCOUNTINHIBIT_IMPLEMENTED: true +)"; + +// --------------------------------------------------------------------------- +// X register file tests (Layer 4a–4c) +// --------------------------------------------------------------------------- + +TEST_CASE("X register storage has 32 entries", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + // Write a known value to x31, verify it round-trips; index 32 throws. + REQUIRE_NOTHROW(hart->set_xreg(31, 42)); + REQUIRE(hart->xreg(31) == 42); + REQUIRE_THROWS_AS(hart->xreg(32), std::out_of_range); + delete hart; +} + +TEST_CASE("x0 is zero after reset", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + REQUIRE(hart->xreg(0) == 0); + delete hart; +} + +TEST_CASE("writing to x0 leaves it zero (arch_write)", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + hart->set_xreg(0, 42); + REQUIRE(hart->xreg(0) == 0); + delete hart; +} + +TEST_CASE("xreg throws out_of_range for index >= 32", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + REQUIRE_THROWS_AS(hart->set_xreg(32, 0), std::out_of_range); + delete hart; +} + +// --------------------------------------------------------------------------- +// F register file tests (Layer 4d: hart.hpp adds virtual freg() to HartBase) +// --------------------------------------------------------------------------- + +TEST_CASE("F register storage has 32 entries", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + REQUIRE_NOTHROW(hart->set_freg(31, 0xdeadbeef)); + REQUIRE(hart->freg(31) == 0xdeadbeef); + REQUIRE_THROWS_AS(hart->freg(32), std::out_of_range); + delete hart; +} + +TEST_CASE("freg round-trips a written value", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + hart->set_freg(0, 0x3f800000); + REQUIRE(hart->freg(0) == 0x3f800000); + delete hart; +} + +TEST_CASE("freg throws out_of_range for index >= 32", "[regfile]") { + udb::IssSocModel soc(1024 * 1024, 0); + auto* hart = udb::HartFactory::create("rv64", 0, cfg_yaml, soc); + REQUIRE_THROWS_AS(hart->set_freg(32, 0), std::out_of_range); + delete hart; +} diff --git a/backends/cpp_hart_gen/lib/gen_cpp.rb b/backends/cpp_hart_gen/lib/gen_cpp.rb index ca32d13548..f096fd6812 100644 --- a/backends/cpp_hart_gen/lib/gen_cpp.rb +++ b/backends/cpp_hart_gen/lib/gen_cpp.rb @@ -873,9 +873,12 @@ def gen_cpp(symtab, indent = 0, indent_spaces: 2) "#{' ' * indent}#{var.gen_cpp(symtab, 0, indent_spaces:)}.at(#{index.gen_cpp(symtab, 0)})" end else - if var.text_value.start_with?("X") - #"#{' '*indent}#{var.gen_cpp(symtab, 0, indent_spaces:)}[#{index.gen_cpp(symtab, 0, indent_spaces:)}]" - "#{' ' * indent} __UDB_HART->_xreg(#{index.gen_cpp(symtab, 0, indent_spaces:)})" + var_type = var.type(symtab) + if var_type.kind == :array && + var_type.sub_type.is_a?(Idl::RegFileElementType) && + var_type.qualifiers.include?(:global) + rf_name = var_type.sub_type.name.downcase + "#{' ' * indent}__UDB_HART->_#{rf_name}reg(#{index.gen_cpp(symtab, 0, indent_spaces:)})" else "#{' ' * indent}#{var.gen_cpp(symtab, 0, indent_spaces:)}.at(#{index.gen_cpp(symtab, 0, indent_spaces:)}.get())" end @@ -928,9 +931,12 @@ def gen_cpp(symtab, indent = 0, indent_spaces: 2) class AryElementAssignmentAst < AstNode sig { override.params(symtab: SymbolTable, indent: Integer, indent_spaces: Integer).returns(String) } def gen_cpp(symtab, indent = 0, indent_spaces: 2) - if lhs.is_a?(Idl::IdAst) && lhs.name == "X" - #"#{' '*indent} #{lhs.gen_cpp(symtab, 0, indent_spaces:)}[#{idx.gen_cpp(symtab, 0, indent_spaces:)}] = #{rhs.gen_cpp(symtab, 0, indent_spaces:)}" - "#{' ' * indent}__UDB_HART->_set_xreg( #{idx.gen_cpp(symtab, 0, indent_spaces:)}, #{rhs.gen_cpp(symtab, 0, indent_spaces:)})" + lhs_type = lhs.type(symtab) + if lhs_type.kind == :array && + lhs_type.sub_type.is_a?(Idl::RegFileElementType) && + lhs_type.qualifiers.include?(:global) + rf_name = lhs_type.sub_type.name.downcase + "#{' ' * indent}__UDB_HART->_set_#{rf_name}reg( #{idx.gen_cpp(symtab, 0, indent_spaces:)}, #{rhs.gen_cpp(symtab, 0, indent_spaces:)})" elsif lhs.type(symtab).kind == :bits "#{' ' * indent}#{lhs.gen_cpp(symtab, 0, indent_spaces:)}.setBit(#{idx.gen_cpp(symtab, 0, indent_spaces:)}, #{rhs.gen_cpp(symtab, 0, indent_spaces:)})" else diff --git a/backends/cpp_hart_gen/lib/template_helpers.rb b/backends/cpp_hart_gen/lib/template_helpers.rb index 01fd3669ee..7fdac58da8 100644 --- a/backends/cpp_hart_gen/lib/template_helpers.rb +++ b/backends/cpp_hart_gen/lib/template_helpers.rb @@ -156,6 +156,53 @@ def quot_str(val) val end end + + # C++ width string for a register file element type (e.g. "64" or "VLEN"). + # Used in template parameters like PossiblyUnknownBits. + def rf_elem_width(rf) + width = rf.eval_register_length(cfg_arch) + width.is_a?(String) ? width : width.to_s + end + + # Compile an IDL expression string to an AST node that responds to gen_cpp. + def compile_idl_expr(idl_str) + cfg_arch.idl_compiler.compile_expression(idl_str, cfg_arch.symtab) + end + + # IDL Type for one register file element (Bits). + def rf_elem_type(rf) + width = rf.eval_register_length(cfg_arch) + Idl::Type.new(:bits, width: width.is_a?(String) ? rf.max_register_length : width) + end + + def gen_arch_read_cpp(entry) = idl_body_to_cpp(entry.arch_read) + def gen_arch_write_cpp(entry) = idl_body_to_cpp(entry.arch_write) + + # True if the named register file (e.g. "F") has register_class: floating_point. + def rf_floating_point?(rf_name) + cfg_arch.register_files.find { |rf| rf.name == rf_name }&.register_class == "floating_point" + end + + # Returns the base offset into udb::Reg::Enum for the named register file. + # Must match the enum layout in backends/cpp_hart_gen/cpp/include/udb/inst.hpp. + RF_ENUM_BASES = { "X" => 0, "F" => 32, "V" => 64 }.freeze + def rf_enum_base(rf_name) + RF_ENUM_BASES.fetch(rf_name) { raise "No Reg::Enum base defined for register file '#{rf_name}'" } + end + + # All register files defined for this architecture. + # The ISS generates storage and accessors for all register files since + # for a partially-configured arch, any extension may be present. + def applicable_register_files + cfg_arch.register_files + end + + private + + def idl_body_to_cpp(body) + expr_str = body.strip.sub(/\Areturn\s+/, "").sub(/;\z/, "").strip + compile_idl_expr(expr_str).gen_cpp(cfg_arch.symtab, 0) + end end class TemplateEnv diff --git a/backends/cpp_hart_gen/tasks.rake b/backends/cpp_hart_gen/tasks.rake index 138922afd3..c84638a6f7 100644 --- a/backends/cpp_hart_gen/tasks.rake +++ b/backends/cpp_hart_gen/tasks.rake @@ -204,6 +204,7 @@ rule %r{#{CPP_HART_GEN_DST}/[^/]+/build/Makefile} => [ "-S#{CPP_HART_GEN_DST}/#{build_name}", "-B#{CPP_HART_GEN_DST}/#{build_name}/build", "-DCMAKE_CXX_COMPILER=#{$root}/bin/g++", + "-DCOVERAGE_COMMAND=#{$root}/bin/gcov", "-DCONFIG_LIST=\"#{ENV['CONFIG'].gsub(',', ';')}\"", "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DCMAKE_BUILD_TYPE=#{cmake_build_type}", @@ -420,6 +421,7 @@ namespace :test do Dir.chdir "#{CPP_HART_GEN_DST}/#{build_name}/build" do sh "make -j #{$jobs} test_bits_directed" sh "make -j #{$jobs} test_bits_random" + sh "make -j #{$jobs} test_regfile" sh "ctest -T coverage -T test" end end diff --git a/backends/cpp_hart_gen/templates/hart.hxx.erb b/backends/cpp_hart_gen/templates/hart.hxx.erb index a0df0e6224..10284716b7 100644 --- a/backends/cpp_hart_gen/templates/hart.hxx.erb +++ b/backends/cpp_hart_gen/templates/hart.hxx.erb @@ -79,10 +79,10 @@ namespace udb { public: <%- cfg_arch.globals.each do |global| -%> <%- if global.is_a?(Idl::GlobalWithInitializationAst) -%> - <%- if global.type(cfg_arch.symtab).const? -%> - static <%= global.type(cfg_arch.symtab).const? ? 'constexpr ' : '' %><%= global.type(cfg_arch.symtab).to_cxx %> <%= global.id %> = <%= global.rhs.gen_cpp(cfg_arch.symtab, 0) %>; + <%- if global.is_a?(Idl::GlobalWithInitializationAst) && global.type(cfg_arch.symtab).const? && global.rhs.const_eval?(cfg_arch.symtab) -%> + static constexpr <%= global.type(cfg_arch.symtab).to_cxx %> <%= global.id %> = <%= global.rhs.gen_cpp(cfg_arch.symtab, 0) %>; <%- else -%> - static <%= global.type(cfg_arch.symtab).to_cxx %> <%= global.id %>; + static <%= global.type(cfg_arch.symtab).to_cxx.gsub("const ", "") %> <%= global.id %>; <%- end -%> <%- else -%> static <%= global.type(cfg_arch.symtab).to_cxx %> <%= global.id %>; @@ -94,13 +94,18 @@ namespace udb { static constexpr unsigned MXLEN = <%= cfg_arch.mxlen.nil? ? 64 : cfg_arch.mxlen %>; using XReg = Bits; +#define __UDB_FUNC_CALL this-> <%= hart_name -%>(uint64_t hart_id, SocType& soc, const Config& cfg) : HartBase(hart_id, soc, cfg), m_params(cfg), - <%- if cfg_arch.mxlen.nil? -%> - m_xregs { - <%- 32.times do |i| -%> - { WidthArg(m_params.MXLEN.value()) }, + <%- applicable_register_files.each do |rf| -%> + <%- rf_name = rf.name.downcase -%> + <%- width = rf.eval_register_length(cfg_arch) -%> + <%- next unless width.is_a?(String) -%> + <%- param_name = width -%> + m_<%= rf_name %>regs { + <%- rf.registers.count.times do -%> + PossiblyUnknownRuntimeBits<<%= rf.max_register_length %>>{ WidthArg(m_params.<%= param_name %>.has_value() ? static_cast(m_params.<%= param_name %>.value().get()) : static_cast(<%= rf.max_register_length %>)) }, <%- end -%> }, <%- end -%> @@ -127,7 +132,14 @@ namespace udb { <%- end -%> } { - m_xregs[0] = 0_b; // set x0 + <%- applicable_register_files.each do |rf| -%> + <%- rf_name = rf.name.downcase -%> + <%- rf.registers.each do |r| -%> + <%- next if r.reset_value.nil? -%> + <%- reset_cpp = compile_idl_expr(r.reset_value).gen_cpp(cfg_arch.symtab, 0) -%> + m_<%= rf_name %>regs[<%= r.index %>] = <%= reset_cpp %>; + <%- end -%> + <%- end -%> } void reset(uint64_t reset_pc) override { @@ -137,7 +149,7 @@ namespace udb { <%- cfg_arch.globals.each do |global| -%> <%- if global.is_a?(Idl::GlobalWithInitializationAst) -%> - <%- next if global.type(cfg_arch.symtab).const? -%> + <%- next if global.type(cfg_arch.symtab).const? && global.rhs.const_eval?(cfg_arch.symtab) -%> <%- lhs_t = global.type(cfg_arch.symtab) -%> <%- rhs_t = global.rhs.type(cfg_arch.symtab) -%> <%- rhs_cpp = global.rhs.gen_cpp(cfg_arch.symtab, 0) -%> @@ -154,6 +166,7 @@ namespace udb { m_csrs.reset(); } +#undef __UDB_FUNC_CALL bool implemented_version_Q_(const ExtensionName& ext, const VersionRequirement& req) const override { @@ -323,40 +336,74 @@ namespace udb { unsigned mxlen() override { return MXLEN; } - uint64_t xreg(unsigned num) const override { - if (num >= 32) { - throw std::out_of_range("X register indices are 0 - 31, inclusive"); + <%- applicable_register_files.each do |rf| -%> + <%- rf_name = rf.name.downcase -%> + <%- bits_width = rf_elem_width(rf) -%> + <%- rf_width = rf.eval_register_length(cfg_arch) -%> + <%- is_runtime_width = rf_width.is_a?(String) -%> + <%- accessor_type = is_runtime_width ? "PossiblyUnknownRuntimeBits<#{rf.max_register_length}>" : "PossiblyUnknownBits<#{bits_width}>" -%> + <%- setter_param_type = is_runtime_width ? "_PossiblyUnknownRuntimeBits<#{rf.max_register_length}, false>" : "_PossiblyUnknownBits<#{bits_width}, false>" -%> + <%- entries_with_read = rf.registers.select { |r| r.arch_read } -%> + <%- entries_with_write = rf.registers.select { |r| r.arch_write } -%> + + uint64_t <%= rf_name %>reg(unsigned num) const override { + if (num >= <%= rf.registers.count %>) { + throw std::out_of_range("<%= rf.name %> register indices are 0 - <%= rf.registers.count - 1 %>, inclusive"); } - return _xreg(num).get(); + <%- if is_runtime_width -%> + return static_cast(_<%= rf_name %>reg(num).get().get_ui()); + <%- else -%> + return _<%= rf_name %>reg(num).get(); + <%- end -%> } - PossiblyUnknownBits _xreg(unsigned num) const { - return m_xregs[num]; + <%= accessor_type %> _<%= rf_name %>reg(unsigned num) const { + <%- if entries_with_read.any? -%> + switch (num) { + <%- entries_with_read.each do |r| -%> + case <%= r.index %>: return <%= accessor_type %>(<%= gen_arch_read_cpp(r) %>); + <%- end -%> + default: return m_<%= rf_name %>regs[num]; + } + <%- else -%> + return m_<%= rf_name %>regs[num]; + <%- end -%> } template