891 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			891 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | ||
| #include "riscv.h"
 | ||
| #include "debug.h"
 | ||
| #include "stdio.h"
 | ||
| #include "stdlib.h"
 | ||
| #include "errno.h"
 | ||
| #include "string.h"
 | ||
| 
 | ||
| // cpu外设
 | ||
| #include "print.h"
 | ||
| #include "timer.h"
 | ||
| 
 | ||
| #include "../main.h"
 | ||
| 
 | ||
| #define device_write(riscv,addr,value) \
 | ||
|   for (int i = 0;i < riscv->device_num;i++) {\
 | ||
|     if (riscv->device_list[i] && riscv->device_list[i]->write) {\
 | ||
|       if(addr>=riscv->device_list[i]->addr && addr<riscv->device_list[i]->addr+riscv->device_list[i]->size) {\
 | ||
|         riscv->device_list[i]->write(addr, value);\
 | ||
|         return;\
 | ||
|       }\
 | ||
|     }\
 | ||
|   }
 | ||
| 
 | ||
|   #define device_read(riscv,addr,ret) \
 | ||
|   for (int i = 0;i < riscv->device_num;i++) {\
 | ||
|     if (riscv->device_list[i] && riscv->device_list[i]->read) {\
 | ||
|       if(addr>=riscv->device_list[i]->addr && addr<riscv->device_list[i]->addr+riscv->device_list[i]->size) {\
 | ||
|         ret=riscv->device_list[i]->read(addr);\
 | ||
|         return ret;\
 | ||
|       }\
 | ||
|     }\
 | ||
|   }
 | ||
| 
 | ||
|   int riscv_print(riscv_t* riscv) {
 | ||
|     printf("x0(zero):  %08x\n", riscv->zero);
 | ||
|     printf("x1(ra):    %08x\n", riscv->ra);
 | ||
|     printf("x2(sp):    %08x\n", riscv->sp);
 | ||
|     printf("x3(gp):    %08x\n", riscv->gp);
 | ||
|     printf("x4(tp):    %08x\n", riscv->tp);
 | ||
|     printf("x5(t0):    %08x\n", riscv->t0);
 | ||
|     printf("x6(t1):    %08x\n", riscv->t1);
 | ||
|     printf("x7(t2):    %08x\n", riscv->t2);
 | ||
|     printf("x8(s0|fp): %08x\n", riscv->fp);
 | ||
|     printf("x9(s1):    %08x\n", riscv->s1);
 | ||
|     printf("x10(a0):   %08x\n", riscv->a0);
 | ||
|     printf("x11(a1):   %08x\n", riscv->a1);
 | ||
|     printf("x12(a2):   %08x\n", riscv->a2);
 | ||
|     printf("x13(a3):   %08x\n", riscv->a3);
 | ||
|     printf("x14(a4):   %08x\n", riscv->a4);
 | ||
|     printf("x15(a5):   %08x\n", riscv->a5);
 | ||
|     printf("x16(a6):   %08x\n", riscv->a6);
 | ||
|     printf("x17(a7):   %08x\n", riscv->a7);
 | ||
|     printf("x18(s2):   %08x\n", riscv->s2);
 | ||
|     printf("x19(s3):   %08x\n", riscv->s3);
 | ||
|     printf("x20(s4):   %08x\n", riscv->s4);
 | ||
|     printf("x21(s5):   %08x\n", riscv->s5);
 | ||
|     printf("x22(s6):   %08x\n", riscv->s6);
 | ||
|     printf("x23(s7):   %08x\n", riscv->s7);
 | ||
|     printf("x24(s8):   %08x\n", riscv->s8);
 | ||
|     printf("x25(s9):   %08x\n", riscv->s9);
 | ||
|     printf("x26(s10):  %08x\n", riscv->s10);
 | ||
|     printf("x27(s11):  %08x\n", riscv->s11);
 | ||
|     printf("x28(t3):   %08x\n", riscv->t3);
 | ||
|     printf("x29(t4):   %08x\n", riscv->t4);
 | ||
|     printf("x30(t5):   %08x\n", riscv->t5);
 | ||
|     printf("x31(t6):   %08x\n", riscv->t6);
 | ||
|     return 0;
 | ||
|   }
 | ||
