实现中断与异常

This commit is contained in:
2025-04-18 19:18:49 +08:00
parent a096b91bc1
commit 38d433558d
11 changed files with 392 additions and 10 deletions

View File

@@ -67,19 +67,33 @@
void mem_w_write(riscv_t * riscv, uint32_t addr, uint32_t value) {
if (addr & 0x3) {
riscv->exc_code = 6;
riscv->mtval = addr;
return;
}
if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
mem_wr(addr) = value;
} else {
device_write(riscv, addr, value);
riscv->exc_code = 7;
riscv->mtval = addr;
}
}
void mem_wh_write(riscv_t* riscv, uint32_t addr, uint16_t value) {
if (addr & 0x1) {
riscv->exc_code = 6;
riscv->mtval = addr;
return;
}
if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
mem_wrh(addr) = value;
} else {
device_write(riscv, addr, value);
riscv->exc_code = 7;
riscv->mtval = addr;
}
}
@@ -88,17 +102,26 @@ void mem_wb_write(riscv_t* riscv, uint32_t addr, uint8_t value) {
mem_wrb(addr) = value;
} else {
device_write(riscv, addr, value);
riscv->exc_code = 7;
riscv->mtval = addr;
}
}
uint32_t mem_w_read(riscv_t* riscv, uint32_t addr) {
uint32_t ret = 0xaaaaaaaa;
if (addr & 0x3) {
riscv->exc_code = 4;
riscv->mtval = addr;
return ret;
}
if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
ret = mem_wr(addr);
} else if (addr>=riscv->rom_addr_base && addr<riscv->rom_addr_base+riscv->rom_size){
ret = rom_wr(addr);
} else {
device_read(riscv, addr, ret);
riscv->exc_code = 5;
riscv->mtval = addr;
}
return ret;
}
@@ -106,12 +129,19 @@ uint32_t mem_w_read(riscv_t* riscv, uint32_t addr) {
uint16_t mem_wh_read(riscv_t* riscv, uint32_t addr) {
uint16_t ret = 0xaaaa;
if (addr & 0x1) {
riscv->exc_code = 4;
riscv->mtval = addr;
return ret;
}
if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
ret = mem_wrh(addr);
} else if (addr>=riscv->rom_addr_base && addr<riscv->rom_addr_base+riscv->rom_size){
ret = rom_wrh(addr);
} else {
device_read(riscv, addr, ret);
riscv->exc_code = 5;
riscv->mtval = addr;
}
return ret;
}
@@ -125,6 +155,8 @@ uint8_t mem_wb_read(riscv_t* riscv, uint32_t addr) {
ret = rom_wrb(addr);
} else {
device_read(riscv, addr, ret);
riscv->exc_code = 5;
riscv->mtval = addr;
}
return ret;
}
@@ -302,8 +334,14 @@ void ins_lui(riscv_t* riscv, int imm, int rd) {
}
void ins_mret(riscv_t* riscv) {
riscv->pc = riscv->csrs[0x305];
printf("mret\n");
riscv->pc = riscv->mepc;
if (riscv->mstatus & MSTATUS_MPIE) {
riscv->mstatus &= ~MSTATUS_MPIE;
riscv->mstatus |= MSTATUS_MIE;
} else {
riscv->mstatus &= ~MSTATUS_MIE;
}
printf("mret: pc=%08x\n", riscv->pc);
}
void ins_or(riscv_t* riscv, int rs2, int rs1, int rd) {
@@ -467,6 +505,7 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
ins_bgeu(riscv, rs2, rs1, imm);
break;
default:
riscv->exc_code = 2;
break;
}
break;
@@ -490,6 +529,7 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
ins_lhu(riscv, rs1, imm, rd);
break;
default:
riscv->exc_code = 2;
break;
}
break;
@@ -506,6 +546,7 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
ins_sw(riscv, rs2, rs1, imm);
break;
default:
riscv->exc_code = 2;
break;
}
break;
@@ -544,6 +585,7 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
}
break;
default:
riscv->exc_code = 2;
break;
}
break;
@@ -583,6 +625,7 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
ins_and(riscv, rs2, rs1, rd);
break;
default:
riscv->exc_code = 2;
break;
}
break;
@@ -591,7 +634,15 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
switch (funct3)
{
case 0x0:
ins_ebreak(riscv);
if (imm == 1) {
ins_ebreak(riscv);
} else if (imm == 0) {
ins_ecall(riscv);
} else if (ins == 0x30200073) {
ins_mret(riscv);
} else{
riscv->exc_code = 2;
}
break;
case 0x1:
ins_csrrw(riscv, rs1, rd, imm);
@@ -613,12 +664,17 @@ int riscv_decode(riscv_t* riscv, uint32_t ins) {
ins_csrrci(riscv, rs1, rd, imm);
break;
default:
riscv->exc_code = 2;
break;
}
break;
default:
riscv->exc_code = 2;
break;
}
if (riscv->exc_code == 2) {
riscv->mtval = ins;
}
return 0;
}
@@ -645,15 +701,67 @@ int riscv_init(riscv_t* riscv, uint32_t* rom, uint32_t rom_addr_base, uint32_t r
return 0;
}
// 进入中断 is_interrupt=1 进入中断 is_interrupt=0 进入异常
// irq_num 中断号
int riscv_enter_trap(riscv_t* riscv, int is_interrupt, int irq_num) {
riscv->mepc = riscv->pc;
riscv->mcause = (is_interrupt << 31) | irq_num;
riscv->pc = riscv->mtvec;
// 禁用全局中断
if (riscv->mstatus & MSTATUS_MIE) {
riscv->mstatus &= ~MSTATUS_MIE;
riscv->mstatus |= MSTATUS_MPIE;
} else {
riscv->mstatus &= ~MSTATUS_MPIE;
}
return 0;
}
// 检测是否产生了中断
int riscv_irq_check(riscv_t* riscv) {
uint32_t tmp;
int irq_num = 0;
tmp = riscv->mip & (MIP_MSIP | MIP_MTIP | MIP_MEIP);
if (tmp) {
if (riscv->mstatus & MSTATUS_MIE) {
if ((riscv->mie & MIP_MSIP) && (tmp & MIP_MSIP)) {
irq_num = 3;
} else if ((riscv->mie & MIP_MTIP) && (tmp & MIP_MTIP)) {
irq_num = 7;
} else if ((riscv->mie & MIP_MEIP) && (tmp & MIP_MEIP)) {
irq_num = 11;
}
riscv->mtval = 0;
riscv_enter_trap(riscv, 1, irq_num);
if (irq_num>0) {
riscv->mip &= ~(1 << irq_num);
irq_num = 0;
}
}
}
return 0;
}
int riscv_run(riscv_t* riscv) {
int ret = 0;
uint32_t pc;
while (1) {
if(riscv->pc >= riscv->rom_addr_base + riscv->rom_size || riscv->pc < riscv->rom_addr_base){
printf("riscv run out of rom pc=%08x\n",riscv->pc);
if (riscv->pc == 0) {
break;
}
uint32_t instr = riscv->rom[(riscv->pc-riscv->rom_addr_base) >> 2];
if (riscv->pc >= riscv->rom_addr_base + riscv->rom_size || riscv->pc < riscv->rom_addr_base) {
// 指令访问失败
riscv->mtval = riscv->pc;
printf("riscv run out of rom pc=%08x\n",riscv->pc);
riscv_enter_trap(riscv, 0, 1);
printf("riscv run out of rom pc=%08x\n",riscv->pc);
}
if (riscv->pc & 0x3) {
// 指令地址未对齐
riscv->mtval = riscv->pc;
riscv_enter_trap(riscv, 0, 0);
}
uint32_t instr = riscv->rom[(riscv->pc - riscv->rom_addr_base) >> 2];
// printf("pc: %08x instr: %08x\n", riscv->pc, instr);
pc = riscv->pc;
ret = riscv_decode(riscv, instr);
@@ -662,10 +770,19 @@ int riscv_run(riscv_t* riscv) {
if (riscv->pc == pc) {
riscv->pc += 4;
}
if (riscv->exc_code > 0) {
riscv_enter_trap(riscv, 0, riscv->exc_code);
riscv->exc_code = 0;
}
riscv_irq_check(riscv);
// riscv_print(riscv);
if(ret){
break;
}
if (riscv->mscratch == 0xffffffff) {
printf("proactively terminate\n");
break;
}
}
printf("riscv run end\n");
return 0;