提交 3fd461b0 编写于 作者: Z Zihao Yu

riscv64: use global flag instead of longjmp to implement exceptions

* calling setjmp() at the beginning of exec() will reduce performance
上级 5c74c556
......@@ -22,6 +22,7 @@ typedef struct {
bool fetching;
bool amo;
int mem_exception;
// for LR/SC
vaddr_t lr_addr;
......
#include "../local-include/intr.h"
static inline make_EHelper(lr) {
rtl_lm(s, s0, dsrc1, s->width);
check_mem_ex();
rtl_sext(s, s0, s0, s->width);
rtl_sr(s, id_dest->reg, s0, 0);
......@@ -12,6 +15,7 @@ static inline make_EHelper(sc) {
// should check overlapping instead of equality
if (cpu.lr_addr == *dsrc1) {
rtl_sm(s, dsrc1, dsrc2, s->width);
check_mem_ex();
rtl_li(s, s0, 0);
} else {
rtl_li(s, s0, 1);
......@@ -28,47 +32,60 @@ static void inline amo_load(DecodeExecState *s) {
static void inline amo_update(DecodeExecState *s) {
rtl_sm(s, dsrc1, s1, s->width);
check_mem_ex();
rtl_sr(s, id_dest->reg, s0, 0);
}
static inline make_EHelper(amoswap) {
amo_load(s);
check_mem_ex();
rtl_mv(s, s1, dsrc2); // swap
amo_update(s);
check_mem_ex();
print_asm_template3(amoswap);
}
static inline make_EHelper(amoadd) {
amo_load(s);
check_mem_ex();
rtl_add(s, s1, s0, dsrc2);
amo_update(s);
check_mem_ex();
print_asm_template3(amoor);
}
static inline make_EHelper(amoor) {
amo_load(s);
check_mem_ex();
rtl_or(s, s1, s0, dsrc2);
amo_update(s);
check_mem_ex();
print_asm_template3(amoor);
}
static inline make_EHelper(amoand) {
amo_load(s);
check_mem_ex();
rtl_and(s, s1, s0, dsrc2);
amo_update(s);
check_mem_ex();
print_asm_template3(amoand);
}
static inline make_EHelper(amomaxu) {
amo_load(s);
check_mem_ex();
*s1 = (*s0 > *dsrc2 ? *s0 : *dsrc2);
amo_update(s);
check_mem_ex();
print_asm_template3(amomaxu);
}
static inline make_EHelper(amoxor) {
amo_load(s);
check_mem_ex();
rtl_xor(s, s1, s0, dsrc2);
amo_update(s);
check_mem_ex();
print_asm_template3(amoxor);
}
......@@ -2,7 +2,6 @@
#include "../local-include/decode.h"
#include "../local-include/intr.h"
#include "all-instr.h"
#include <setjmp.h>
#define decode_empty(s)
......@@ -109,7 +108,7 @@ static inline make_EHelper(atomic) {
}
static inline make_EHelper(fp) {
longjmp_raise_intr(EX_II);
raise_intr(s, EX_II, cpu.pc);
}
// RVC
......@@ -158,18 +157,14 @@ static inline make_EHelper(misc_alu) {
}
static inline void exec(DecodeExecState *s) {
extern jmp_buf intr_buf;
int setjmp_ret;
if ((setjmp_ret = setjmp(intr_buf)) != 0) {
int exception = setjmp_ret - 1;
raise_intr(s, exception, cpu.pc);
return;
}
cpu.fetching = true;
if ((s->seq_pc & 0xfff) == 0xffe) {
// instruction may accross page boundary
uint32_t lo = instr_fetch(&s->seq_pc, 2);
if (cpu.mem_exception != MEM_OK) {
cpu.fetching = false;
return;
}
s->isa.instr.val = lo & 0xffff;
if (s->isa.instr.r.opcode1_0 != 0x3) {
// this is an RVC instruction
......@@ -189,6 +184,8 @@ static inline void exec(DecodeExecState *s) {
}
cpu.fetching = false;
check_mem_ex();
if (s->isa.instr.r.opcode1_0 == 0x3) {
switch (s->isa.instr.r.opcode6_2) {
IDEX (000, ld, load) EX (001, fp) EX (003, fence)
......@@ -225,6 +222,10 @@ vaddr_t isa_exec_once() {
s.seq_pc = cpu.pc;
exec(&s);
if (cpu.mem_exception != MEM_OK) {
raise_intr(&s, cpu.mem_exception, cpu.pc);
cpu.mem_exception = MEM_OK;
}
update_pc(&s);
#if !defined(DIFF_TEST) && !_SHARE
......
#include "../local-include/intr.h"
static inline make_EHelper(ld) {
rtl_lm(s, s0, &id_src1->addr, s->width);
check_mem_ex();
rtl_sr(s, id_dest->reg, s0, 0);
switch (s->width) {
......@@ -14,6 +17,7 @@ static inline make_EHelper(ld) {
// load sign value
static inline make_EHelper(lds) {
rtl_lm(s, s0, &id_src1->addr, s->width);
check_mem_ex();
rtl_sext(s, s0, s0, s->width);
rtl_sr(s, id_dest->reg, s0, 0);
......@@ -27,6 +31,7 @@ static inline make_EHelper(lds) {
static inline make_EHelper(st) {
rtl_sm(s, &id_src1->addr, ddest, s->width);
check_mem_ex();
switch (s->width) {
case 8: print_asm_template2(sd); break;
......
#include <monitor/difftest.h>
#include "../local-include/csr.h"
static inline bool csr_check(DecodeExecState *s, uint32_t addr) {
switch (addr) {
case 0xc01: // time
case 0x001: // fflags
case 0x002: // frm
case 0x003: // fcsr
raise_intr(s, EX_II, cpu.pc);
return false;
}
return true;
}
static inline make_EHelper(csrrw) {
uint32_t addr = *dsrc2;
if (!csr_check(s, addr)) return;
csr_read(s0, addr);
rtl_sr(s, id_dest->reg, s0, 8);
csr_write(addr, dsrc1);
......@@ -12,6 +25,7 @@ static inline make_EHelper(csrrw) {
static inline make_EHelper(csrrs) {
uint32_t addr = *dsrc2;
if (!csr_check(s, addr)) return;
csr_read(s0, addr);
rtl_sr(s, id_dest->reg, s0, 8);
if (id_src1->reg != 0) {
......@@ -24,6 +38,7 @@ static inline make_EHelper(csrrs) {
static inline make_EHelper(csrrc) {
uint32_t addr = id_src2->val;
if (!csr_check(s, addr)) return;
csr_read(s0, addr);
rtl_sr(s, id_dest->reg, s0, 8);
if (id_src1->reg != 0) {
......
......@@ -3,7 +3,6 @@
#include "local-include/csr.h"
#include "local-include/rtl.h"
#include "local-include/intr.h"
#include <setjmp.h>
#define INTR_BIT (1ULL << 63)
enum {
......@@ -81,8 +80,3 @@ void query_intr(DecodeExecState *s) {
}
}
}
jmp_buf intr_buf;
void longjmp_raise_intr(uint32_t NO) {
longjmp(intr_buf, NO + 1);
}
......@@ -22,7 +22,12 @@ enum {
EX_SPF, // store/amo page fault
};
// now NEMU does not support EX_IAM,
// so it may ok to use EX_IAM to indicate a successful memory access
#define MEM_OK 0
void raise_intr(DecodeExecState *s, word_t NO, vaddr_t epc);
void longjmp_raise_intr(uint32_t);
#define check_mem_ex() do { if (cpu.mem_exception != MEM_OK) return; } while (0)
#endif
......@@ -35,7 +35,7 @@ static inline uintptr_t VPNi(vaddr_t va, int i) {
return (va >> VPNiSHFT(i)) & VPNMASK;
}
static inline void check_permission(PTE *pte, bool ok, vaddr_t vaddr, bool is_write) {
static inline bool check_permission(PTE *pte, bool ok, vaddr_t vaddr, bool is_write) {
uint32_t mode = (mstatus->mprv && !cpu.fetching ? mstatus->mpp : cpu.mode);
ok = ok && pte->v;
ok = ok && !(mode == MODE_U && !pte->u);
......@@ -44,31 +44,31 @@ static inline void check_permission(PTE *pte, bool ok, vaddr_t vaddr, bool is_wr
if (!(ok && pte->x)) {
assert(!cpu.amo);
stval->val = vaddr;
longjmp_raise_intr(EX_IPF);
cpu.mem_exception = EX_IPF;
return false;
}
} else if (!is_write) {
bool can_load = pte->r || (mstatus->mxr && pte->x);
if (!(ok && can_load)) {
if (cpu.mode == MODE_M) mtval->val = vaddr;
else stval->val = vaddr;
if (cpu.amo) {
cpu.amo = false;
Log("redirect to AMO page fault exception at pc = " FMT_WORD, cpu.pc);
longjmp_raise_intr(EX_SPF);
}
longjmp_raise_intr(EX_LPF);
if (cpu.amo) Log("redirect to AMO page fault exception at pc = " FMT_WORD, cpu.pc);
cpu.mem_exception = (cpu.amo ? EX_SPF : EX_LPF);
return false;
}
} else {
if (!(ok && pte->w)) {
if (cpu.amo) cpu.amo = false;
if (cpu.mode == MODE_M) mtval->val = vaddr;
else stval->val = vaddr;
longjmp_raise_intr(EX_SPF);
cpu.mem_exception = EX_SPF;
return false;
}
}
return true;
}
static word_t page_walk(vaddr_t vaddr, bool is_write) {
static bool page_walk(vaddr_t vaddr, paddr_t *paddr, bool is_write) {
word_t pg_base = PGBASE(satp->ppn);
word_t p_pte; // pte pointer
PTE pte;
......@@ -86,18 +86,18 @@ static word_t page_walk(vaddr_t vaddr, bool is_write) {
if (pte.r || pte.x) { break; }
else {
level --;
if (level < 0) { check_permission(&pte, false, vaddr, is_write); }
if (level < 0) { if (!check_permission(&pte, false, vaddr, is_write)) return false; }
}
}
check_permission(&pte, true, vaddr, is_write);
if (!check_permission(&pte, true, vaddr, is_write)) return false;
if (level > 0) {
// superpage
word_t pg_mask = ((1ull << VPNiSHFT(level)) - 1);
if ((pg_base & pg_mask) != 0) {
// missaligned superpage
check_permission(&pte, false, vaddr, is_write);
if (!check_permission(&pte, false, vaddr, is_write)) return false;
}
pg_base = (pg_base & ~pg_mask) | (vaddr & pg_mask & ~PGMASK);
}
......@@ -108,18 +108,22 @@ static word_t page_walk(vaddr_t vaddr, bool is_write) {
paddr_write(p_pte, pte.val, PTE_SIZE);
}
return pg_base;
*paddr = pg_base;
return true;
}
static inline paddr_t page_translate(vaddr_t addr, bool is_write) {
static inline bool page_translate(vaddr_t vaddr, paddr_t *paddr, bool is_write) {
uint32_t mode = (mstatus->mprv && !cpu.fetching ? mstatus->mpp : cpu.mode);
if (mode < MODE_M) {
assert(satp->mode == 0 || satp->mode == 8);
if (satp->mode == 8) {
return page_walk(addr, is_write) | (addr & PAGE_MASK);
if (!page_walk(vaddr, paddr, is_write)) return false;
*paddr |= (vaddr & PAGE_MASK);
return true;
}
}
return addr;
*paddr = vaddr;
return true;
}
/*
......@@ -173,23 +177,22 @@ uint_type(bits) concat(isa_vaddr_read, bits) (vaddr_t addr) { \
if (!cpu.fetching) { \
if ((addr & (bits / 8 - 1)) != 0) { \
mtval->val = addr; \
if (cpu.amo) { \
cpu.amo = false; \
longjmp_raise_intr(EX_SAM); \
} \
longjmp_raise_intr(EX_LAM); \
cpu.mem_exception = (cpu.amo ? EX_SAM : EX_LAM); \
return 0; \
} \
} \
paddr_t paddr = page_translate(addr, false); \
paddr_t paddr; \
if (!page_translate(addr, &paddr, false)) return 0; \
return concat(paddr_read, bits)(paddr); \
} \
void concat(isa_vaddr_write, bits) (vaddr_t addr, uint_type(bits) data) { \
if ((addr & (bits / 8 - 1)) != 0) { \
if (cpu.amo) cpu.amo = false; \
mtval->val = addr; \
longjmp_raise_intr(EX_SAM); \
cpu.mem_exception = EX_SAM; \
return; \
} \
paddr_t paddr = page_translate(addr, true); \
paddr_t paddr; \
if (!page_translate(addr, &paddr, true)) return; \
concat(paddr_write, bits)(paddr, data); \
}
......
......@@ -51,13 +51,6 @@ static bool csr_exist[4096] = {
static inline word_t* csr_decode(uint32_t addr) {
assert(addr < 4096);
switch (addr) {
case 0xc01: // time
case 0x001: // fflags
case 0x002: // frm
case 0x003: // fcsr
longjmp_raise_intr(EX_II);
}
Assert(csr_exist[addr], "unimplemented CSR 0x%x at pc = " FMT_WORD, addr, cpu.pc);
return &csr_array[addr];
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册