diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-03-16 14:57:03 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-03-16 15:02:06 +0800 |
| commit | ac1bfb6ae8253d71904a273b20a1d0e5d4803fd4 (patch) | |
| tree | 61bd790dcf30dfd3435c7738c1f9e63f3ac121dd | |
| parent | 1554746fd79d51c6bd2281820520a4e2d2c16301 (diff) | |
| download | rcc-project-ac1bfb6ae8253d71904a273b20a1d0e5d4803fd4.tar.gz rcc-project-ac1bfb6ae8253d71904a273b20a1d0e5d4803fd4.tar.xz | |
expand tests and format output
| -rw-r--r-- | rv64cpu/tb/unit/tb_alu.cc | 27 | ||||
| -rw-r--r-- | rv64cpu/tb/unit/tb_decoder.cc | 8 | ||||
| -rw-r--r-- | rv64cpu/tb/unit/tb_regfile.cc | 98 |
3 files changed, 124 insertions, 9 deletions
diff --git a/rv64cpu/tb/unit/tb_alu.cc b/rv64cpu/tb/unit/tb_alu.cc index 0d37b30..60afd4e 100644 --- a/rv64cpu/tb/unit/tb_alu.cc +++ b/rv64cpu/tb/unit/tb_alu.cc @@ -77,6 +77,33 @@ int main(int argc, char** argv) { 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)"); + + // 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 << "All tests passed!" << std::endl; delete alu; diff --git a/rv64cpu/tb/unit/tb_decoder.cc b/rv64cpu/tb/unit/tb_decoder.cc index e55bbb6..1fbb7be 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,9 +43,9 @@ 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) { diff --git a/rv64cpu/tb/unit/tb_regfile.cc b/rv64cpu/tb/unit/tb_regfile.cc index eef92a2..2491eb6 100644 --- a/rv64cpu/tb/unit/tb_regfile.cc +++ b/rv64cpu/tb/unit/tb_regfile.cc @@ -48,7 +48,7 @@ int main(int argc, char** argv) { 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 +60,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 +72,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 +90,97 @@ 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 << "Register file unit test complete\033[0m" << std::endl; delete dut; exit(0); |
