diff --git a/src/isa/mips32/diff-test.c b/src/isa/mips32/diff-test.c index 303f2119847298ffd162ac0cdeb3266487641462..b24f3c4bc6a5ea350fe77c0bebccebb699697572 100644 --- a/src/isa/mips32/diff-test.c +++ b/src/isa/mips32/diff-test.c @@ -5,6 +5,8 @@ void isa_difftest_syncregs() { ref_difftest_setregs(&cpu); } +#define check_reg(r) same = same && difftest_check_reg(str(r), pc, ref_r->r, cpu.r) + bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { bool same = true; if (memcmp(&cpu, ref_r, sizeof(cpu.gpr))) { @@ -14,7 +16,11 @@ bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { } same = false; } - same = same && difftest_check_reg("pc", pc, ref_r->pc, cpu.pc); + check_reg(pc); + check_reg(lo); + check_reg(hi); + check_reg(status); + return same; } diff --git a/src/isa/mips32/exec/all-instr.h b/src/isa/mips32/exec/all-instr.h index 09643edbe3056c1569c1bc14c2ec842165df9226..42aeec3497be1494d6db2bad5c3b9fa120e4188e 100644 --- a/src/isa/mips32/exec/all-instr.h +++ b/src/isa/mips32/exec/all-instr.h @@ -25,6 +25,8 @@ make_EHelper(lwr); make_EHelper(mfhi); make_EHelper(mflo); +make_EHelper(mthi); +make_EHelper(mtlo); make_EHelper(mul); make_EHelper(mult); make_EHelper(multu); @@ -44,3 +46,8 @@ make_EHelper(bgez); make_EHelper(inv); make_EHelper(nemu_trap); + +make_EHelper(syscall); +make_EHelper(eret); +make_EHelper(mfc0); +make_EHelper(mtc0); diff --git a/src/isa/mips32/exec/exec.c b/src/isa/mips32/exec/exec.c index 3133bb38b3430a9fa43428b9f1e33bf83bc9df4e..d506721a56993738e28516dc8d02ff35e3c1ecb6 100644 --- a/src/isa/mips32/exec/exec.c +++ b/src/isa/mips32/exec/exec.c @@ -3,8 +3,8 @@ static OpcodeEntry special_table [64] = { /* b000 */ IDEX(shift, sll), EMPTY, IDEX(shift, srl), IDEX(shift, sra), IDEX(R, sll), EMPTY, IDEX(R, srl), IDEX(R, sra), - /* b001 */ IDEX(R, jr), IDEX(R, jalr), IDEX(cmov, movz), IDEX(cmov, movn), EMPTY, EMPTY, EMPTY, EMPTY, - /* b010 */ IDEX(R, mfhi), EMPTY, IDEX(R, mflo), EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b001 */ IDEX(R, jr), IDEX(R, jalr), IDEX(cmov, movz), IDEX(cmov, movn), EX(syscall), EMPTY, EMPTY, EMPTY, + /* b010 */ IDEX(R, mfhi), IDEX(R, mthi), IDEX(R, mflo), IDEX(R, mtlo), EMPTY, EMPTY, EMPTY, EMPTY, /* b011 */ IDEX(R, mult), IDEX(R, multu), IDEX(R, div), IDEX(R, divu), EMPTY, EMPTY, EMPTY, EMPTY, /* b100 */ EMPTY, IDEX(R, add), EMPTY, IDEX(R, sub), IDEX(R, and), IDEX(R, or), IDEX(R, xor), IDEX(R, nor), /* b101 */ EMPTY, EMPTY, IDEX(R, slt), IDEX(R, sltu), EMPTY, EMPTY, EMPTY, EMPTY, @@ -42,10 +42,35 @@ static make_EHelper(regimm) { idex(eip, ®imm_table[decinfo.isa.instr.rt]); } +static OpcodeEntry cop0_table [16] = { + /* b00 */ IDEX(R, mfc0), EMPTY, EMPTY, EMPTY, IDEX(R, mtc0), EMPTY, EMPTY, EMPTY, + /* b01 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, +}; + +static OpcodeEntry cop0co_table [64] = { + /* b000 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b001 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b010 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b011 */ EX(eret), EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b100 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b101 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b110 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b111 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, +}; + +static make_EHelper(cop0) { + if (decinfo.isa.instr.rs & 0x10) { + idex(eip, &cop0co_table[decinfo.isa.instr.func]); + } + else { + idex(eip, &cop0_table[decinfo.isa.instr.rs]); + } +} + static OpcodeEntry opcode_table [64] = { /* b000 */ EX(special), EX(regimm), IDEX(J, j), IDEX(J, jal), IDEX(B, beq), IDEX(B, bne), IDEX(B, blez), IDEX(B, bgtz), /* b001 */ EMPTY, IDEX(I, add), IDEX(I, slt), IDEX(I, sltu), IDEX(IU, and), IDEX(IU, or), IDEX(IU, xor), IDEX(IU, lui), - /* b010 */ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + /* b010 */ EX(cop0), EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, /* b011 */ EMPTY, EMPTY, EMPTY, EMPTY, EX(special2), EMPTY, EMPTY, EMPTY, /* b100 */ IDEXW(ld, lds, 1), IDEXW(ld, lds, 2), IDEX(st, lwl), IDEXW(ld, ld, 4), IDEXW(ld, ld, 1), IDEXW(ld, ld, 2), IDEX(st, lwr), EMPTY, /* b101 */ IDEXW(st, st, 1), IDEXW(st, st, 2), IDEX(st, swl), IDEXW(st, st, 4), EMPTY, EMPTY, IDEX(st, swr), EMPTY, diff --git a/src/isa/mips32/exec/muldiv.c b/src/isa/mips32/exec/muldiv.c index 0a7640d643660ebf5b8a2c706b35148497943953..e5e263c5b42963487b77af6d21c9c547593b85ae 100644 --- a/src/isa/mips32/exec/muldiv.c +++ b/src/isa/mips32/exec/muldiv.c @@ -12,6 +12,18 @@ make_EHelper(mflo) { print_asm_template3(mflo); } +make_EHelper(mthi) { + rtl_mv(&cpu.hi, &id_src->val); + + print_asm_template2(mthi); +} + +make_EHelper(mtlo) { + rtl_mv(&cpu.lo, &id_src->val); + + print_asm_template2(mtlo); +} + make_EHelper(mul) { rtl_imul_lo(&s0, &id_src->val, &id_src2->val); rtl_sr(id_dest->reg, &s0, 4); diff --git a/src/isa/mips32/exec/system.c b/src/isa/mips32/exec/system.c new file mode 100644 index 0000000000000000000000000000000000000000..99b70516d2a6881a631e4e0be638e46a07b18fd6 --- /dev/null +++ b/src/isa/mips32/exec/system.c @@ -0,0 +1,61 @@ +#include "cpu/exec.h" + +void raise_intr(uint8_t, vaddr_t); +#define EX_SYSCALL 8 + +make_EHelper(syscall) { +#if defined(DIFF_TEST) + difftest_skip_ref(); +#endif + + raise_intr(EX_SYSCALL, cpu.pc); + + print_asm("syscall"); +} + +make_EHelper(eret) { +#if defined(DIFF_TEST) + difftest_skip_ref(); +#endif + + rtl_li(&s0, cpu.epc); + rtl_jr(&s0); + + print_asm("eret"); +} + +make_EHelper(mfc0) { +#if defined(DIFF_TEST) + difftest_skip_ref(); +#endif + + uint32_t val; + char *name; + switch (id_dest->reg) { + case 12: val = cpu.status; name = "status"; break; + case 13: val = cpu.cause; name = "cause"; break; + case 14: val = cpu.epc; name = "epc"; break; + default: assert(0); + } + + rtl_li(&s0, val); + rtl_sr(id_src2->reg, &s0, 4); + + print_asm("mfc0 %s, %s", id_src2->str, name); +} + +make_EHelper(mtc0) { +#if defined(DIFF_TEST) + difftest_skip_ref(); +#endif + + char *name; + switch (id_dest->reg) { + case 12: cpu.status = id_src2->val; name = "status"; break; + case 13: cpu.cause = id_src2->val; name = "cause"; break; + case 14: cpu.epc = id_src2->val; name = "epc"; break; + default: assert(0); + } + + print_asm("mtc0 %s, %s", id_src2->str, name); +} diff --git a/src/isa/mips32/include/isa/reg.h b/src/isa/mips32/include/isa/reg.h index 26a333908d86d9c3fd375dc964fd10f364e1a1d6..876d405d048d3dfe5a7ca4b894375431c79932e7 100644 --- a/src/isa/mips32/include/isa/reg.h +++ b/src/isa/mips32/include/isa/reg.h @@ -17,6 +17,7 @@ typedef struct { uint32_t badvaddr; uint32_t cause; vaddr_t pc; + uint32_t epc; bool INTR; } CPU_state; diff --git a/src/isa/mips32/intr.c b/src/isa/mips32/intr.c index 8828e32474d65ed824661d78ae374a471182e21b..44dc6817f17284b81d6ea4c8fe55af2af7b13d06 100644 --- a/src/isa/mips32/intr.c +++ b/src/isa/mips32/intr.c @@ -1,10 +1,16 @@ #include "cpu/rtl.h" //#include "isa/mmu.h" -void raise_intr(uint8_t NO, vaddr_t ret_addr) { +#define EX_ENTRY 0x180 + +void raise_intr(uint8_t NO, vaddr_t epc) { /* TODO: Trigger an interrupt/exception with ``NO''. * That is, use ``NO'' to index the IDT. */ //TODO(); + cpu.cause = NO << 2; + cpu.epc = epc; + + rtl_j(EX_ENTRY); }