| 
 | ||
| 
 | ||
| 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;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void mem_wb_write(riscv_t* riscv, uint32_t addr, uint8_t value) {
 | ||
|   if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
 | ||
|     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;
 | ||
|     printf("unaligned access addr:%08x\n", 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;
 | ||
|     printf("error addr:%08x\n", addr);
 | ||
|   }
 | ||
|   return ret;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 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;
 | ||
| }
 | ||
| 
 | ||
| uint8_t mem_wb_read(riscv_t* riscv, uint32_t addr) {
 | ||
|   uint8_t ret = 0xaa;
 | ||
|   // printf("read addr=%08x\n", addr);
 | ||
|   if (addr >= MEM_ADDR_BASE && addr < MEM_ADDR_BASE + MEM_SIZE) {
 | ||
|     ret = mem_wrb(addr);
 | ||
|   } else if (addr>=riscv->rom_addr_base && addr<riscv->rom_addr_base+riscv->rom_size){
 | ||
|     ret = rom_wrb(addr);
 | ||
|   } else {
 | ||
|     device_read(riscv, addr, ret);
 | ||
|     riscv->exc_code = 5;
 | ||
|     riscv->mtval = addr;
 | ||
|   }
 | ||
|   return ret;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| void ins_add(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] + riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_addi(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] + imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_addiw(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] + imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_addw(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] + riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_and(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] & riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_andi(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] & imm;
 | ||
| }
 | ||
| 
 | ||
| // 设置pc指针高位地址
 | ||
