aboutsummaryrefslogtreecommitdiff
path: root/rv64cpu
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-03-16 15:21:03 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-03-16 15:21:03 +0800
commit660e5ce626965105f6a9327c66ba251f17f7c5f7 (patch)
treebfe5e44e6074feee02368bc5954fc06cf714f1f0 /rv64cpu
parent1554746fd79d51c6bd2281820520a4e2d2c16301 (diff)
parent161eb7764bb9054aa21080b5100a4e743ab91fd6 (diff)
downloadrcc-project-660e5ce626965105f6a9327c66ba251f17f7c5f7.tar.gz
rcc-project-660e5ce626965105f6a9327c66ba251f17f7c5f7.tar.xz
Merge pull request #1 from Richard-Qin-001/expand-tests
Expand tests and format output
Diffstat (limited to 'rv64cpu')
-rw-r--r--rv64cpu/tb/unit/tb_alu.cc43
-rw-r--r--rv64cpu/tb/unit/tb_decoder.cc17
-rw-r--r--rv64cpu/tb/unit/tb_regfile.cc104
3 files changed, 143 insertions, 21 deletions
diff --git a/rv64cpu/tb/unit/tb_alu.cc b/rv64cpu/tb/unit/tb_alu.cc
index 0d37b30..04eaaed 100644
--- a/rv64cpu/tb/unit/tb_alu.cc
+++ b/rv64cpu/tb/unit/tb_alu.cc
@@ -44,13 +44,11 @@ void test_alu(Valu* alu, uint8_t op, uint64_t rs1, uint64_t rs2, uint64_t expect
if (alu->alu_result == expected) {
std::cout << "\033[32m";
std::cout << "[PASS] " << test_name << " | "
- << rs1 << " op " << rs2 << " = " << expected << std::endl;
- std::cout << "\033[0m";
+ << rs1 << " op " << rs2 << " = " << expected << "\033[0m" << std::endl;
} else {
std::cout << "\033[31m";
std::cerr << "[FAIL] " << test_name << " | "
- << "Expected: " << expected << ", Got: " << alu->alu_result << std::endl;
- std::cout << "\033[0m";
+ << "Expected: " << expected << ", Got: " << alu->alu_result << "\033[0m" << std::endl;
assert(false);
}
}
@@ -59,7 +57,9 @@ int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
Valu* alu = new Valu;
- std::cout << "Running ALU Unit Test ..." << std::endl;
+ std::cout << "----------------------------------" << std::endl;
+ std::cout << " ALU Unit Test" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
test_alu(alu, ALU_ADD, 100, 50, 150, "ADD_Positive");
test_alu(alu, ALU_SUB, 100, 50, 50, "SUB_Positive");
@@ -73,11 +73,40 @@ int main(int argc, char** argv) {
uint64_t minus_one = (uint64_t)-1;
uint64_t five = 5;
-
+
test_alu(alu, ALU_SLTU, minus_one, five, 0, "SLTU (Unsigned: -1 < 5 is False)");
test_alu(alu, ALU_SLT, minus_one, five, 1, "SLT (Signed: -1 < 5 is True)");
- std::cout << "All tests passed!" << std::endl;
+
+ // Missing Basic Operations
+ test_alu(alu, ALU_OR, 0xAAAA, 0x5555, 0xFFFF, "OR_All_Bits");
+ test_alu(alu, ALU_SRL, 0xF000000000000000ULL, 4, 0x0F00000000000000ULL, "SRL_By_4");
+
+ // Arithmetic Right Shift (SRA)
+ test_alu(alu, ALU_SRA, 0xF000000000000000ULL, 4, 0xFF00000000000000ULL, "SRA_Negative_By_4");
+ test_alu(alu, ALU_SRA, 0x7000000000000000ULL, 4, 0x0700000000000000ULL, "SRA_Positive_By_4");
+
+ // Shift Edge Cases
+ test_alu(alu, ALU_SLL, 1, 0, 1, "SLL_By_0");
+ test_alu(alu, ALU_SLL, 1, 63, 0x8000000000000000ULL, "SLL_By_63");
+ test_alu(alu, ALU_SRL, 0x8000000000000000ULL, 63, 1, "SRL_By_63");
+ test_alu(alu, ALU_SRA, 0x8000000000000000ULL, 63, 0xFFFFFFFFFFFFFFFFULL, "SRA_By_63_SignExt");
+
+ // All 0 / All 1 Cases
+ test_alu(alu, ALU_ADD, 0, 0, 0, "ADD_Zero");
+ test_alu(alu, ALU_ADD, 0xFFFFFFFFFFFFFFFFULL, 1, 0, "ADD_Overflow");
+ test_alu(alu, ALU_XOR, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0, "XOR_Same");
+
+ // SLT / SLTU Same Value
+ test_alu(alu, ALU_SLT, 100, 100, 0, "SLT_Same_Value");
+ test_alu(alu, ALU_SLTU, 100, 100, 0, "SLTU_Same_Value");
+
+ // SLT Edge Cases
+ test_alu(alu, ALU_SLT, 0x8000000000000000ULL, 0x7FFFFFFFFFFFFFFFULL, 1, "SLT_Min_max");
+ test_alu(alu, ALU_SLT, 0x7FFFFFFFFFFFFFFFULL, 0x8000000000000000ULL, 0, "SLT_Max_Min");
+ std::cout << "----------------------------------" << std::endl;
+ std::cout << "\033[32mAll tests passed!\033[0m" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
delete alu;
return 0;
diff --git a/rv64cpu/tb/unit/tb_decoder.cc b/rv64cpu/tb/unit/tb_decoder.cc
index e55bbb6..aa6788c 100644
--- a/rv64cpu/tb/unit/tb_decoder.cc
+++ b/rv64cpu/tb/unit/tb_decoder.cc
@@ -31,10 +31,10 @@ static int fail_count = 0;
uint64_t _got = (uint64_t)(dut->signal); \
uint64_t _exp = (uint64_t)(expected); \
if (_got != _exp) { \
- std::cerr << "\033[31m[FAIL]\033[0m " << test_name \
+ std::cerr << "\033[31m[FAIL] " << test_name \
<< " | " << #signal << " expected: 0x" \
<< std::hex << _exp << " got: 0x" << _got \
- << std::dec << std::endl; \
+ << std::dec << "\033[0m" << std::endl; \
fail_count++; \
} \
} while(0)
@@ -43,18 +43,18 @@ void decode(Vdecoder* dut, uint32_t instr, const char* name) {
dut->instr = instr;
dut->eval();
test_count++;
- std::cout << "[TEST " << std::setw(2) << test_count << "] " << name
+ std::cout << "\033[32m[PASS] [TEST " << std::setw(2) << test_count << "] " << name
<< " (0x" << std::hex << std::setw(8) << std::setfill('0')
- << instr << std::dec << std::setfill(' ') << ")" << std::endl;
+ << instr << std::dec << std::setfill(' ') << ")\033[0m" << std::endl;
}
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
Vdecoder* dut = new Vdecoder;
- std::cout << "═══════════════════════════════════════════════" << std::endl;
- std::cout << " Decoder Unit Test Suite" << std::endl;
- std::cout << "═══════════════════════════════════════════════" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
+ std::cout << " Decoder Unit Test" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
// 1. R-type: ADD x1, x2, x3
// funct7=0000000 rs2=00011 rs1=00010 funct3=000 rd=00001 op=0110011
@@ -285,13 +285,14 @@ int main(int argc, char** argv) {
CHECK(dut, reg_write_en, 0, "Illegal");
// Results
- std::cout << "═══════════════════════════════════════════════" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
if (fail_count == 0) {
std::cout << "\033[32mAll " << test_count << " tests passed!\033[0m" << std::endl;
} else {
std::cout << "\033[31m" << fail_count << " check(s) FAILED out of "
<< test_count << " tests.\033[0m" << std::endl;
}
+ std::cout << "----------------------------------" << std::endl;
delete dut;
return (fail_count > 0) ? 1 : 0;
diff --git a/rv64cpu/tb/unit/tb_regfile.cc b/rv64cpu/tb/unit/tb_regfile.cc
index eef92a2..3d08dd5 100644
--- a/rv64cpu/tb/unit/tb_regfile.cc
+++ b/rv64cpu/tb/unit/tb_regfile.cc
@@ -42,13 +42,15 @@ int main(int argc, char** argv) {
dut->rs1_addr = 0;
dut->rs2_addr = 0;
- std::cout << "Starting register file unit test" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
+ std::cout << " Register File Unit Test" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
// Test 1: Reset
dut->rst = 1;
tick(dut);
dut->rst = 0;
- std::cout << "[PASS] Reset complete" << std::endl;
+ std::cout << "\033[32m[PASS] Reset complete\033[0m" << std::endl;
// Test 2: Write and read
dut->reg_write_en = 1;
@@ -60,7 +62,7 @@ int main(int argc, char** argv) {
dut->rs1_addr = 5;
dut->eval();
assert(dut->rs1_rdata == 0xDEADBEEF);
- std::cout << "[PASS] Write and read (x5) complete" << std::endl;
+ std::cout << "\033[32m[PASS] Write and read (x5) complete\033[0m" << std::endl;
// Test 3: x0
dut->reg_write_en = 1;
@@ -72,7 +74,7 @@ int main(int argc, char** argv) {
dut->rs2_addr = 0;
dut->eval();
assert(dut->rs2_rdata == 0);
- std::cout << "[PASS] Write and read (x0) complete" << std::endl;
+ std::cout << "\033[32m[PASS] Write and read (x0) complete\033[0m" << std::endl;
// Test 4: Dual-port simultaneous read
dut->reg_write_en = 1;
@@ -90,9 +92,99 @@ int main(int argc, char** argv) {
dut->eval();
assert(dut->rs1_rdata == 0x87654321 && dut->rs2_rdata == 0x11223344);
- std::cout << "[PASS] Dual-port simultaneous read complete" << std::endl;
+ std::cout << "\033[32m[PASS] Dual-port simultaneous read complete\033[0m" << std::endl;
- std::cout << "Register file unit test complete" << std::endl;
+
+ // Test 5: Write enable = 0 (Data should not change)
+ dut->reg_write_en = 1;
+ dut->rd_addr = 10;
+ dut->rd_wdata = 0xCAFEBABE;
+ tick(dut);
+
+ dut->reg_write_en = 0; // Disable write
+ dut->rd_addr = 10;
+ dut->rd_wdata = 0x11111111; // Attempt to overwrite
+ tick(dut);
+
+ dut->rs1_addr = 10;
+ dut->eval();
+ assert(dut->rs1_rdata == 0xCAFEBABE);
+ std::cout << "\033[32m[PASS] Write enable = 0 correctly ignores write\033[0m" << std::endl;
+
+ // Test 6: Verify full reset behavior
+ // First, dirty up some registers
+ for (int i = 1; i < 32; i += 5) {
+ dut->reg_write_en = 1;
+ dut->rd_addr = i;
+ dut->rd_wdata = 0x1000 + i;
+ tick(dut);
+ }
+
+ // Apply reset
+ dut->rst = 1;
+ tick(dut);
+ dut->rst = 0;
+
+ // Check all are zero
+ bool reset_ok = true;
+ for (int i = 1; i < 32; i++) {
+ dut->rs1_addr = i;
+ dut->eval();
+ if (dut->rs1_rdata != 0) {
+ reset_ok = false;
+ std::cerr << "\033[31m[FAIL] Reset failed on register x" << i << std::endl;
+ }
+ }
+ assert(reset_ok);
+ 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;
+ dut->rd_addr = 15;
+ dut->rd_wdata = 0x55555555; // Pseudo
+
+ // 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)
+ dut->rs1_addr = 15;
+ dut->eval();
+ assert(dut->rs1_rdata == 0);
+
+ tick(dut); // Clock edge happens
+
+ dut->reg_write_en = 0; // Turn off write
+ dut->eval(); // Combinational read update
+ assert(dut->rs1_rdata == 0x99999999);
+ std::cout << "\033[32m[PASS] Read-After-Write (RAW) behavior verified\033[0m" << std::endl;
+
+ // Test 8: Sweep all registers (Write and Read distinct values)
+ for (int i = 1; i < 32; i++) {
+ dut->reg_write_en = 1;
+ dut->rd_addr = i;
+ dut->rd_wdata = 0xABCDE000 + i;
+ tick(dut);
+ }
+
+ dut->reg_write_en = 0;
+ bool sweep_ok = true;
+ for (int i = 1; i < 32; i++) {
+ dut->rs1_addr = i;
+ dut->eval();
+ if (dut->rs1_rdata != (0xABCDE000 + i)) {
+ sweep_ok = false;
+ }
+ }
+ assert(sweep_ok);
+ std::cout << "\033[32m[PASS] All 31 mutable registers write/read successfully without collision\033[0m" << std::endl;
+
+ std::cout << "----------------------------------" << std::endl;
+ std::cout << "\033[32mAll 8 tests passed!\033[0m" << std::endl;
+ std::cout << "----------------------------------" << std::endl;
delete dut;
exit(0);