Skip to content

Commit 0e4f67b

Browse files
committed
Implement direct mapped cache for instruction fetch
Extend the existing architecture to cache the last fetched PC instruction, improving instruction fetch hit rate by approximately 2%. Also includes clang-format fixes for several expressions.
1 parent 8f0c958 commit 0e4f67b

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

riscv.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <stdio.h>
2+
#include <string.h>
23

34
#include "common.h"
45
#include "device.h"
@@ -180,6 +181,11 @@ static inline uint32_t read_rs2(const hart_t *vm, uint32_t insn)
180181
return vm->x_regs[decode_rs2(insn)];
181182
}
182183

184+
static inline void ic_invalidate_all(hart_t *vm)
185+
{
186+
memset(&vm->ic, 0, sizeof(vm->ic));
187+
}
188+
183189
/* virtual addressing */
184190

185191
void mmu_invalidate(hart_t *vm)
@@ -188,6 +194,7 @@ void mmu_invalidate(hart_t *vm)
188194
vm->cache_load[0].n_pages = 0xFFFFFFFF;
189195
vm->cache_load[1].n_pages = 0xFFFFFFFF;
190196
vm->cache_store.n_pages = 0xFFFFFFFF;
197+
ic_invalidate_all(vm);
191198
}
192199

193200
/* Pre-verify the root page table to minimize page table access during
@@ -301,11 +308,27 @@ static void mmu_fence(hart_t *vm, uint32_t insn UNUSED)
301308

302309
static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
303310
{
304-
uint32_t vpn = addr >> RV_PAGE_SHIFT;
305-
if (unlikely(vpn != vm->cache_fetch.n_pages)) {
311+
/* cache hit */
312+
uint32_t idx = (addr >> IC_SHIFT) & IC_INDEX_MASK;
313+
uint32_t tag = addr >> (IC_SHIFT + IC_INDEX_BITS);
314+
ic_block_t *blk = &vm->ic.block[idx];
315+
316+
if (likely(blk->valid && blk->tag == tag)) {
306317
#ifdef MMU_CACHE_STATS
307-
vm->cache_fetch.misses++;
318+
vm->cache_fetch.hits++;
308319
#endif
320+
uint32_t ofs = addr & IC_BLOCK_MASK;
321+
*value = *(const uint32_t *) (blk->base + ofs);
322+
return;
323+
}
324+
325+
#ifdef MMU_CACHE_STATS
326+
vm->cache_fetch.misses++;
327+
#endif
328+
329+
/* cache miss, Continue using the original va->pa*/
330+
uint32_t vpn = addr >> RV_PAGE_SHIFT;
331+
if (unlikely(vpn != vm->cache_fetch.n_pages)) {
309332
mmu_translate(vm, &addr, (1 << 3), (1 << 6), false, RV_EXC_FETCH_FAULT,
310333
RV_EXC_FETCH_PFAULT);
311334
if (vm->error)
@@ -317,12 +340,14 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
317340
vm->cache_fetch.n_pages = vpn;
318341
vm->cache_fetch.page_addr = page_addr;
319342
}
320-
#ifdef MMU_CACHE_STATS
321-
else {
322-
vm->cache_fetch.hits++;
323-
}
324-
#endif
343+
325344
*value = vm->cache_fetch.page_addr[(addr >> 2) & MASK(RV_PAGE_SHIFT - 2)];
345+
346+
/* fill into the cache */
347+
uint32_t block_off = (addr & RV_PAGE_MASK) & ~IC_BLOCK_MASK;
348+
blk->base = (const uint8_t *) vm->cache_fetch.page_addr + block_off;
349+
blk->tag = addr >> (IC_SHIFT + IC_INDEX_BITS);
350+
blk->valid = true;
326351
}
327352

328353
static void mmu_load(hart_t *vm,

riscv.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,26 @@ typedef struct {
6969
typedef struct __hart_internal hart_t;
7070
typedef struct __vm_internel vm_t;
7171

72+
#define IC_BLOCKS_SIZE 256
73+
#define IC_BLOCKS 256
74+
#define IC_SHIFT (__builtin_ctz((IC_BLOCKS_SIZE)))
75+
#define IC_INDEX_BITS (__builtin_ctz((IC_BLOCKS)))
76+
#define IC_INDEX_MASK (IC_BLOCKS - 1)
77+
#define IC_BLOCK_MASK (IC_BLOCKS_SIZE - 1)
78+
#define RV_PAGE_MASK (RV_PAGE_SIZE - 1)
79+
80+
typedef struct {
81+
uint32_t tag;
82+
const uint8_t *base;
83+
bool valid;
84+
} ic_block_t;
85+
86+
typedef struct {
87+
ic_block_t block[IC_BLOCKS];
88+
} ic_t;
89+
7290
struct __hart_internal {
91+
ic_t ic;
7392
uint32_t x_regs[32];
7493

7594
/* LR reservation virtual address. last bit is 1 if valid */

0 commit comments

Comments
 (0)