| void ins_auipc(riscv_t* riscv, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->pc + imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_beq(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   if (riscv->reg[rs1] == riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void ins_bge(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   if ((int)riscv->reg[rs1] >= (int)riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void ins_bgeu(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   if (riscv->reg[rs1] >= riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void ins_blt(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   if ((int)riscv->reg[rs1] < (int)riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void ins_bltu(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   if (riscv->reg[rs1] < riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void ins_bne(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   // printf("bne %d %d imm=%08x\n", rs2, rs1, imm);
 | ||
|   if (riscv->reg[rs1] != riscv->reg[rs2]) {
 | ||
|     riscv->pc += imm;
 | ||
|     riscv->pc_modify = 1;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 读后清除
 | ||
| void ins_csrrc(riscv_t* riscv, int rs1, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = riscv->csrs[csr] & ~riscv->reg[rs1];
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_csrrs(riscv_t* riscv, int rs1, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = riscv->csrs[csr] | riscv->reg[rs1];
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_csrrw(riscv_t* riscv, int rs1, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = riscv->reg[rs1];
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_csrrci(riscv_t* riscv, int imm, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = riscv->csrs[csr] & ~imm;
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_csrrsi(riscv_t* riscv, int imm, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = riscv->csrs[csr] | imm;
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_csrrwi(riscv_t* riscv, int imm, int rd, int csr) {
 | ||
|   uint32_t t = riscv->csrs[csr];
 | ||
|   riscv->csrs[csr] = imm;
 | ||
|   riscv->reg[rd] = t;
 | ||
| }
 | ||
| 
 | ||
| void ins_ecall(riscv_t* riscv) {
 | ||
|   printf("ecall\n");
 | ||
| }
 | ||
| 
 | ||
| void ins_ebreak(riscv_t* riscv) {
 | ||
|   printf("ebreak\n");
 | ||
| }
 | ||
| 
 | ||
| void ins_jal(riscv_t* riscv, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->pc + 4;
 | ||
|   riscv->pc += imm;
 | ||
|   riscv->pc_modify = 1;
 | ||
| }
 | ||
| 
 | ||
| void ins_jalr(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t t;
 | ||
|   t = riscv->pc + 4;
 | ||
|   riscv->pc = (riscv->reg[rs1] + imm) & (~1);
 | ||
|   riscv->reg[rd] = t;
 | ||
|   riscv->pc_modify = 1;
 | ||
| }
 | ||
| 
 | ||
| void ins_lb(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lb %08x,imm=%d\n",addr,imm);
 | ||
|   uint32_t r=mem_wb_read(riscv, addr);
 | ||
|   if(r&(0x80)){
 | ||
|     r|=0xffffff00;
 | ||
|   }
 | ||
|   riscv->reg[rd] = r;
 | ||
| }
 | ||
| 
 | ||
| void ins_lbu(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lbu %08x,imm=%d\n",addr,imm);
 | ||
|   riscv->reg[rd] = mem_wb_read(riscv, addr);
 | ||
| }
 | ||
| 
 | ||
| void ins_lh(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lh %08x,imm=%d\n",addr,imm);
 | ||
|   uint32_t r=mem_wh_read(riscv, addr);
 | ||
|   if(r&(0x8000)){
 | ||
|     r|=0xffff0000;
 | ||
|   }
 | ||
|   riscv->reg[rd] = r;
 | ||
| }
 | ||
| 
 | ||
| void ins_lhu(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lhu %08x,imm=%d\n",addr,imm);
 | ||
|   riscv->reg[rd] = mem_wh_read(riscv, addr);
 | ||
| }
 | ||
| 
 | ||
| void ins_lw(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lw %08x,imm=%d\n",addr,imm);
 | ||
|   riscv->reg[rd] = (int)mem_w_read(riscv, addr);
 | ||
| }
 | ||
| 
 | ||
| void ins_lwu(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("lwu %08x,imm=%d\n",addr,imm);
 | ||
|   riscv->reg[rd] = mem_w_read(riscv, addr);
 | ||
| }
 | ||
| 
 | ||
| void ins_lui(riscv_t* riscv, int imm, int rd) {
 | ||
|   riscv->reg[rd] = imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_mret(riscv_t* riscv) {
 | ||
|   riscv->pc = riscv->mepc;
 | ||
|   riscv->pc_modify = 1;
 | ||
|   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) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] | riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_ori(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] | imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sb(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("sb %08x,imm=%d\n",addr,imm);
 | ||
|   mem_wb_write(riscv, addr, riscv->reg[rs2]);
 | ||
| }
 | ||
| 
 | ||
| void ins_sh(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("sh %08x,imm=%d\n",addr,imm);
 | ||
|   mem_wh_write(riscv, addr, riscv->reg[rs2]);
 | ||
| }
 | ||
| 
 | ||
| void ins_sw(riscv_t* riscv, int rs2, int rs1, int imm) {
 | ||
|   uint32_t addr = riscv->reg[rs1] + imm;
 | ||
|   // printf("sw %08x,imm=%d\n",addr,imm);
 | ||
|   mem_w_write(riscv, addr, riscv->reg[rs2]);
 | ||
| }
 | ||
| 
 | ||
| void ins_sll(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] << riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_slli(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] << imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_slliw(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] << imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sllw(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] << riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_slt(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] < (int)riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_slti(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] < imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sltiu(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] < (uint32_t)imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sltu(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] < riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_sra(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] >> riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_srai(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] >> imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sraiw(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] >> imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_sraw(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = (int)riscv->reg[rs1] >> riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_srl(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] >> riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_srli(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] >> imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_srliw(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] >> imm;
 | ||
| }
 | ||
| 
 | ||
| void ins_srlw(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] >> riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_sub(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] - riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_subw(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] - riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_wfi(riscv_t* riscv) {
 | ||
|   printf("wfi\n");
 | ||
| }
 | ||
| 
 | ||
| void ins_xor(riscv_t* riscv, int rs2, int rs1, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] ^ riscv->reg[rs2];
 | ||
| }
 | ||
| 
 | ||
| void ins_xori(riscv_t* riscv, int rs1, int imm, int rd) {
 | ||
|   riscv->reg[rd] = riscv->reg[rs1] ^ imm;
 | ||
| }
 | ||
| 
 | ||
| // 解析指令
 | ||
| int riscv_decode(riscv_t* riscv, uint32_t ins) {
 | ||
|   int imm = 0;
 | ||
|   int rs1 = (ins >> 15) & 0x1f;
 | ||
|   int rs2 = (ins >> 20) & 0x1f;
 | ||
|   int rd = (ins >> 7) & 0x1f;
 | ||
|   int funct3 = (ins >> 12) & 0x7;
 | ||
|   int funct7 = (ins >> 25) & 0x7f;
 | ||
|   int opcode = ins & 0x7f;
 | ||
|   switch (opcode) {
 | ||
|     // U-type
 | ||
|   case opcode_lui:
 | ||
|     imm_u_type(ins, imm);
 | ||
|     ins_lui(riscv, imm, rd);
 | ||
|     break;
 | ||
|   case opcode_auipc:
 | ||
|     imm_u_type(ins, imm);
 | ||
|     ins_auipc(riscv, imm, rd);
 | ||
|     break;
 | ||
|     // J-type
 | ||
|   case opcode_jal:
 | ||
|     imm_j_type(ins, imm);
 | ||
|     ins_jal(riscv, imm, rd);
 | ||
|     break;
 | ||
|   case opcode_jalr:
 | ||
|     // I-type
 | ||
|     imm_i_type(ins, imm);
 | ||
|     ins_jalr(riscv, rs1, imm, rd);
 | ||
|     break;
 | ||
|   case opcode_beq:
 | ||
|     imm_b_type(ins, imm);
 | ||
|     switch(funct3) {
 | ||
|       case 0x0:
 | ||
|         ins_beq(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x1:
 | ||
|         ins_bne(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x4:
 | ||
|         ins_blt(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x5:
 | ||
|         ins_bge(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x6:
 | ||
|         ins_bltu(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x7:
 | ||
|         ins_bgeu(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       default:
 | ||
|         riscv->exc_code = 2;
 | ||
|         break;
 | ||
|     }
 | ||
|     break;
 | ||
|   case opcode_lb:
 | ||
|     imm_i_type(ins, imm);
 | ||
|     switch (funct3)
 | ||
|     {
 | ||
|     case 0x0:
 | ||
|       ins_lb(riscv, rs1, imm, rd);
 | ||
|       break;
 | ||
|     case 0x1:
 | ||
|       ins_lh(riscv, rs1, imm, rd);
 | ||
|       break;
 | ||
|     case 0x2:
 | ||
|       ins_lw(riscv, rs1, imm, rd);
 | ||
|       break;
 | ||
|     case 0x4:
 | ||
|       ins_lbu(riscv, rs1, imm, rd);
 | ||
|       break;
 | ||
|     case 0x5:
 | ||
|       ins_lhu(riscv, rs1, imm, rd);
 | ||
|       break;
 | ||
|     default:
 | ||
|       riscv->exc_code = 2;
 | ||
|       break;
 | ||
|     }
 | ||
|     break;
 | ||
|   case opcode_sb:
 | ||
|     imm_s_type(ins, imm);
 | ||
|     switch (funct3) {
 | ||
|       case 0x0:
 | ||
|         ins_sb(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x1:
 | ||
|         ins_sh(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       case 0x2:
 | ||
|         ins_sw(riscv, rs2, rs1, imm);
 | ||
|         break;
 | ||
|       default:
 | ||
|         riscv->exc_code = 2;
 | ||
|         break;
 | ||
|     }
 | ||
|     break;
 | ||
|   case opcode_addi:
 | ||
|     imm_i_type(ins,imm);
 | ||
|     switch (funct3)
 | ||
|     {
 | ||
|       case 0x0:
 | ||
|         ins_addi(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x2:
 | ||
|         ins_slti(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x3:
 | ||
|        ins_sltiu(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x4:
 | ||
|         ins_xori(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x6:
 | ||
|         ins_ori(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x7:
 | ||
|         ins_andi(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x1:
 | ||
|         imm = imm&0x1f;
 | ||
|         ins_slli(riscv, rs1, imm, rd);
 | ||
|         break;
 | ||
|       case 0x5:
 | ||
|         imm = imm&0x1f;
 | ||
|         if(funct7 == 0x20){
 | ||
|           ins_srai(riscv, rs1, imm, rd);
 | ||
|         }else{
 | ||
|           ins_srli(riscv, rs1, imm, rd);
 | ||
|         }
 | ||
|         break;
 | ||
|       default:
 | ||
|         riscv->exc_code = 2;
 | ||
|         break;
 | ||
|     }
 | ||
|     break;
 | ||
|   case opcode_add:
 | ||
|     switch (funct3)
 | ||
|     {
 | ||
|       case 0x0:
 | ||
|         if(funct7 == 0x20){
 | ||
|           ins_sub(riscv, rs2, rs1, rd);
 | ||
|         }else{
 | ||
|           ins_add(riscv, rs2, rs1, rd);
 | ||
|         }
 | ||
|         break;
 | ||
|       case 0x1:
 | ||
|         ins_sll(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       case 0x2:
 | ||
|         ins_slt(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       case 0x3:
 | ||
|         ins_sltu(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       case 0x4:
 | ||
|         ins_xor(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       case 0x5:
 | ||
|         if (funct7 == 0x20) {
 | ||
|           ins_sra(riscv, rs2, rs1, rd);
 | ||
|         }else{
 | ||
|           ins_srl(riscv, rs2, rs1, rd);
 | ||
|         }
 | ||
|         break;
 | ||
|       case 0x6:
 | ||
|         ins_or(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       case 0x7:
 | ||
|         ins_and(riscv, rs2, rs1, rd);
 | ||
|         break;
 | ||
|       default:
 | ||
|         riscv->exc_code = 2;
 | ||
|         break;
 | ||
|     }
 | ||
|     break;
 | ||
|     case opcode_ecall:
 | ||
|     imm_csr(ins,imm);
 | ||
|     switch (funct3)
 | ||
|     {
 | ||
|     case 0x0:
 | ||
|       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);
 | ||
|       break;
 | ||
|     case 0x2:
 | ||
|       ins_csrrs(riscv, rs1, rd, imm);
 | ||
|       break;
 | ||
|     case 0x3:
 | ||
|       ins_csrrc(riscv, rs1, rd, imm);
 | ||
|       break;
 | ||
|     case 0x5:
 | ||
|       // rs1 保存的是zimm 值
 | ||
|       ins_csrrwi(riscv, rs1, rd, imm);
 | ||
|       break;
 | ||
|     case 0x6:
 | ||
|       ins_csrrsi(riscv, rs1, rd, imm);
 | ||
|       break;
 | ||
|     case 0x7:
 | ||
|       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;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| // 注册外设
 | ||
| int riscv_register_device(riscv_t* riscv, const device_t* device) {
 | ||
|   if (riscv->device_num >= DEVICE_MAX_NUM) {
 | ||
|     printf("riscv register device failed, device num out of range\n");
 | ||
|     return -1;
 | ||
|   }
 | ||
|   // printf("device: base_addr=%08x, size=%08x\n", device->addr, device->size);
 | ||
|   riscv->device_list[riscv->device_num] = device;
 | ||
|   riscv->device_num++;
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| // 跑外设(执行外设逻辑,设置中断等)
 | ||
| int riscv_device_run(riscv_t* riscv) {
 | ||
|   for (int i = 0;i < riscv->device_num;i++) {
 | ||
|     if (riscv->device_list[i] && riscv->device_list[i]->run) {
 | ||
|       riscv->device_list[i]->run(riscv, riscv->device_list[i]);
 | ||
|     }
 | ||
|   }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| // 外设初始化
 | ||
| int riscv_device_init(riscv_t* riscv) {
 | ||
|   for (int i = 0;i < riscv->device_num;i++) {
 | ||
|     if (riscv->device_list[i] && riscv->device_list[i]->init) {
 | ||
|       riscv->device_list[i]->init(riscv->device_list[i]);
 | ||
|     }
 | ||
|   }
 | ||
|   return 0;
 | ||
| 
 | ||
| }
 | ||
| 
 | ||
| int riscv_init(riscv_t* riscv, uint32_t* rom, uint32_t rom_addr_base, uint32_t rom_size) {
 | ||
|   riscv->rom = rom;
 | ||
|   riscv->rom_size = rom_size;
 | ||
|   riscv->rom_addr_base = rom_addr_base;
 | ||
|   riscv->pc = riscv->rom_addr_base;
 | ||
|   riscv->pc_modify = 0;
 | ||
|   riscv->ra = 0xffffffff;
 | ||
|   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;
 | ||
|   riscv->pc_modify = 1;
 | ||
|   // 禁用全局中断
 | ||
|   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;
 | ||
|       if (irq_num>0) {
 | ||
|         riscv_enter_trap(riscv, 1, irq_num);
 | ||
|         riscv->mip &= ~(1 << irq_num);
 | ||
|         irq_num = 0;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| int riscv_run(riscv_t* riscv) {
 | ||
|   int ret = 0;
 | ||
|   while (1) {
 | ||
|     if (riscv->pc == 0xfffffffe && riscv->ra == 0xffffffff) {
 | ||
|       break;
 | ||
|     }
 | ||
|     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);
 | ||
|     }
 | ||
|     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);
 | ||
|     ret = riscv_decode(riscv, instr);
 | ||
|     riscv->zero = 0;
 | ||
|     // 如果指令修改了pc,则以修改后的为准,如果pc未被修改,则继续执行下一条指令
 | ||
|     if (!riscv->pc_modify) {
 | ||
|       riscv->pc += 4;
 | ||
|     } else {
 | ||
|       // printf("pc modify=1\n");
 | ||
|       riscv->pc_modify = 0;
 | ||
|     }
 | ||
|     if (riscv->exc_code > 0) {
 | ||
|       riscv_enter_trap(riscv, 0, riscv->exc_code);
 | ||
|       riscv->exc_code = 0;
 | ||
|     }
 | ||
|     riscv_device_run(riscv);
 | ||
|     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;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| long get_file_size(FILE *stream)
 | ||
| {
 | ||
| 	long file_size = -1;
 | ||
| 	long cur_offset = ftell(stream);	// 获取当前偏移位置
 | ||
| 	if (cur_offset == -1) {
 | ||
| 		printf("ftell failed :%s\n", strerror(errno));
 | ||
| 		return -1;
 | ||
| 	}
 | ||
| 	if (fseek(stream, 0, SEEK_END) != 0) {	// 移动文件指针到文件末尾
 | ||
| 		printf("fseek failed: %s\n", strerror(errno));
 | ||
| 		return -1;
 | ||
| 	}
 | ||
| 	file_size = ftell(stream);	// 获取此时偏移值,即文件大小
 | ||
| 	if (file_size == -1) {
 | ||
| 		printf("ftell failed :%s\n", strerror(errno));
 | ||
| 	}
 | ||
| 	if (fseek(stream, cur_offset, SEEK_SET) != 0) {	// 将文件指针恢复初始位置
 | ||
| 		printf("fseek failed: %s\n", strerror(errno));
 | ||
| 		return -1;
 | ||
| 	}
 | ||
| 	return file_size;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| riscv_t riscv = { 0 };
 | ||
| 
 | ||
| 
 | ||
| int thread_fun_r(void* t)
 | ||
| {
 | ||
|   int argc;
 | ||
|   char** argv;
 | ||
|   argc = get_argv(&argv);
 | ||
| 
 | ||
|   char *bin_name="riscv.bin";
 | ||
|   if(argc>1){
 | ||
|     bin_name=argv[1];
 | ||
|   }
 | ||
| 
 | ||
|   printf("riscv start\n");
 | ||
|   FILE *file=fopen(bin_name, "rb" );
 | ||
|   if(file==NULL)
 | ||
|   {
 | ||
|     printf("open file %s error\n",bin_name);
 | ||
|     return -1;
 | ||
|   }
 | ||
|   riscv.rom_size = get_file_size(file);
 | ||
|   printf("rom size: %d\n", riscv.rom_size);
 | ||
|   riscv.rom = calloc((riscv.rom_size + 3) / 4, 4);
 | ||
|   fread(riscv.rom, 1, riscv.rom_size, file);
 | ||
|   fclose(file);
 | ||
| 
 | ||
|   riscv_register_device(&riscv, print_dev());
 | ||
|   riscv_register_device(&riscv, timer_dev());
 | ||
|   riscv_init(&riscv, riscv.rom, 0x80000000, riscv.rom_size);
 | ||
|   riscv_device_init(&riscv);
 | ||
|   riscv_run(&riscv);
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 |