Skip to content

Commit a383578

Browse files
committed
Add simple LRU MMU cache
Simple MMU translation lookup cache using a ringbuffer.
1 parent cf5c213 commit a383578

File tree

3 files changed

+104
-11
lines changed

3 files changed

+104
-11
lines changed

mmu_cache.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
#include <string.h>
3+
/* This currently implements a simple, fixed-size LRU cache for MMU
4+
entries. Assumes that address 0 is never cached and it is used to
5+
flag empty entries. If a returned translation is zero, the calling
6+
logic has to assume that this means 'no entry available'. */
7+
8+
#define MMU_CACHE_ENTRIES 3
9+
#define MMU_CACHE_IDX_TYPE int
10+
#define MMU_CACHE_COUNTERS 0
11+
12+
struct _mmu_cache_ctx {
13+
MMU_CACHE_IDX_TYPE write_idx;
14+
uint32_t from[MMU_CACHE_ENTRIES];
15+
uint32_t to[MMU_CACHE_ENTRIES];
16+
#if MMU_CACHE_COUNTERS
17+
uint64_t hits, misses;
18+
#endif
19+
};
20+
21+
static inline void mmu_cache_reset_ctx(struct _mmu_cache_ctx* cc) {
22+
if (MMU_CACHE_ENTRIES) {
23+
cc->write_idx=0;
24+
for (size_t i=0; i != MMU_CACHE_ENTRIES; i++) {
25+
cc->from[i]=cc->to[i]=0;
26+
}
27+
}
28+
}
29+
30+
static inline uint32_t mmu_cache_lookup(struct _mmu_cache_ctx* cc,
31+
uint32_t high_part) {
32+
if (!MMU_CACHE_ENTRIES) {
33+
#if MMU_CACHE_COUNTERS
34+
cc->misses++;
35+
#endif
36+
return 0;
37+
}
38+
MMU_CACHE_IDX_TYPE i = cc->write_idx;
39+
do {
40+
if (cc->from[i] == high_part) {
41+
#if MMU_CACHE_COUNTERS
42+
cc->hits++;
43+
#endif
44+
return cc->to[i];
45+
}
46+
i--;
47+
if (i<0) i = MMU_CACHE_ENTRIES-1;
48+
} while(i != cc->write_idx);
49+
#if MMU_CACHE_COUNTERS
50+
cc->misses++;
51+
#endif
52+
return 0; // no entry available
53+
}
54+
55+
static inline void mmu_cache_insert(struct _mmu_cache_ctx* cc,
56+
uint32_t ifrom,
57+
uint32_t ito) {
58+
if (!MMU_CACHE_ENTRIES) return;
59+
MMU_CACHE_IDX_TYPE idx = cc->write_idx+1;
60+
if (idx == MMU_CACHE_ENTRIES)
61+
idx = 0;
62+
cc->write_idx = idx;
63+
cc->from[idx]=ifrom;
64+
cc->to[idx]=ito;
65+
}

riscv.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,19 @@ static inline uint32_t read_rs2(const vm_t *vm, uint32_t insn)
167167

168168
/* virtual addressing */
169169

