aboutsummaryrefslogtreecommitdiff
path: root/rv64cpu
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-03-18 19:48:35 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-03-18 19:48:35 +0800
commit1d4ed362e1caccc22aa4bd0dc2a9316e999f849a (patch)
tree3c8d3a0c5ed61ef0e0e54995b0ab95411c289215 /rv64cpu
parent5e18d160d16771252292ccebcb66ae4ba8cc9d64 (diff)
downloadrcc-project-1d4ed362e1caccc22aa4bd0dc2a9316e999f849a.tar.gz
rcc-project-1d4ed362e1caccc22aa4bd0dc2a9316e999f849a.tar.xz
Add fibonacci tests and fix bugs
Diffstat (limited to 'rv64cpu')
-rw-r--r--rv64cpu/rtl/core/regfile.sv11
-rw-r--r--rv64cpu/tb/core/tb_core.cc61
-rw-r--r--rv64cpu/tb/unit/tb_regfile.cc13
3 files changed, 77 insertions, 8 deletions
diff --git a/rv64cpu/rtl/core/regfile.sv b/rv64cpu/rtl/core/regfile.sv
index 640890d..dbc3c04 100644
--- a/rv64cpu/rtl/core/regfile.sv
+++ b/rv64cpu/rtl/core/regfile.sv
@@ -41,8 +41,15 @@ module regfile
logic [XLEN-1:0] regs [0:31];
// Read Logic (combinational logic)
- assign rs1_rdata = (rs1_addr == 5'b0) ? '0 : regs[rs1_addr];
- assign rs2_rdata = (rs2_addr == 5'b0) ? '0 : regs[rs2_addr];
+ // Internal bypass: If reading the same register as currently being written,
+ // forward the write data immediately.
+ assign rs1_rdata = (rs1_addr == 5'b0) ? '0 :
+ ((rs1_addr == rd_addr) && reg_write_en) ? rd_wdata :
+ regs[rs1_addr];
+
+ assign rs2_rdata = (rs2_addr == 5'b0) ? '0 :
+ ((rs2_addr == rd_addr) && reg_write_en) ? rd_wdata :
+ regs[rs2_addr];
// Write Logic (sequential logic)
always_ff @(posedge clk) begin
diff --git a/rv64cpu/tb/core/tb_core.cc b/rv64cpu/tb/core/tb_core.cc
index 1c5926c..30fe554 100644
--- a/rv64cpu/tb/core/tb_core.cc
+++ b/rv64cpu/tb/core/tb_core.cc
@@ -53,6 +53,21 @@ static uint32_t rv_s_type(uint32_t imm12, uint32_t rs2, uint32_t rs1, uint32_t f
return (imm_hi << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (imm_lo << 7) | opcode;
}
+// U-type: imm[31:12] | rd[4:0] | opcode[6:0]
+static uint32_t rv_u_type(uint32_t imm20, uint32_t rd, uint32_t opcode) {
+ return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | opcode;
+}
+
+// J-type: imm[20] | imm[10:1] | imm[11] | imm[19:12] | rd[4:0] | opcode[6:0]
+static uint32_t rv_j_type(int32_t offset, uint32_t rd, uint32_t opcode) {
+ uint32_t imm = static_cast<uint32_t>(offset);
+ uint32_t bit20 = (imm >> 20) & 0x1;
+ uint32_t bit10_1 = (imm >> 1) & 0x3FF;
+ uint32_t bit11 = (imm >> 11) & 0x1;
+ uint32_t bit19_12 = (imm >> 12) & 0xFF;
+ return (bit20 << 31) | (bit10_1 << 21) | (bit11 << 20) | (bit19_12 << 12) | (rd << 7) | opcode;
+}
+
// B-type: imm[12|10:5] | rs2[4:0] | rs1[4:0] | funct3[2:0] | imm[4:1|11] | opcode[6:0]
static uint32_t rv_b_type(int32_t offset, uint32_t rs2, uint32_t rs1, uint32_t funct3, uint32_t opcode) {
uint32_t imm = static_cast<uint32_t>(offset);
@@ -87,6 +102,12 @@ static uint32_t BEQ(uint32_t rs1, uint32_t rs2, int32_t offset) {
static uint32_t BNE(uint32_t rs1, uint32_t rs2, int32_t offset) {
return rv_b_type(offset, rs2, rs1, 0x1, 0x63);
}
+static uint32_t LUI(uint32_t rd, uint32_t imm) {
+ return rv_u_type(imm, rd, 0x37);
+}
+static uint32_t JAL(uint32_t rd, int32_t offset) {
+ return rv_j_type(offset, rd, 0x6f);
+}
// -----------------------
// Test Infrastructure
@@ -574,6 +595,41 @@ void test_reset_mid_execution(CoreSim& sim) {
ASSERT_EQ(sim.top->dmem_write_en, 0, "Mid-reset: no dmem write");
}
+// Test 13: RV64 Fibonacci Sequence Integration Test
+void test_fibonacci(CoreSim& sim) {
+ std::cout << "Test 13: RV64 Fibonacci Sequence..." << std::endl;
+
+ std::vector<uint32_t> program = {
+ ADDI(5, 0, 10), // addi x5, x0, 10
+ LUI(6, 0x10000), // lui x6, 0x10000
+ ADDI(7, 0, 0), // addi x7, x0, 0
+ ADDI(8, 0, 1), // addi x8, x0, 1
+ BEQ(5, 0, 32), // beq x5, x0, 32
+ SD(7, 6, 0), // sd x7, 0(x6)
+ ADD(9, 7, 8), // add x9, x7, x8
+ ADDI(7, 8, 0), // addi x7, x8, 0
+ ADDI(8, 9, 0), // addi x8, x9, 0
+ ADDI(6, 6, 8), // addi x6, x6, 8
+ ADDI(5, 5, -1), // addi x5, x5, -1
+ JAL(0, -28), // jal x0, -28
+ JAL(0, 0) // jal x0, 0
+ };
+
+ sim.mem.load_program(0x80000000ULL, program);
+ sim.reset();
+
+ sim.run(200);
+
+ uint64_t expected_fib[10] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34};
+
+ for (int i = 0; i < 10; i++) {
+ uint64_t addr = 0x10000000ULL + (i * 8);
+ uint64_t actual_val = sim.mem.read_data(addr);
+
+ ASSERT_EQ(actual_val, expected_fib[i], "Fibonacci value mismatch");
+ }
+}
+
// ═══════════════════════════════════════════════════════════════
// Main
// ═══════════════════════════════════════════════════════════════
@@ -634,6 +690,11 @@ int main(int argc, char** argv) {
test_reset_mid_execution(sim);
}
+ {
+ CoreSim sim;
+ test_fibonacci(sim);
+ }
+
std::cout << "================================================================" << std::endl;
std::cout << " Results: " << g_pass_count << "/" << g_test_count << " assertions passed" << std::endl;
std::cout << "================================================================" << std::endl;
diff --git a/rv64cpu/tb/unit/tb_regfile.cc b/rv64cpu/tb/unit/tb_regfile.cc
index 3d08dd5..8e210ec 100644
--- a/rv64cpu/tb/unit/tb_regfile.cc
+++ b/rv64cpu/tb/unit/tb_regfile.cc
@@ -122,6 +122,7 @@ int main(int argc, char** argv) {
// Apply reset
dut->rst = 1;
+ dut->reg_write_en = 0; // Clear write enable from previous test
tick(dut);
dut->rst = 0;
@@ -139,21 +140,21 @@ int main(int argc, char** argv) {
std::cout << "\033[32m[PASS] Full memory reset verified\033[0m" << std::endl;
// Test 7: Read-After-Write (Same cycle collision check)
- // Combinational read should return the OLD value on the cycle WE is asserted
- // NOTE: Verilator handles combinational loops. Before the clock edge, it evaluates.
- dut->reg_write_en = 1;
+ // With internal bypass added, combinational read should return the NEW bypassed value immediately.
+ dut->reg_write_en = 0;
dut->rd_addr = 15;
- dut->rd_wdata = 0x55555555; // Pseudo
+ dut->rd_wdata = 0x55555555;
+ tick(dut); // Write 0x55555555 to x15 to set old value
// Setup for RAW
dut->reg_write_en = 1;
dut->rd_addr = 15;
dut->rd_wdata = 0x99999999;
- // Before tick, read should be 0 (from previous reset)
+ // Before tick, read should be the new bypassed value (0x99999999)
dut->rs1_addr = 15;
dut->eval();
- assert(dut->rs1_rdata == 0);
+ assert(dut->rs1_rdata == 0x99999999);
tick(dut); // Clock edge happens