From 328d4ef7537a98bab8f6891a0280cda9e03b0cee Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Tue, 7 Apr 2026 21:21:03 +0800 Subject: feat(tlb): enhance TLB functionality with ASID-targeted flush and additional test cases --- rv64cpu/CMakeLists.txt | 6 +++++ rv64cpu/rtl/core/mmu/tlb.sv | 2 +- rv64cpu/tb/unit/tb_tlb.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) (limited to 'rv64cpu') 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(n) << 12); + const uint64_t ppn_fill = 0x91000ULL + static_cast(n); + do_refill(dut, sv48_vpn(va_fill), ppn_fill, 0, MODE_SV48, static_cast(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"; -- cgit v1.2.3