Skip to content

Commit fe2d95e

Browse files
committed
Fix victim cache fill logic
Previous implementation did not correctly place the evicted I-cache block into the victim cache, leaving all victim entries empty and thus never hit. This patch properly stores the replaced I-cache block into the victim cache before refill, allowing victim hits to function as intended. Measurement shows that the number of virtual-to-physical translations during instruction fetch (mmu_translate() calls) decreased by ~7%.
1 parent 724d8df commit fe2d95e

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

riscv.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,13 +333,16 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
333333
}
334334

335335
/* search the victim cache */
336+
uint32_t vcache_key = addr >> ICACHE_OFFSET_BITS;
336337
for (int i = 0; i < VCACHE_BLOCKS; i++) {
337338
victim_cache_block_t *vblk = &vm->icache.v_block[i];
338-
if (vblk->valid && vblk->tag == tag) {
339-
/* victim cache hit, block swap*/
339+
340+
/* victim cache hit, swap blocks */
341+
if (vblk->valid && vblk->tag == vcache_key) {
340342
icache_block_t tmp = *blk;
341343
*blk = *vblk;
342344
*vblk = tmp;
345+
blk->tag = tag;
343346

344347
uint32_t ofs = addr & ICACHE_BLOCK_MASK;
345348
*value = *(const uint32_t *) (blk->base + ofs);
@@ -351,7 +354,7 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
351354
vm->cache_fetch.misses++;
352355
#endif
353356

354-
/* cache miss, Continue using the original va->pa*/
357+
/* icache miss, Continue using the original va->pa*/
355358
uint32_t vpn = addr >> RV_PAGE_SHIFT;
356359
uint32_t index = __builtin_parity(vpn) & 0x1;
357360
if (unlikely(vpn != vm->cache_fetch[index].n_pages)) {
@@ -370,7 +373,16 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
370373
*value =
371374
vm->cache_fetch[index].page_addr[(addr >> 2) & MASK(RV_PAGE_SHIFT - 2)];
372375

373-
/* fill into the cache */
376+
/* Move the current icache block into the victim cache before replacement */
377+
if (blk->valid) {
378+
victim_cache_block_t *vblk = &vm->icache.v_block[vm->icache.v_next];
379+
*vblk = *blk;
380+
vblk->tag = (blk->tag << ICACHE_INDEX_BITS) | idx;
381+
vblk->valid = true;
382+
vm->icache.v_next = (vm->icache.v_next + 1) % VCACHE_BLOCKS;
383+
}
384+
385+
/* fill into the icache */
374386
uint32_t block_off = (addr & RV_PAGE_MASK) & ~ICACHE_BLOCK_MASK;
375387
blk->base = (const uint8_t *) vm->cache_fetch[index].page_addr + block_off;
376388
blk->tag = tag;

riscv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ typedef icache_block_t victim_cache_block_t;
119119
typedef struct {
120120
icache_block_t i_block[ICACHE_BLOCKS];
121121
victim_cache_block_t v_block[VCACHE_BLOCKS];
122+
uint32_t v_next;
122123
} icache_t;
123124

124125
struct __hart_internal {

0 commit comments

Comments
 (0)