Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions backends/cpp_hart_gen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
# )
Expand All @@ -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})
Expand Down
4 changes: 2 additions & 2 deletions backends/cpp_hart_gen/cpp/include/udb/bits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3370,9 +3370,9 @@ namespace udb {

#undef RUNTIME_BITS_BINARY_OP

_PossiblyUnknownRuntimeBits operator~() { return _PossiblyUnknownRuntimeBits{~m_val, _Bits<MaxN, false>{m_width}}; }
_PossiblyUnknownRuntimeBits operator~() { return _PossiblyUnknownRuntimeBits{~m_val, m_width}; }

_PossiblyUnknownRuntimeBits operator-() { return _PossiblyUnknownRuntimeBits{-m_val, _Bits<MaxN, false>{m_width}}; }
_PossiblyUnknownRuntimeBits operator-() { return _PossiblyUnknownRuntimeBits{-m_val, m_width}; }

template <unsigned msb, unsigned lsb>
requires ((lsb >= 0) && (msb >= lsb) && (msb <= MaxN))
Expand Down
13 changes: 13 additions & 0 deletions backends/cpp_hart_gen/cpp/include/udb/hart.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
54 changes: 49 additions & 5 deletions backends/cpp_hart_gen/cpp/include/udb/inst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand All @@ -82,6 +114,16 @@ namespace udb {
template <typename BitsClass>
requires (BitsClass::IsABits)
Reg(const BitsClass& r, bool is_fp = false) : m_reg(Enum(is_fp ? r.get() + 32 : r.get())) {}

template <typename T>
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<uint64_t>(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; }
Expand All @@ -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<uint64_t>(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());
}

Expand Down
21 changes: 16 additions & 5 deletions backends/cpp_hart_gen/cpp/src/iss.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
}
}
Comment thread
dhower-qc marked this conversation as resolved.
else if (reg >= RISCV_REG_CSR_FIRST && reg <= RISCV_REG_CSR_LAST)
{
Expand Down
179 changes: 179 additions & 0 deletions backends/cpp_hart_gen/cpp/test/test_regfile.cpp
Original file line number Diff line number Diff line change
@@ -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 <catch2/catch_test_macros.hpp>
#include <udb/hart_factory.hxx>
#include <udb/iss_soc_model.hpp>
#include <stdexcept>

// 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;
}
Loading
Loading