Skip to content

Commit d4d7c46

Browse files
committed
Implement Ziccid correctly and cleanly
The algorithm is as follows: - The ITLB maintains inclusion of the I$ - The same address cannot be in any hart's ITLB if it is in any hart's STLB, and vice versa The effect is that any word that can be stored-to cannot be in any I$. The old scheme (periodically flush I$) was hacky and didn't correctly respect the in-order fetch rule (i.e. fetches are in-order wrt. each other, and so they see ordered stores in order).
1 parent aee4555 commit d4d7c46

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

riscv/mmu.cc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,32 @@ void mmu_t::store_slow_path(reg_t original_addr, reg_t len, const uint8_t* bytes
384384
}
385385
}
386386

387+
void mmu_t::flush_icache_vpn(reg_t vpn)
388+
{
389+
for (size_t i = 0; i < ICACHE_ENTRIES; i++)
390+
if ((icache[i].tag >> PGSHIFT) == vpn)
391+
icache[i].tag = -1;
392+
}
393+
394+
void mmu_t::flush_stlb_paddr(reg_t paddr)
395+
{
396+
for (size_t i = 0; i < TLB_ENTRIES; i++)
397+
if (tlb_store[i].data.target_addr == paddr)
398+
tlb_store[i].tag = -1;
399+
}
400+
401+
void mmu_t::flush_itlb_paddr(reg_t paddr)
402+
{
403+
for (size_t i = 0; i < TLB_ENTRIES; i++) {
404+
if (tlb_insn[i].data.target_addr == paddr) {
405+
// Maintain inclusion of I$
406+
flush_icache_vpn(tlb_insn[i].tag & ~TLB_FLAGS);
407+
408+
tlb_insn[i].tag = -1;
409+
}
410+
}
411+
}
412+
387413
tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type)
388414
{
389415
reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES;
@@ -402,14 +428,31 @@ tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_
402428

403429
switch (type) {
404430
case FETCH:
431+
if (proc && proc->extension_enabled(EXT_ZICCID)) {
432+
// Maintain inclusion of I$
433+
if (tlb_insn[idx].tag != (reg_t)-1)
434+
flush_icache_vpn(tlb_insn[idx].tag & ~TLB_FLAGS);
435+
436+
// Maintain exclusion with all store TLBs
437+
for (auto [_, p2] : sim->get_harts())
438+
p2->mmu->flush_stlb_paddr(entry.target_addr);
439+
}
440+
405441
tlb_insn[idx].data = entry;
406442
tlb_insn[idx].tag = expected_tag | (check_triggers_fetch ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag;
407443
break;
408444
case LOAD:
409445
tlb_load[idx].data = entry;
410446
tlb_load[idx].tag = expected_tag | (check_triggers_load ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag;
411447
break;
448+
412449
case STORE:
450+
if (proc && proc->extension_enabled(EXT_ZICCID)) {
451+
// Maintain exclusion with all instruction TLBs
452+
for (auto [_, p2] : sim->get_harts())
453+
p2->mmu->flush_itlb_paddr(entry.target_addr);
454+
}
455+
413456
tlb_store[idx].data = entry;
414457
tlb_store[idx].tag = expected_tag | (check_triggers_store ? TLB_CHECK_TRIGGERS : 0) | trace_flag | mmio_flag;
415458
break;

riscv/mmu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,10 @@ class mmu_t
372372
}
373373

374374
void flush_tlb();
375+
void flush_itlb_paddr(reg_t paddr);
376+
void flush_stlb_paddr(reg_t paddr);
375377
void flush_icache();
378+
void flush_icache_vpn(reg_t vpn);
376379

377380
void register_memtracer(memtracer_t*);
378381

0 commit comments

Comments
 (0)