Merge pull request #64 from alexfru/master
Initial support for MIPS16e in virtualmips emulator
This commit is contained in:
@@ -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 $@
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user