aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-07 21:21:03 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-07 21:21:03 +0800
commit328d4ef7537a98bab8f6891a0280cda9e03b0cee (patch)
treea201ad9d62d2d566feb3da23d578e4df39f9a94a
parent9c34902e4a763109d7d6251781bcb92f6bc68c56 (diff)
downloadrcc-project-328d4ef7537a98bab8f6891a0280cda9e03b0cee.tar.gz
rcc-project-328d4ef7537a98bab8f6891a0280cda9e03b0cee.tar.xz
feat(tlb): enhance TLB functionality with ASID-targeted flush and additional test cases
-rw-r--r--rv64cpu/CMakeLists.txt6
-rw-r--r--rv64cpu/rtl/core/mmu/tlb.sv2
-rw-r--r--rv64cpu/tb/unit/tb_tlb.cc63
3 files changed, 70 insertions, 1 deletions
diff --git a/rv64cpu/CMakeLists.txt b/rv64cpu/CMakeLists.txt
index 4649abb..da146d5 100644
--- a/rv64cpu/CMakeLists.txt
+++ b/rv64cpu/CMakeLists.txt
@@ -1,4 +1,9 @@
cmake_minimum_required(VERSION 3.20)
+
+if(POLICY CMP0144)
+ cmake_policy(SET CMP0144 NEW)
+endif()
+
project(richard_cpu
VERSION 0.1.0
DESCRIPTION "RV64IMAZicsr_Zifencei Five-Stage Pipelined CPU SoC"
@@ -54,6 +59,7 @@ file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/waves)
# ─── Testing ────────────────────────────────────────────────────────────────────
enable_testing()
+include(CTest)
# ─── Testbench Subdirectory ─────────────────────────────────────────────────────
add_subdirectory(tb)
diff --git a/rv64cpu/rtl/core/mmu/tlb.sv b/rv64cpu/rtl/core/mmu/tlb.sv
index 521b08a..f466cb3 100644
--- a/rv64cpu/rtl/core/mmu/tlb.sv
+++ b/rv64cpu/rtl/core/mmu/tlb.sv
@@ -341,7 +341,7 @@ module tlb
logic mode_match;
logic [44:0] mask;
- asid_match = !flush_asid_valid || entries[i].g || (entries[i].asid == flush_asid);
+ asid_match = !flush_asid_valid || (!entries[i].g && (entries[i].asid == flush_asid));
mode_match = !flush_vpn_valid || (entries[i].mode == flush_mode);
if (flush_vpn_valid) begin
mask = make_vpn_mask(entries[i].mode, entries[i].level);
diff --git a/rv64cpu/tb/unit/tb_tlb.cc b/rv64cpu/tb/unit/tb_tlb.cc
index ba6af6d..f244fbe 100644
--- a/rv64cpu/tb/unit/tb_tlb.cc
+++ b/rv64cpu/tb/unit/tb_tlb.cc
@@ -409,6 +409,69 @@ int main(int argc, char** argv) {
issue_req(dut, va13, 18, MODE_SV48, 1, true, false, false, false);
check(dut->resp_page_fault == 1, "ABit_FetchFault_WhenA0");
+ // 22) ASID-targeted flush must preserve global entries
+ const uint64_t va14 = 0x0000'0000'8888'0600ULL;
+ do_refill(dut, sv48_vpn(va14), 0x88000ULL, 0, MODE_SV48, 33, true, false, true, true, false, true, true);
+ apply_flush_asid(dut, 33);
+ issue_load(dut, va14, 99, MODE_SV48);
+ check(dut->resp_hit == 1, "FlushAsid_GlobalPreserved");
+
+ // 23) Refill pressure should eventually evict oldest entry (round-robin)
+ apply_flush_all(dut);
+ const uint64_t va15 = 0x0000'0000'9000'1000ULL;
+ do_refill(dut, sv48_vpn(va15), 0x90001ULL, 0, MODE_SV48, 40, false, false, true, true, false, true, true);
+ for (int n = 0; n < 32; ++n) {
+ const uint64_t va_fill = 0x0000'0001'0000'0000ULL + (static_cast<uint64_t>(n) << 12);
+ const uint64_t ppn_fill = 0x91000ULL + static_cast<uint64_t>(n);
+ do_refill(dut, sv48_vpn(va_fill), ppn_fill, 0, MODE_SV48, static_cast<uint16_t>(50 + n), false, false, true, true, false, true, true);
+ }
+ issue_load(dut, va15, 40, MODE_SV48);
+ check(dut->resp_hit == 0, "ReplacementPressure_OldestEvicted");
+
+ // 24) Newest refill remains accessible after pressure
+ const uint64_t va16 = 0x0000'0001'0001'F000ULL;
+ do_refill(dut, sv48_vpn(va16), 0xA001FULL, 0, MODE_SV48, 77, false, false, true, true, false, true, true);
+ issue_load(dut, va16, 77, MODE_SV48);
+ check(dut->resp_hit == 1, "ReplacementPressure_NewestEntryHits");
+
+ // 25) flush_vpn should invalidate Sv48 level-1 superpage for any VPN within same range
+ apply_flush_all(dut);
+ const uint64_t va17_base = 0x0000'0001'2340'0000ULL;
+ const uint64_t va17_same_superpage = 0x0000'0001'2341'2ABCULL;
+ const uint64_t va17_other_superpage = 0x0000'0001'2440'0555ULL;
+ do_refill(dut, sv48_vpn(va17_base), 0xB1000ULL, 1, MODE_SV48, 88, false, false, true, true, false, true, true);
+ do_refill(dut, sv48_vpn(va17_other_superpage), 0xB2000ULL, 1, MODE_SV48, 88, false, false, true, true, false, true, true);
+ apply_flush_vpn(dut, sv48_vpn(va17_same_superpage), MODE_SV48);
+ issue_load(dut, va17_base, 88, MODE_SV48);
+ check(dut->resp_hit == 0, "FlushVpn_Sv48L1_SameSuperpageInvalidated");
+ issue_load(dut, va17_other_superpage, 88, MODE_SV48);
+ check(dut->resp_hit == 1, "FlushVpn_Sv48L1_OtherSuperpagePreserved");
+
+ // 26) flush_vpn should invalidate Sv57 level-2 superpage with 18-bit VPN wildcard
+ apply_flush_all(dut);
+ const uint64_t va18_base = 0x0012'3456'7800'1000ULL;
+ const uint64_t va18_same_superpage = 0x0012'3456'7BFF'8FFFULL;
+ const uint64_t va18_other_superpage = 0x0012'345A'0000'2000ULL;
+ do_refill(dut, sv57_vpn(va18_base), 0xC1234ULL, 2, MODE_SV57, 99, false, false, true, true, false, true, true);
+ do_refill(dut, sv57_vpn(va18_other_superpage), 0xC5678ULL, 2, MODE_SV57, 99, false, false, true, true, false, true, true);
+ apply_flush_vpn(dut, sv57_vpn(va18_same_superpage), MODE_SV57);
+ issue_load(dut, va18_base, 99, MODE_SV57);
+ check(dut->resp_hit == 0, "FlushVpn_Sv57L2_SameSuperpageInvalidated");
+ issue_load(dut, va18_other_superpage, 99, MODE_SV57);
+ check(dut->resp_hit == 1, "FlushVpn_Sv57L2_OtherSuperpagePreserved");
+
+ // 27) flush_vpn with exact-page entry must not over-invalidate neighboring pages
+ apply_flush_all(dut);
+ const uint64_t va19_a = 0x0000'0000'9900'1000ULL;
+ const uint64_t va19_b = 0x0000'0000'9900'2000ULL;
+ do_refill(dut, sv48_vpn(va19_a), 0xD1000ULL, 0, MODE_SV48, 120, false, false, true, true, false, true, true);
+ do_refill(dut, sv48_vpn(va19_b), 0xD2000ULL, 0, MODE_SV48, 120, false, false, true, true, false, true, true);
+ apply_flush_vpn(dut, sv48_vpn(va19_a), MODE_SV48);
+ issue_load(dut, va19_a, 120, MODE_SV48);
+ check(dut->resp_hit == 0, "FlushVpn_Level0_OnlyTargetInvalidated");
+ issue_load(dut, va19_b, 120, MODE_SV48);
+ check(dut->resp_hit == 1, "FlushVpn_Level0_NeighborPreserved");
+
std::cout << "\n----------------------------------\n";
std::cout << "TLB tests passed: " << g_pass_count << "\n";
std::cout << "----------------------------------\n";