Skip to content

Commit 7718dc1

Browse files
committed
Implement direct-mapped instruction cache
Extend the existing architecture to include a direct-mapped instruction cache that stores recently fetched instructions. Add related constants and macros for cache size and address fields.
1 parent 55af56c commit 7718dc1

File tree

2 files changed

+63
-8
lines changed

2 files changed

+63
-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 icache_invalidate_all(hart_t *vm)
185+
{
186+
memset(&vm->icache, 0, sizeof(vm->icache));
187+
}
188+
183189
/* virtual addressing */
184190

185191
void mmu_invalidate(hart_t *vm)
@@ -197,6 +203,7 @@ void mmu_invalidate(hart_t *vm)
197203
vm->cache_store[set].ways[way].n_pages = 0xFFFFFFFF;
198204
vm->cache_store[set].lru = 0; /* Reset LRU to way 0 */
199205
}
206+
icache_invalidate_all(vm);
200207
}
201208

202209
/* Invalidate MMU caches for a specific virtual address range.
@@ -361,11 +368,27 @@ static void mmu_fence(hart_t *vm, uint32_t insn UNUSED)
361368

362369
static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
363370
{
364-
uint32_t vpn = addr >> RV_PAGE_SHIFT;
365-
if (unlikely(vpn != vm->cache_fetch.n_pages)) {
371+
/* cache hit */
372+
uint32_t idx = (addr >> ICACHE_OFFSET_BITS) & ICACHE_INDEX_MASK;
373+
uint32_t tag = addr >> (ICACHE_OFFSET_BITS + ICACHE_INDEX_BITS);
374+
icache_block_t *blk = &vm->icache.block[idx];
375+
376+
if (likely(blk->valid && blk->tag == tag)) {
366377
#ifdef MMU_CACHE_STATS
367-
vm->cache_fetch.misses++;
378+
vm->cache_fetch.hits++;
368379
#endif
380+
uint32_t ofs = addr & ICACHE_BLOCK_MASK;
381+
*value = *(const uint32_t *) (blk->base + ofs);
382+
return;
383+
}
384+
385+
#ifdef MMU_CACHE_STATS
386+
vm->cache_fetch.misses++;
387+
#endif
388+
389+
/* cache miss, Continue using the original va->pa*/
390+
uint32_t vpn = addr >> RV_PAGE_SHIFT;
391+
if (unlikely(vpn != vm->cache_fetch.n_pages)) {
369392
mmu_translate(vm, &addr, (1 << 3), (1 << 6), false, RV_EXC_FETCH_FAULT,
370393
RV_EXC_FETCH_PFAULT);
371394
if (vm->error)
@@ -377,12 +400,14 @@ static void mmu_fetch(hart_t *vm, uint32_t addr, uint32_t *value)
377400
vm->cache_fetch.n_pages = vpn;
378401
vm->cache_fetch.page_addr = page_addr;
379402
}
380-
#ifdef MMU_CACHE_STATS
381-
else {
382-
vm->cache_fetch.hits++;
383-
}
384-
#endif
403+
385404
*value = vm->cache_fetch.page_addr[(addr >> 2) & MASK(RV_PAGE_SHIFT - 2)];
405+
406+
/* fill into the cache */
407+
uint32_t block_off = (addr & RV_PAGE_MASK) & ~ICACHE_BLOCK_MASK;
408+
blk->base = (const uint8_t *) vm->cache_fetch.page_addr + block_off;
409+
blk->tag = tag;
410+
blk->valid = true;
386411
}
387412

388413
static void mmu_load(hart_t *vm,

riscv.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,37 @@ typedef struct {
7575
typedef struct __hart_internal hart_t;
7676
typedef struct __vm_internel vm_t;
7777

78+
/* ICACHE_BLOCKS_SIZE: Size of one instruction-cache block (line).
79+
* ICACHE_BLOCKS: Number of blocks (lines) in the instruction cache.
80+
*
81+
* The cache address is decomposed into [ tag | index | offset ] fields:
82+
* - block-offset bits = log2(ICACHE_BLOCKS_SIZE)
83+
* - index bits = log2(ICACHE_BLOCKS)
84+
*/
85+
#define ICACHE_BLOCKS_SIZE 256
86+
#define ICACHE_BLOCKS 256
87+
#define ICACHE_OFFSET_BITS 8
88+
#define ICACHE_INDEX_BITS 8
89+
90+
/* For power-of-two sizes, (size - 1) sets all low bits to 1,
91+
* allowing fast extraction of an address.
92+
*/
93+
#define ICACHE_INDEX_MASK (ICACHE_BLOCKS - 1)
94+
#define ICACHE_BLOCK_MASK (ICACHE_BLOCKS_SIZE - 1)
95+
#define RV_PAGE_MASK (RV_PAGE_SIZE - 1)
96+
97+
typedef struct {
98+
uint32_t tag;
99+
const uint8_t *base;
100+
bool valid;
101+
} icache_block_t;
102+
103+
typedef struct {
104+
icache_block_t block[ICACHE_BLOCKS];
105+
} icache_t;
106+
78107
struct __hart_internal {
108+
icache_t icache;
79109
uint32_t x_regs[32];
80110

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

0 commit comments

Comments
 (0)