Skip to content

Commit 98114a7

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 98114a7

File tree

3 files changed

+80
-36
lines changed

3 files changed

+80
-36
lines changed

main.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ static inline sbi_ret_t handle_sbi_ecall_TIMER(hart_t *hart, int32_t fid)
342342
(((uint64_t) hart->x_regs[RV_R_A1]) << 32) |
343343
(uint64_t) (hart->x_regs[RV_R_A0]);
344344
hart->sip &= ~RV_INT_STI_BIT;
345-
return (sbi_ret_t){SBI_SUCCESS, 0};
345+
return (sbi_ret_t) {SBI_SUCCESS, 0};
346346
default:
347-
return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
347+
return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0};
348348
}
349349
}
350350

@@ -356,9 +356,9 @@ static inline sbi_ret_t handle_sbi_ecall_RST(hart_t *hart, int32_t fid)
356356
fprintf(stderr, "system reset: type=%u, reason=%u\n",
357357
hart->x_regs[RV_R_A0], hart->x_regs[RV_R_A1]);
358358
data->stopped = true;
359-
return (sbi_ret_t){SBI_SUCCESS, 0};
359+
return (sbi_ret_t) {SBI_SUCCESS, 0};
360360
default:
361-
return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
361+
return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0};
362362
}
363363
}
364364

@@ -378,13 +378,13 @@ static inline sbi_ret_t handle_sbi_ecall_HSM(hart_t *hart, int32_t fid)
378378
vm->hart[hartid]->x_regs[RV_R_A1] = opaque;
379379
vm->hart[hartid]->pc = start_addr;
380380
vm->hart[hartid]->s_mode = true;
381-
return (sbi_ret_t){SBI_SUCCESS, 0};
381+
return (sbi_ret_t) {SBI_SUCCESS, 0};
382382
case SBI_HSM__HART_STOP:
383383
hart->hsm_status = SBI_HSM_STATE_STOPPED;
384-
return (sbi_ret_t){SBI_SUCCESS, 0};
384+
return (sbi_ret_t) {SBI_SUCCESS, 0};
385385
case SBI_HSM__HART_GET_STATUS:
386386
hartid = hart->x_regs[RV_R_A0];
387-
return (sbi_ret_t){SBI_SUCCESS, vm->hart[hartid]->hsm_status};
387+
return (sbi_ret_t) {SBI_SUCCESS, vm->hart[hartid]->hsm_status};
388388
case SBI_HSM__HART_SUSPEND:
389389
suspend_type = hart->x_regs[RV_R_A0];
390390
resume_addr = hart->x_regs[RV_R_A1];
@@ -398,11 +398,11 @@ static inline sbi_ret_t handle_sbi_ecall_HSM(hart_t *hart, int32_t fid)
398398
hart->hsm_resume_pc = resume_addr;
399399
hart->hsm_resume_opaque = opaque;
400400
}
401-
return (sbi_ret_t){SBI_SUCCESS, 0};
401+
return (sbi_ret_t) {SBI_SUCCESS, 0};
402402
default:
403-
return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
403+
return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0};
404404
}
405-
return (sbi_ret_t){SBI_ERR_FAILED, 0};
405+
return (sbi_ret_t) {SBI_ERR_FAILED, 0};
406406
}
407407

408408
static inline sbi_ret_t handle_sbi_ecall_IPI(hart_t *hart, int32_t fid)
@@ -421,10 +421,10 @@ static inline sbi_ret_t handle_sbi_ecall_IPI(hart_t *hart, int32_t fid)
421421
data->sswi.ssip[i] = hart_mask & 1;
422422
}
423423

424-
return (sbi_ret_t){SBI_SUCCESS, 0};
424+
return (sbi_ret_t) {SBI_SUCCESS, 0};
425425
break;
426426
default:
427-
return (sbi_ret_t){SBI_ERR_FAILED, 0};
427+
return (sbi_ret_t) {SBI_ERR_FAILED, 0};
428428
}
429429
}
430430

@@ -439,7 +439,7 @@ static inline sbi_ret_t handle_sbi_ecall_RFENCE(hart_t *hart, int32_t fid)
439439
uint64_t hart_mask, hart_mask_base;
440440
switch (fid) {
441441
case 0:
442-
return (sbi_ret_t){SBI_SUCCESS, 0};
442+
return (sbi_ret_t) {SBI_SUCCESS, 0};
443443
case 1:
444444
hart_mask = (uint64_t) hart->x_regs[RV_R_A0];
445445
hart_mask_base = (uint64_t) hart->x_regs[RV_R_A1];
@@ -452,16 +452,16 @@ static inline sbi_ret_t handle_sbi_ecall_RFENCE(hart_t *hart, int32_t fid)
452452
mmu_invalidate(hart->vm->hart[i]);
453453
}
454454
}
455-
return (sbi_ret_t){SBI_SUCCESS, 0};
455+
return (sbi_ret_t) {SBI_SUCCESS, 0};
456456
case 2:
457457
case 3:
458458
case 4:
459459
case 5:
460460
case 6:
461461
case 7:
462-
return (sbi_ret_t){SBI_SUCCESS, 0};
462+
return (sbi_ret_t) {SBI_SUCCESS, 0};
463463
default:
464-
return (sbi_ret_t){SBI_ERR_FAILED, 0};
464+
return (sbi_ret_t) {SBI_ERR_FAILED, 0};
465465
}
466466
}
467467

