Skip to content

Commit 7796041

Browse files
committed
Add victim cache for I-cache
Introduce a small victim cache to reduce conflict misses in the direct-mapped instruction cache. On an I-cache miss, probe the victim cache; on hit, swap the victim block with the current I-cache block and return the data. Also rename ic.block → ic.i_block to distinguish between primary I-cache blocks and victim cache blocks.
1 parent 5478710 commit 7796041

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

riscv.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
321321
/* cache hit */
322322
uint32_t idx = (addr >> IC_OFFSET_BITS) & IC_INDEX_MASK;
323323
uint32_t tag = addr >> (IC_OFFSET_BITS + IC_INDEX_BITS);
324-
icache_block_t *blk = &vm->ic.block[idx];
324+
icache_block_t *blk = &vm->ic.i_block[idx];
325325

326326
if (likely(blk->valid && blk->tag == tag)) {
327327
#ifdef MMU_CACHE_STATS
@@ -332,6 +332,21 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
332332
return;
333333
}
334334

335+
/* search the victim cache */
336+
for (int i = 0; i < VC_BLOCKS; i++) {
337+
victim_cache_block_t *vblk = &vm->ic.v_block[i];
338+
if (vblk->valid && vblk->tag == tag) {
339+
/* victim cache hit, block swap*/
340+
icache_block_t tmp = *blk;
341+
*blk = *vblk;
342+
*vblk = tmp;
343+
344+
uint32_t ofs = addr & IC_BLOCK_MASK;
345+
*value = *(const uint32_t *) (blk->base + ofs);
346+
return;
347+
}
348+
}
349+
335350
#ifdef MMU_CACHE_STATS
336351
vm->cache_fetch.misses++;
337352
#endif

riscv.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ typedef struct __vm_internel vm_t;
9191
#define IC_OFFSET_BITS (__builtin_ctz((IC_BLOCKS_SIZE)))
9292
#define IC_INDEX_BITS (__builtin_ctz((IC_BLOCKS)))
9393

94+
/* Define the victim cache.
95+
*
96+
* The block size of the victim cache is identical to that of the primary
97+
* instruction cache (IC), ensuring full block compatibility.
98+
* However, the number of blocks is smaller, allowing the VC to store
99+
* a few recently evicted cache lines to reduce conflict misses.
100+
*/
101+
#define VC_BLOCK_SIZE IC_BLOCKS_SIZE
102+
#define VC_BLOCKS 16
103+
94104
/* For power-of-two sizes, (size - 1) sets all low bits to 1,
95105
* allowing fast extraction of an address.
96106
*/
@@ -104,8 +114,11 @@ typedef struct {
104114
bool valid;
105115
} icache_block_t;
106116

117+
typedef icache_block_t victim_cache_block_t;
118+
107119
typedef struct {
108-
icache_block_t block[IC_BLOCKS];
120+
icache_block_t i_block[IC_BLOCKS];
121+
victim_cache_block_t v_block[VC_BLOCKS];
109122
} icache_t;
110123

111124
struct __hart_internal {

0 commit comments

Comments
 (0)