170+
static void mmu_invalidate_caches(vm_t *vm) {
171+
mmu_cache_reset_ctx(&vm->mmu_cache_fetch_ctx);
172+
mmu_cache_reset_ctx(&vm->mmu_cache_load_ctx);
173+
mmu_cache_reset_ctx(&vm->mmu_cache_store_ctx);
174+
}
175+
176+
170177
/* Pre-verify the root page table to minimize page table access during
171178
* translation time.
172179
*/
173180
static void mmu_set(vm_t *vm, uint32_t satp)
174181
{
182+
mmu_invalidate_caches(vm);
175183
if (satp >> 31) {
176184
uint32_t *page_table = vm->mem_page_table(vm, satp & MASK(22));
177185
if (!page_table)
@@ -228,16 +236,25 @@ static bool mmu_lookup(const vm_t *vm,
228236
return true;
229237
}
230238

231-
static void mmu_translate(vm_t *vm,
232-
uint32_t *addr,
233-
const uint32_t access_bits,
234-
const uint32_t set_bits,
235-
const bool skip_privilege_test,
236-
const uint8_t fault,
237-
const uint8_t pfault)
239+
static inline void mmu_translate(vm_t *vm,
240+
struct _mmu_cache_ctx *cctx,
241+
uint32_t *addr,
242+
const uint32_t access_bits,
243+
const uint32_t set_bits,
244+
const bool skip_privilege_test,
245+
const uint8_t fault,
246+
const uint8_t pfault)
238247
{
248+
const uint32_t high_part = *addr & ~MASK(RV_PAGE_SHIFT);
249+
uint32_t caddr=mmu_cache_lookup(cctx, high_part);
250+
239251
/* NOTE: save virtual address, for physical accesses, to set exception. */
240252
vm->exc_val = *addr;
253+
254+
if (caddr) {
255+
*addr= caddr | (*addr & MASK(RV_PAGE_SHIFT));
256+
return;
257+
}
241258
if (!vm->page_table)
242259
return;
243260

@@ -265,16 +282,18 @@ static void mmu_translate(vm_t *vm,
265282
*pte_ref = new_pte;
266283

267284
*addr = ((*addr) & MASK(RV_PAGE_SHIFT)) | (ppn << RV_PAGE_SHIFT);
285+
mmu_cache_insert(cctx, high_part, ppn << RV_PAGE_SHIFT);
268286
}
269287

270288
static void mmu_fence(vm_t *vm UNUSED, uint32_t insn UNUSED)
271289
{
272-
/* no-op for now */
290+
mmu_invalidate_caches(vm);
273291
}
274292

275293
static void mmu_fetch(vm_t *vm, uint32_t addr, uint32_t *value)
276294
{
277-
mmu_translate(vm, &addr, (1 << 3), (1 << 6), false, RV_EXC_FETCH_FAULT,
295+
mmu_translate(vm, &vm->mmu_cache_fetch_ctx,
296+
&addr, (1 << 3), (1 << 6), false, RV_EXC_FETCH_FAULT,
278297
RV_EXC_FETCH_PFAULT);
279298
if (vm->error)
280299
return;
@@ -287,7 +306,8 @@ static void mmu_load(vm_t *vm,
287306
uint32_t *value,
288307
bool reserved)
289308
{
290-
mmu_translate(vm, &addr, (1 << 1) | (vm->sstatus_mxr ? (1 << 3) : 0),
309+
mmu_translate(vm, &vm->mmu_cache_load_ctx,
310+
&addr, (1 << 1) | (vm->sstatus_mxr ? (1 << 3) : 0),
291311
(1 << 6), vm->sstatus_sum && vm->s_mode, RV_EXC_LOAD_FAULT,
292312
RV_EXC_LOAD_PFAULT);
293313
if (vm->error)
@@ -306,7 +326,8 @@ static bool mmu_store(vm_t *vm,
306326
uint32_t value,
307327
bool cond)
308328
{
309-
mmu_translate(vm, &addr, (1 << 2), (1 << 6) | (1 << 7),
329+
mmu_translate(vm, &vm->mmu_cache_store_ctx,
330+
&addr, (1 << 2), (1 << 6) | (1 << 7),
310331
vm->sstatus_sum && vm->s_mode, RV_EXC_STORE_FAULT,
311332
RV_EXC_STORE_PFAULT);
312333
if (vm->error)
@@ -336,6 +357,8 @@ void vm_set_exception(vm_t *vm, uint32_t cause, uint32_t val)
336357

337358
void vm_trap(vm_t *vm)
338359
{
360+
mmu_invalidate_caches(vm);
361+
339362
/* Fill exception fields */
340363
vm->scause = vm->exc_cause;
341364
vm->stval = vm->exc_val;
@@ -357,6 +380,8 @@ void vm_trap(vm_t *vm)
357380

358381
static void op_sret(vm_t *vm)
359382
{
383+
mmu_invalidate_caches(vm);
384+
360385
/* Restore from stack */
361386
vm->pc = vm->sepc;
362387
vm->s_mode = vm->sstatus_spp;

riscv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <stdbool.h>
44
#include <stdint.h>
5+
#include "mmu_cache.h"
56

67
/* ERR_EXCEPTION indicates that the instruction has raised one of the
78
* exceptions defined in the specification. If this flag is set, the
@@ -96,6 +97,8 @@ struct __vm_internal {
9697
uint32_t satp; /**< MMU */
9798
uint32_t *page_table;
9899

100+
struct _mmu_cache_ctx mmu_cache_fetch_ctx, mmu_cache_load_ctx, mmu_cache_store_ctx;
101+
99102
void *priv; /**< environment supplied */
100103

101104
/* Memory access sets the vm->error to indicate failure. On successful

0 commit comments

Comments
 (0)