@@ -473,26 +473,26 @@ static inline sbi_ret_t handle_sbi_ecall_BASE(hart_t *hart, int32_t fid)
473473
{
474474
switch (fid) {
475475
case SBI_BASE__GET_SBI_IMPL_ID:
476-
return (sbi_ret_t){SBI_SUCCESS, SBI_IMPL_ID};
476+
return (sbi_ret_t) {SBI_SUCCESS, SBI_IMPL_ID};
477477
case SBI_BASE__GET_SBI_IMPL_VERSION:
478-
return (sbi_ret_t){SBI_SUCCESS, SBI_IMPL_VERSION};
478+
return (sbi_ret_t) {SBI_SUCCESS, SBI_IMPL_VERSION};
479479
case SBI_BASE__GET_MVENDORID:
480-
return (sbi_ret_t){SBI_SUCCESS, RV_MVENDORID};
480+
return (sbi_ret_t) {SBI_SUCCESS, RV_MVENDORID};
481481
case SBI_BASE__GET_MARCHID:
482-
return (sbi_ret_t){SBI_SUCCESS, RV_MARCHID};
482+
return (sbi_ret_t) {SBI_SUCCESS, RV_MARCHID};
483483
case SBI_BASE__GET_MIMPID:
484-
return (sbi_ret_t){SBI_SUCCESS, RV_MIMPID};
484+
return (sbi_ret_t) {SBI_SUCCESS, RV_MIMPID};
485485
case SBI_BASE__GET_SBI_SPEC_VERSION:
486-
return (sbi_ret_t){SBI_SUCCESS, (2 << 24) | 0}; /* version 2.0 */
486+
return (sbi_ret_t) {SBI_SUCCESS, (2 << 24) | 0}; /* version 2.0 */
487487
case SBI_BASE__PROBE_EXTENSION: {
488488
int32_t eid = (int32_t) hart->x_regs[RV_R_A0];
489489
bool available = eid == SBI_EID_BASE || eid == SBI_EID_TIMER ||
490490
eid == SBI_EID_RST || eid == SBI_EID_HSM ||
491491
eid == SBI_EID_IPI || eid == SBI_EID_RFENCE;
492-
return (sbi_ret_t){SBI_SUCCESS, available};
492+
return (sbi_ret_t) {SBI_SUCCESS, available};
493493
}
494494
default:
495-
return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
495+
return (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0};
496496
}
497497
}
498498

@@ -522,7 +522,7 @@ static void handle_sbi_ecall(hart_t *hart)
522522
SBI_HANDLE(RFENCE);
523523
break;
524524
default:
525-
ret = (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0};
525+
ret = (sbi_ret_t) {SBI_ERR_NOT_SUPPORTED, 0};
526526
}
527527
hart->x_regs[RV_R_A0] = (uint32_t) ret.error;
528528
hart->x_regs[RV_R_A1] = (uint32_t) ret.value;
@@ -1037,8 +1037,8 @@ static int semu_run(emu_state_t *emu)
10371037
#else
10381038
/* Linux: poll on timerfd and UART */
10391039
struct pollfd pfds[2];
1040-
pfds[0] = (struct pollfd){wfi_timer_fd, POLLIN, 0};
1041-
pfds[1] = (struct pollfd){emu->uart.in_fd, POLLIN, 0};
1040+
pfds[0] = (struct pollfd) {wfi_timer_fd, POLLIN, 0};
1041+
pfds[1] = (struct pollfd) {emu->uart.in_fd, POLLIN, 0};
10421042
poll(pfds, 2, -1);
10431043

10441044
/* Consume timerfd event to prevent accumulation */
@@ -1220,7 +1220,7 @@ static int semu_run_debug(emu_state_t *emu)
12201220

12211221
emu->curr_cpuid = 0;
12221222
if (!gdbstub_init(&gdbstub, &gdbstub_ops,
1223-
(arch_info_t){
1223+
(arch_info_t) {
12241224
.smp = vm->n_hart,
12251225
.reg_num = 33,
12261226
.target_desc = TARGET_RV32,

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)