diff --git a/src/cmd/smlrc/Makefile b/src/cmd/smlrc/Makefile index 462ef61..119d50d 100644 --- a/src/cmd/smlrc/Makefile +++ b/src/cmd/smlrc/Makefile @@ -33,3 +33,4 @@ clean: rm -f *.o smlrc smlrc.dis smlrc.elf ### smlrc.o: smlrc.c cgmips.c + ${CC} ${CFLAGS} -mips16 smlrc.c -c -o $@ diff --git a/tools/virtualmips/mips.c b/tools/virtualmips/mips.c index bda5b34..595078c 100644 --- a/tools/virtualmips/mips.c +++ b/tools/virtualmips/mips.c @@ -436,7 +436,7 @@ void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot) /* we don't set EPC if EXL is set */ if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL)) { - cp0->reg[MIPS_CP0_EPC] = cpu->pc; + cp0->reg[MIPS_CP0_EPC] = cpu->pc | cpu->is_mips16e; /*Cause BD is not update. MIPS VOLUME V3 P65 */ cause &= ~MIPS_CP0_CAUSE_BD_SLOT; //clear bd if (bd_slot) @@ -446,6 +446,7 @@ void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot) } + cpu->is_mips16e = 0; cause &= ~MIPS_CP0_CAUSE_EXC_MASK; //clear exec-code cause |= (exc_code << 2); cp0->reg[MIPS_CP0_CAUSE] = cause; @@ -535,6 +536,8 @@ void fastcall mips_exec_eret (cpu_mips_t * cpu) /* We have to clear the LLbit */ cpu->ll_bit = 0; + cpu->is_mips16e = cpu->pc & 1; + cpu->pc &= 0xFFFFFFFE; } /* Execute BREAK instruction */ diff --git a/tools/virtualmips/mips.h b/tools/virtualmips/mips.h index 6397621..71f5784 100644 --- a/tools/virtualmips/mips.h +++ b/tools/virtualmips/mips.h @@ -427,6 +427,9 @@ struct cpu_mips { u_int addr_mode; int is_in_bdslot; + int insn_len; /* length of last fetched instruction in bytes */ + int is_mips16e; /* 1 if ISA Mode is MIPS16e, 0 if MIPS32 */ + int trace_syscall; /* Current exec page (non-JIT) info */ diff --git a/tools/virtualmips/mips_codetable.c b/tools/virtualmips/mips_codetable.c index e3599af..ff56607 100644 --- a/tools/virtualmips/mips_codetable.c +++ b/tools/virtualmips/mips_codetable.c @@ -610,6 +610,10 @@ static int div_op (cpu_mips_t * cpu, mips_insn_t insn) int rs = bits (insn, 21, 25); int rt = bits (insn, 16, 20); + if (cpu->gpr[rt] == 0 || + (cpu->gpr[rs] == 0x80000000 && cpu->gpr[rt] == 0xFFFFFFFF)) + return (0); + cpu->lo = (m_int32_t) cpu->gpr[rs] / (m_int32_t) cpu->gpr[rt]; cpu->hi = (m_int32_t) cpu->gpr[rs] % (m_int32_t) cpu->gpr[rt]; @@ -753,7 +757,7 @@ static int jal_op (cpu_mips_t * cpu, mips_insn_t insn) m_va_t new_pc; /* compute the new pc */ - new_pc = cpu->pc & ~((1 << 28) - 1); + new_pc = (cpu->pc + 4) & ~((1 << 28) - 1); new_pc |= instr_index << 2; /* set the return address (instruction after the delay slot) */ @@ -766,6 +770,27 @@ static int jal_op (cpu_mips_t * cpu, mips_insn_t insn) return (1); } +static int jalx_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + u_int instr_index = bits (insn, 0, 25); + m_va_t new_pc; + + /* compute the new pc */ + new_pc = (cpu->pc + 4) & ~((1 << 28) - 1); + new_pc |= instr_index << 2; + + /* set the return address (instruction after the delay slot) */ + cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8); + + int ins_res = mips_exec_bdslot (cpu); + if (likely (!ins_res)) { + cpu->is_mips16e = 1; + cpu->pc = new_pc; + } + + return (1); +} + static int jalr_op (cpu_mips_t * cpu, mips_insn_t insn) { int rs = bits (insn, 21, 25); @@ -779,8 +804,10 @@ static int jalr_op (cpu_mips_t * cpu, mips_insn_t insn) new_pc = cpu->gpr[rs]; int ins_res = mips_exec_bdslot (cpu); - if (likely (!ins_res)) - cpu->pc = new_pc; + if (likely (!ins_res)) { + cpu->is_mips16e = new_pc & 1; + cpu->pc = new_pc & 0xFFFFFFFE; + } return (1); } @@ -794,8 +821,10 @@ static int jr_op (cpu_mips_t * cpu, mips_insn_t insn) new_pc = cpu->gpr[rs]; int ins_res = mips_exec_bdslot (cpu); - if (likely (!ins_res)) - cpu->pc = new_pc; + if (likely (!ins_res)) { + cpu->is_mips16e = new_pc & 1; + cpu->pc = new_pc & 0xFFFFFFFE; + } return (1); } @@ -1775,7 +1804,7 @@ static const struct mips_op_desc mips_opcodes[] = { {"ldl", ldl_op, 0x1A}, {"ldr", ldr_op, 0x1B}, {"spec2", spec2_op, 0x1C}, /* indexed by FUNC field */ - {"undef", undef_op, 0x1D}, + {"jalx", jalx_op, 0x1D}, {"undef", undef_op, 0x1E}, {"spec3", spec3_op, 0x1F}, /* indexed by FUNC field */ {"lb", lb_op, 0x20}, @@ -2167,3 +2196,553 @@ static const struct mips_op_desc mips_tlb_opcodes[] = { {"?tlb", undef_tlb, 0x3e}, {"?tlb", undef_tlb, 0x3f}, }; + +static int mips_exec_mips16e(cpu_mips_t* cpu, mips_insn_t instr) +{ + mips_insn_t extend = instr >> 16; + const m_va_t pc = cpu->pc; + m_va_t nextPc = pc + cpu->insn_len; + int res = 0; + + instr &= 0xFFFF; + +#define xlat(r) ((r) | (((r) - 2) & 16)) +#define op (instr >> 11) +#define imm2 (instr & 0x3) // RRR/SHIFT-funct +#define imm3 (instr & 0x7) // MOV32R rz +#define imm4 (instr & 0xF) // SVRS framesize +#define simm4 (imm4 - ((instr & 0x8) << 1)) +#define imm5 (instr & 0x1F) // MOVR32 r32 +#define imm8 ((uint8_t)instr) +#define simm8 ((int8_t)instr) +#define imm11 (instr & 0x7FF) +#define simm11 (imm11 - ((instr & 0x400) << 1)) +#define imm15 (((extend & 0xF) << 11) | (extend & 0x7F0) | imm4) // EXT-RRI-A addiu +#define simm15 (imm15 - ((extend & 0x8) << 12)) +#define imm16 (((extend & 0x1F) << 11) | (extend & 0x7E0) | imm5) +#define simm16 ((int16_t)imm16) +#define imm26 (((extend & 0x1F) << 21) | ((extend & 0x3E0) << 11) | (uint16_t)instr) // jal(x) +#define rx ((instr >> 8) & 0x7) // funct/SVRS +#define ry ((instr >> 5) & 0x7) // RR-funct +#define rz ((instr >> 2) & 0x7) // sa +#define r32s ((instr & 0x18) | ((instr >> 5) & 0x7)) // MOV32R split/swapped r32 +#define sa5 ((extend >> 6) & 0x1F) // EXT-SHIFT +#define fmsz8 ((extend & 0xF0) | imm4) // EXT-SVRS +#define aregs (extend & 0xF) // EXT-SVRS +#define xsregs ((extend >> 8) & 0x7) // EXT-SVRS +#define code6 ((instr >> 5) & 0x3F) // break, sdbbp + + // TBD!!! better checks for invalid encodings + if ((extend >> 11) == 3) { + // jal(x) adr26<<2 (32-bit instruction; delay slot) + cpu->reg_set(cpu, MIPS_GPR_RA, nextPc + 3); // 2 for non-extended instruction in delay slot + 1 for ISA Mode + if (mips_exec_bdslot(cpu) == 0) { + nextPc = (nextPc & 0xF0000000) | (imm26 << 2); + cpu->pc = nextPc; + cpu->is_mips16e = (extend & 0x400) == 0; // jalx switches to MIPS32 + } + res = 1; + } else if (!extend) { + switch (op) { + case 0: // addiu[sp] rx, sp, imm8 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[MIPS_GPR_SP] + (imm8 << 2)); + break; + case 1: // addiu[pc] rx, pc, imm8 + cpu->reg_set(cpu, xlat(rx), (pc + (imm8 << 2)) & 0xFFFFFFFC); + break; + case 2: // b ofs11<<1 (no delay slot) + nextPc += simm11 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 4: // beqz rx, ofs8<<1 (no delay slot) + if (cpu->gpr[xlat(rx)] == 0) + nextPc += simm8 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 5: // bnez rx, ofs8<<1 (no delay slot) + if (cpu->gpr[xlat(rx)] != 0) + nextPc += simm8 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 6: // SHIFT + switch (imm2) { + case 0: // sll rx, ry, imm3 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(ry)] << (rz | ((rz - 1) & 8))); + break; + case 2: // srl rx, ry, imm3 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(ry)] >> (rz | ((rz - 1) & 8))); + break; + case 3: // sra rx, ry, imm3 + cpu->reg_set(cpu, xlat(rx), (int32_t)cpu->gpr[xlat(ry)] >> (rz | ((rz - 1) & 8))); + break; + default: + goto lInvalidInstruction; + } + break; + case 8: // addiu ry, rx, imm4 + cpu->reg_set(cpu, xlat(ry), cpu->gpr[xlat(rx)] + simm4); + break; + case 9: // addiu[8] rx, imm8 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] + simm8); + break; + case 10: // slti rx, imm8 + cpu->reg_set(cpu, MIPS_GPR_T8, (int32_t)cpu->gpr[xlat(rx)] < (int32_t)imm8); + break; + case 11: // sltiu rx, imm8 + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] < imm8); + break; + case 12: // I8 + switch (rx) { + case 0: // bteqz ofs8<<1 (no delay slot) + if (cpu->gpr[MIPS_GPR_T8] == 0) + nextPc += simm8 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 1: // btnez ofs8<<1 (no delay slot) + if (cpu->gpr[MIPS_GPR_T8] != 0) + nextPc += simm8 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 2: // sw[rasp] ra, ofs8<<2(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, MIPS_GPR_SP, imm8 << 2, MIPS_GPR_RA, FALSE); + break; + case 3: // ADJSP AKA addiu sp, imm8 + cpu->reg_set(cpu, MIPS_GPR_SP, cpu->gpr[MIPS_GPR_SP] + (simm8 << 3)); + break; + case 4: // SVRS + if (instr & 0x80) { // save + uint32_t temp = cpu->gpr[MIPS_GPR_SP]; + cpu->reg_set(cpu, MIPS_GPR_SP, cpu->gpr[MIPS_GPR_SP] - (imm4 ? imm4 * 8 : 128)); + if (instr & 0x40) // ra + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_RA, FALSE); + if (instr & 0x10) // s1 + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_S1, FALSE); + if (instr & 0x20) // s0 + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_S0, FALSE); + } else { // restore + uint32_t temp = cpu->gpr[MIPS_GPR_SP] + (imm4 ? imm4 * 8 : 128), temp2 = temp; + if (instr & 0x40) // ra + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_RA, TRUE); + if (instr & 0x10) // s1 + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_S1, TRUE); + if (instr & 0x20) // s0 + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_S0, TRUE); + cpu->reg_set(cpu, MIPS_GPR_SP, temp2); + } + break; + case 5: // move r32, rz (nop = move $0, $16) + cpu->reg_set(cpu, r32s, cpu->gpr[xlat(imm3)]); + cpu->gpr[0] = 0; + break; + case 7: // move ry, r32 + cpu->reg_set(cpu, xlat(ry), cpu->gpr[imm5]); + break; + default: + goto lInvalidInstruction; + } + break; + case 13: // li rx, imm8 + cpu->reg_set(cpu, xlat(rx), imm8); + break; + case 14: // cmpi rx, imm8 + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] ^ imm8); + break; + case 16: // lb ry, ofs5(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LB, xlat(rx), imm5, xlat(ry), TRUE); + break; + case 17: // lh ry, ofs5<<1(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LH, xlat(rx), imm5 << 1, xlat(ry), TRUE); + break; + case 18: // lw[sp] rx, ofs8<<2(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LW, MIPS_GPR_SP, imm8 << 2, xlat(rx), TRUE); + break; + case 19: // lw ry, ofs5<<2(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LW, xlat(rx), imm5 << 2, xlat(ry), TRUE); + break; + case 20: // lbu ry, ofs5(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LBU, xlat(rx), imm5, xlat(ry), TRUE); + break; + case 21: // lhu ry, ofs5<<1(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LHU, xlat(rx), imm5 << 1, xlat(ry), TRUE); + break; + case 22: // lw[pc] rx, ofs8<<2(pc) + res = mips_exec_memop(cpu, MIPS_MEMOP_LW, (pc + (imm8 << 2)) & 0xFFFFFFFC, xlat(rx), TRUE); + break; + case 24: // sb ry, ofs5(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SB, xlat(rx), imm5, xlat(ry), FALSE); + break; + case 25: // sh ry, ofs5<<1(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SH, xlat(rx), imm5 << 1, xlat(ry), FALSE); + break; + case 26: // sw[sp] rx, ofs8<<2(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, MIPS_GPR_SP, imm8 << 2, xlat(rx), FALSE); + break; + case 27: // sw ry, ofs5<<2(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, xlat(rx), imm5 << 2, xlat(ry), FALSE); + break; + case 28: // RRR + switch (imm2) { + case 1: // addu rz, rx, ry + cpu->reg_set(cpu, xlat(rz), cpu->gpr[xlat(rx)] + cpu->gpr[xlat(ry)]); + break; + case 3: // subu rz, rx, ry + cpu->reg_set(cpu, xlat(rz), cpu->gpr[xlat(rx)] - cpu->gpr[xlat(ry)]); + break; + default: + goto lInvalidInstruction; + } + break; + case 29: // RR + switch (imm5) { + case 0: // J(AL)R(C) + switch (ry) { + case 0: // jr rx (delay slot) + nextPc = cpu->gpr[xlat(rx)]; + if (mips_exec_bdslot(cpu) == 0) { + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + } + res = 1; + break; + case 1: // jr ra (delay slot) + nextPc = cpu->gpr[MIPS_GPR_RA]; + if (mips_exec_bdslot(cpu) == 0) { + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + } + res = 1; + break; + case 2: // jalr (delay slot) + cpu->reg_set(cpu, MIPS_GPR_RA, nextPc + 3); // 2 for non-extended instruction in delay slot + 1 for ISA Mode + nextPc = cpu->gpr[xlat(rx)]; + if (mips_exec_bdslot(cpu) == 0) { + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + } + res = 1; + break; + case 4: // jrc rx (no delay slot) + nextPc = cpu->gpr[xlat(rx)]; + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + res = 1; + break; + case 5: // jrc ra (no delay slot) + nextPc = cpu->gpr[MIPS_GPR_RA]; + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + res = 1; + break; + case 6: // jalrc (no delay slot) + cpu->reg_set(cpu, MIPS_GPR_RA, nextPc + 1); // 1 for ISA Mode + nextPc = cpu->gpr[xlat(rx)]; + cpu->pc = nextPc & 0xFFFFFFFE; + cpu->is_mips16e = nextPc & 1; // may switch to MIPS32 + res = 1; + break; + default: + goto lInvalidInstruction; + } + break; + case 1: // sdbbp imm6 + goto lInvalidInstruction; + case 2: // slt rx, ry + cpu->reg_set(cpu, MIPS_GPR_T8, (int32_t)cpu->gpr[xlat(rx)] < (int32_t)cpu->gpr[xlat(ry)]); + break; + case 3: // sltu rx, ry + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] < cpu->gpr[xlat(ry)]); + break; + case 4: // sllv ry, rx + cpu->reg_set(cpu, xlat(ry), cpu->gpr[xlat(ry)] << (cpu->gpr[xlat(rx)] & 31)); + break; + case 5: // break imm6 + mips_exec_break(cpu, code6); + res = 1; + break; + case 6: // srlv ry, rx + cpu->reg_set(cpu, xlat(ry), cpu->gpr[xlat(ry)] >> (cpu->gpr[xlat(rx)] & 31)); + break; + case 7: // srav ry, rx + cpu->reg_set(cpu, xlat(ry), (int32_t)cpu->gpr[xlat(ry)] >> (cpu->gpr[xlat(rx)] & 31)); + break; + case 10: // cmp rx, ry + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] ^ cpu->gpr[xlat(ry)]); + break; + case 11: // neg rx, ry + cpu->reg_set(cpu, xlat(rx), -cpu->gpr[xlat(ry)]); + break; + case 12: // and rx, ry + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] & cpu->gpr[xlat(ry)]); + break; + case 13: // or rx, ry + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] | cpu->gpr[xlat(ry)]); + break; + case 14: // xor rx, ry + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] ^ cpu->gpr[xlat(ry)]); + break; + case 15: // not rx, ry + cpu->reg_set(cpu, xlat(rx), ~cpu->gpr[xlat(ry)]); + break; + case 16: // mfhi rx + cpu->reg_set(cpu, xlat(rx), cpu->hi); + break; + case 17: // CNVT + switch (ry) { + case 0: // zeb rx + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] & 0xFF); + break; + case 1: // zeh rx + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] & 0xFFFF); + break; + case 4: // seb rx + cpu->reg_set(cpu, xlat(rx), (int8_t)cpu->gpr[xlat(rx)]); + break; + case 5: // seh rx + cpu->reg_set(cpu, xlat(rx), (int16_t)cpu->gpr[xlat(rx)]); + break; + default: + goto lInvalidInstruction; + } + break; + case 18: // mflo rx + cpu->reg_set(cpu, xlat(rx), cpu->lo); + break; + case 24: { // mult rx, ry + int64_t p = (int64_t)(int32_t)cpu->gpr[xlat(rx)] * (int32_t)cpu->gpr[xlat(ry)]; + cpu->lo = (uint32_t)p; + cpu->hi = (uint32_t)(p >> 32); + } + break; + case 25: { // multu rx, ry + uint64_t p = (uint64_t)cpu->gpr[xlat(rx)] * cpu->gpr[xlat(ry)]; + cpu->lo = (uint32_t)p; + cpu->hi = (uint32_t)(p >> 32); + } + break; + case 26: // div rx, ry + if (!(cpu->gpr[xlat(ry)] == 0 || + (cpu->gpr[xlat(rx)] == 0x80000000 && cpu->gpr[xlat(ry)] == 0xFFFFFFFF))) { + cpu->lo = (int32_t)cpu->gpr[xlat(rx)] / (int32_t)cpu->gpr[xlat(ry)]; + cpu->hi = (int32_t)cpu->gpr[xlat(rx)] % (int32_t)cpu->gpr[xlat(ry)]; + } + break; + case 27: // divu rx, ry + if (cpu->gpr[xlat(ry)]) { + cpu->lo = cpu->gpr[xlat(rx)] / cpu->gpr[xlat(ry)]; + cpu->hi = cpu->gpr[xlat(rx)] % cpu->gpr[xlat(ry)]; + } + break; + default: + goto lInvalidInstruction; + } + break; + default: + goto lInvalidInstruction; + } + // ^^^ NON-EXTENDED ^^^ + } else { + // vvv EXTENDED vvv + switch (op) { + case 0: // addiu[sp] rx, sp, imm16 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[MIPS_GPR_SP] + simm16); + break; + case 1: // addiu[pc] rx, pc, imm16 + cpu->reg_set(cpu, xlat(rx), (pc & 0xFFFFFFFC) + simm16); + break; + case 2: // b ofs16<<1 (no delay slot) + nextPc += simm16 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 4: // beqz rx, ofs16<<1 (no delay slot) + if (cpu->gpr[xlat(rx)] == 0) + nextPc += simm16 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 5: // bnez rx, ofs16<<1 (no delay slot) + if (cpu->gpr[xlat(rx)] != 0) + nextPc += simm16 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 6: // SHIFT + switch (imm2) { + case 0: // sll rx, ry, imm5 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(ry)] << sa5); + break; + case 2: // srl rx, ry, imm5 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(ry)] >> sa5); + break; + case 3: // sra rx, ry, imm5 + cpu->reg_set(cpu, xlat(rx), (int32_t)cpu->gpr[xlat(ry)] >> sa5); + break; + default: + goto lInvalidInstruction; + } + break; + case 8: // addiu ry, rx, imm15 + cpu->reg_set(cpu, xlat(ry), cpu->gpr[xlat(rx)] + simm15); + break; + case 9: // addiu rx, imm16 + cpu->reg_set(cpu, xlat(rx), cpu->gpr[xlat(rx)] + simm16); + break; + case 10: // slti rx, imm16 + cpu->reg_set(cpu, MIPS_GPR_T8, (int32_t)cpu->gpr[xlat(rx)] < simm16); + break; + case 11: // sltiu rx, imm16 + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] < (uint32_t)simm16); + break; + case 12: // I8 + switch (rx) { + case 0: // bteqz ofs16<<1 (no delay slot) + if (cpu->gpr[MIPS_GPR_T8] == 0) + nextPc += simm16 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 1: // btnez ofs16<<1 (no delay slot) + if (cpu->gpr[MIPS_GPR_T8] != 0) + nextPc += simm16 << 1; + cpu->pc = nextPc; + res = 1; + break; + case 2: // sw[rasp] ra, ofs16(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, MIPS_GPR_SP, simm16, MIPS_GPR_RA, FALSE); + break; + case 3: // ADJSP AKA addiu sp, imm16 + cpu->reg_set(cpu, MIPS_GPR_SP, cpu->gpr[MIPS_GPR_SP] + simm16); + break; + case 4: { // SVRS + uint32_t astatic = 0; + uint32_t i, temp; + switch (aregs) { + case 1: case 5: case 9: case 13: astatic = 1; break; + case 2: case 6: case 10: astatic = 2; break; + case 3: case 7: astatic = 3; break; + case 11: astatic = 4; break; + } + if (instr & 0x80) { // save + uint32_t args = 0; + switch (aregs) { + case 4: case 5: case 6: case 7: args = 1; break; + case 8: case 9: case 10: args = 2; break; + case 12: case 13: args = 3; break; + case 14: args = 4; break; + } + temp = cpu->gpr[MIPS_GPR_SP]; + cpu->reg_set(cpu, MIPS_GPR_SP, cpu->gpr[MIPS_GPR_SP] - fmsz8 * 8); + for (i = 0; i < args; i++) + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp + i * 4, 4 + i, FALSE); + if (instr & 0x40) // ra + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_RA, FALSE); + for (i = xsregs; i; i--) + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, (i == 7) ? 30 : 17 + i, FALSE); + if (instr & 0x10) // s1 + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_S1, FALSE); + if (instr & 0x20) // s0 + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, MIPS_GPR_S0, FALSE); + for (i = 0; i < astatic; i++) + res |= mips_exec_memop(cpu, MIPS_MEMOP_SW, temp -= 4, 7 - i, FALSE); + } else { // restore + uint32_t temp2 = cpu->gpr[MIPS_GPR_SP] + fmsz8 * 8; + temp = temp2; + if (instr & 0x40) // ra + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_RA, TRUE); + for (i = xsregs; i; i--) + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, (i == 7) ? 30 : 17 + i, TRUE); + if (instr & 0x10) // s1 + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_S1, TRUE); + if (instr & 0x20) // s0 + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, MIPS_GPR_S0, TRUE); + for (i = 0; i < astatic; i++) + res |= mips_exec_memop(cpu, MIPS_MEMOP_LW, temp -= 4, 7 - i, TRUE); + cpu->reg_set(cpu, MIPS_GPR_SP, temp2); + } + } + break; + default: + goto lInvalidInstruction; + } + break; + case 13: // li rx, imm16 + cpu->reg_set(cpu, xlat(rx), imm16); + break; + case 14: // cmpi rx, imm16 + cpu->reg_set(cpu, MIPS_GPR_T8, cpu->gpr[xlat(rx)] ^ imm16); + break; + case 16: // lb ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LB, xlat(rx), simm16, xlat(ry), TRUE); + break; + case 17: // lh ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LH, xlat(rx), simm16, xlat(ry), TRUE); + break; + case 18: // lw[sp] rx, ofs16(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LW, MIPS_GPR_SP, simm16, xlat(rx), TRUE); + break; + case 19: // lw ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LW, xlat(rx), simm16, xlat(ry), TRUE); + break; + case 20: // lbu ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LBU, xlat(rx), simm16, xlat(ry), TRUE); + break; + case 21: // lhu ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_LHU, xlat(rx), simm16, xlat(ry), TRUE); + break; + case 22: // lw[pc] rx, ofs16(pc) + res = mips_exec_memop(cpu, MIPS_MEMOP_LW, (pc & 0xFFFFFFFC) + simm16, xlat(rx), TRUE); + break; + case 24: // sb ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SB, xlat(rx), simm16, xlat(ry), FALSE); + break; + case 25: // sh ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SH, xlat(rx), simm16, xlat(ry), FALSE); + break; + case 26: // sw[sp] rx, ofs16(sp) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, MIPS_GPR_SP, simm16, xlat(rx), FALSE); + break; + case 27: // sw ry, ofs16(rx) + res = mips_exec_memop2(cpu, MIPS_MEMOP_SW, xlat(rx), simm16, xlat(ry), FALSE); + break; + default: + goto lInvalidInstruction; + } + } + + return res; + +lInvalidInstruction: + unknown_op(cpu, (extend << 16) | instr); + return 1; +#undef xlat +#undef op +#undef imm2 +#undef imm3 +#undef imm4 +#undef simm4 +#undef imm5 +#undef imm8 +#undef simm8 +#undef imm11 +#undef simm11 +#undef imm15 +#undef simm15 +#undef imm16 +#undef simm16 +#undef imm26 +#undef rx +#undef ry +#undef rz +#undef r32s +#undef sa5 +#undef fmsz8 +#undef aregs +#undef xsregs +#undef code6 +} + diff --git a/tools/virtualmips/mips_fdd.c b/tools/virtualmips/mips_fdd.c index 9d312c1..39b80e1 100644 --- a/tools/virtualmips/mips_fdd.c +++ b/tools/virtualmips/mips_fdd.c @@ -39,6 +39,9 @@ static const struct mips_op_desc mips_spec2_opcodes[]; static const struct mips_op_desc mips_spec3_opcodes[]; static const struct mips_op_desc mips_tlb_opcodes[]; +static int mips_exec_mips16e (cpu_mips_t * cpu, + mips_insn_t instruction); + extern cpu_mips_t *current_cpu; /*for emulation performance check*/ @@ -56,11 +59,9 @@ static void forced_inline mips_main_loop_wait (cpu_mips_t * cpu, vp_get_clock (rt_clock)); } -/* Execute a memory operation (2) */ -static int forced_inline mips_exec_memop2 (cpu_mips_t * cpu, int memop, - m_va_t base, int offset, u_int dst_reg, int keep_ll_bit) +static int forced_inline mips_exec_memop (cpu_mips_t * cpu, int memop, + m_va_t vaddr, u_int dst_reg, int keep_ll_bit) { - m_va_t vaddr = cpu->gpr[base] + sign_extend (offset, 16); mips_memop_fn fn; if (!keep_ll_bit) @@ -69,8 +70,16 @@ static int forced_inline mips_exec_memop2 (cpu_mips_t * cpu, int memop, return (fn (cpu, vaddr, dst_reg)); } +/* Execute a memory operation (2) */ +static int forced_inline mips_exec_memop2 (cpu_mips_t * cpu, int memop, + u_int base_reg, int offset, u_int dst_reg, int keep_ll_bit) +{ + m_va_t vaddr = cpu->gpr[base_reg] + sign_extend (offset, 16); + return mips_exec_memop (cpu, memop, vaddr, dst_reg, keep_ll_bit); +} + /* Fetch an instruction */ -int mips_fetch_instruction (cpu_mips_t * cpu, +static int mips_fetch_instruction_word (cpu_mips_t * cpu, m_va_t pc, mips_insn_t * insn) { m_va_t exec_page; @@ -91,6 +100,42 @@ int mips_fetch_instruction (cpu_mips_t * cpu, return (0); } +int mips_fetch_instruction (cpu_mips_t * cpu, + m_va_t pc, mips_insn_t * insn) +{ + int res = mips_fetch_instruction_word(cpu, pc, insn); + cpu->insn_len = 4; + if (unlikely(res)) { + return res; + } + if (unlikely(cpu->is_mips16e)) { + mips_insn_t i; + if (pc & 2) { + i = *insn >> 16; + } else { + i = *insn & 0xFFFF; + } + if (unlikely((i >> 11) == 0x1E || (i >> 11) == 3)) { + /* 4-byte extended instruction or jal(x) */ + if (pc & 2) { + /* 2 more bytes needed */ + res = mips_fetch_instruction_word(cpu, pc + 2, insn); + if (unlikely(res)) { + return res; + } + *insn = (i << 16) | (*insn & 0xFFFF); + } else { + *insn = (*insn << 16) | (*insn >> 16); + } + } else { + /* 2-byte instruction */ + *insn = i; + cpu->insn_len = 2; + } + } + return res; +} + /* Execute a single instruction */ static forced_inline int mips_exec_single_instruction (cpu_mips_t * cpu, mips_insn_t instruction) @@ -111,9 +156,13 @@ static forced_inline int mips_exec_single_instruction (cpu_mips_t * cpu, exit (1); } #endif - register uint op; - op = MAJOR_OP (instruction); - return mips_opcodes[op].func (cpu, instruction); + if (unlikely(cpu->is_mips16e)) { + return mips_exec_mips16e (cpu, instruction); + } else { + register uint op; + op = MAJOR_OP (instruction); + return mips_opcodes[op].func (cpu, instruction); + } } /* Single-step execution */ @@ -121,11 +170,12 @@ void fastcall mips_exec_single_step (cpu_mips_t * cpu, mips_insn_t instruction) { int res; + int insn_len = cpu->insn_len; res = mips_exec_single_instruction (cpu, instruction); /* Normal flow ? */ if (likely (!res)) - cpu->pc += 4; + cpu->pc += insn_len; } void dumpregs (cpu_mips_t *cpu) @@ -164,6 +214,8 @@ void *mips_cpu_fdd (cpu_mips_t * cpu) start_cpu: for (;;) { + int insn_len; + if (unlikely (cpu->state != CPU_STATE_RUNNING)) break; @@ -182,6 +234,7 @@ start_cpu: } /* Fetch the instruction */ res = mips_fetch_instruction (cpu, cpu->pc, &insn); + insn_len = cpu->insn_len; if (cpu->vm->trace_address == cpu->pc) { /* Trace address. */ @@ -228,11 +281,12 @@ start_cpu: } #endif } + res = mips_exec_single_instruction (cpu, insn); /* Normal flow ? */ if (likely (!res)) - cpu->pc += sizeof (mips_insn_t); + cpu->pc += insn_len; } while (cpu->cpu_thread_running) { @@ -266,15 +320,18 @@ static forced_inline int mips_exec_bdslot (cpu_mips_t * cpu) { mips_insn_t insn; int res = 0; + int insn_len = cpu->insn_len; + cpu->is_in_bdslot = 1; /* Fetch the instruction in delay slot */ - res = mips_fetch_instruction (cpu, cpu->pc + 4, &insn); + res = mips_fetch_instruction (cpu, cpu->pc + insn_len, &insn); if (res == 1) { /*exception when fetching instruction */ cpu->is_in_bdslot = 0; return (1); } + cpu->is_in_bdslot = 1; if (cpu->vm->debug_level > 2 || (cpu->vm->debug_level > 1 && @@ -282,7 +339,7 @@ static forced_inline int mips_exec_bdslot (cpu_mips_t * cpu) ! (cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))) { /* Print instructions in user mode. */ - printf ("%08x: %08x ", cpu->pc + 4, insn); + printf ("%08x: %08x ", cpu->pc + insn_len, insn); print_insn_mips (cpu->pc, insn, stdout); printf ("\n"); fflush (stdout); @@ -290,6 +347,7 @@ static forced_inline int mips_exec_bdslot (cpu_mips_t * cpu) /* Execute the instruction */ res = mips_exec_single_instruction (cpu, insn); + cpu->is_in_bdslot = 0; return res; }