2870 lines
80 KiB
C
2870 lines
80 KiB
C
/*
|
|
* Code dispatch table.
|
|
*
|
|
* Copyright (C) yajin 2008 <yajinzhou@gmail.com >
|
|
*
|
|
* This file is part of the virtualmips distribution.
|
|
* See LICENSE file for terms of the license.
|
|
*/
|
|
|
|
static int unknown_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
printf ("--- Unknown instruction:\n");
|
|
printf ("%08x: %08x ", cpu->pc, insn);
|
|
print_mips (cpu->pc, insn, cpu->insn_len, cpu->is_mips16e, stdout);
|
|
printf ("\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
static int add_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_reg_t res;
|
|
|
|
/* TODO: Exception handling */
|
|
res = (m_uint32_t) cpu->gpr[rs] + (m_uint32_t) cpu->gpr[rt];
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int addi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
m_uint32_t res, val = sign_extend (imm, 16);
|
|
|
|
/* TODO: Exception handling */
|
|
res = (m_uint32_t) cpu->gpr[rs] + val;
|
|
cpu->reg_set (cpu, rt, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int addiu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
m_uint32_t res, val = sign_extend (imm, 16);
|
|
|
|
res = (m_uint32_t) cpu->gpr[rs] + val;
|
|
cpu->reg_set (cpu, rt, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int addu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_uint32_t res;
|
|
|
|
res = (m_uint32_t) cpu->gpr[rs] + (m_uint32_t) cpu->gpr[rt];
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int and_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
cpu->reg_set (cpu, rd, cpu->gpr[rs] & cpu->gpr[rt]);
|
|
return (0);
|
|
}
|
|
|
|
static int andi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
|
|
cpu->reg_set (cpu, rt, cpu->gpr[rs] & imm);
|
|
return (0);
|
|
}
|
|
|
|
static int bcond_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
uint16_t special_func = bits (insn, 16, 20);
|
|
return mips_bcond_opcodes[special_func].func (cpu, insn);
|
|
}
|
|
|
|
static int beq_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] == gpr[rt] */
|
|
res = (cpu->gpr[rs] == cpu->gpr[rt]);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
if (likely (!ins_res)) {
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int beql_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] == gpr[rt] */
|
|
res = (cpu->gpr[rs] == cpu->gpr[rt]);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
if (likely (!ins_res))
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int bgez_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] >= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] >= 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int bgezal_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* set the return address (instruction after the delay slot) */
|
|
cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8);
|
|
|
|
/* take the branch if gpr[rs] >= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] >= 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int bgezall_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* set the return address (instruction after the delay slot) */
|
|
cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8);
|
|
|
|
/* take the branch if gpr[rs] >= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] >= 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
static int bgezl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] >= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] >= 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
static int bgtz_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] > 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] > 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int bgtzl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] > 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] > 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int blez_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] <= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] <= 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int blezl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] <= 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] <= 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int bltz_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] < 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] < 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int bltzal_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* set the return address (instruction after the delay slot) */
|
|
cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8);
|
|
|
|
/* take the branch if gpr[rs] < 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] < 0);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
static int bltzall_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* set the return address (instruction after the delay slot) */
|
|
cpu->reg_set (cpu, MIPS_GPR_RA, cpu->pc + 8);
|
|
|
|
/* take the branch if gpr[rs] < 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] < 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int bltzl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] < 0 */
|
|
res = ((m_ireg_t) cpu->gpr[rs] < 0);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int bne_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] != gpr[rt] */
|
|
res = (cpu->gpr[rs] != cpu->gpr[rt]);
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
|
|
if (likely (!ins_res)) {
|
|
/* take the branch if the test result is true */
|
|
if (res)
|
|
cpu->pc = new_pc;
|
|
else
|
|
cpu->pc += 8;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int bnel_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
m_va_t new_pc;
|
|
int res;
|
|
|
|
/* compute the new pc */
|
|
new_pc = (cpu->pc + 4) + sign_extend (offset << 2, 18);
|
|
|
|
/* take the branch if gpr[rs] != gpr[rt] */
|
|
res = (cpu->gpr[rs] != cpu->gpr[rt]);
|
|
|
|
/* take the branch if the test result is true */
|
|
if (res) {
|
|
mips_exec_bdslot (cpu);
|
|
cpu->pc = new_pc;
|
|
} else
|
|
cpu->pc += 8;
|
|
return (1);
|
|
}
|
|
|
|
static int break_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
u_int code = bits (insn, 6, 25);
|
|
|
|
mips_exec_break (cpu, code);
|
|
return (1);
|
|
}
|
|
|
|
static int cache_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int op = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_CACHE, base, offset, op,
|
|
FALSE));
|
|
}
|
|
|
|
static int cfc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int clz_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rd = bits (insn, 11, 15);
|
|
int i;
|
|
m_uint32_t val;
|
|
val = 32;
|
|
for (i = 31; i >= 0; i--) {
|
|
if (cpu->gpr[rs] & (1 << i)) {
|
|
val = 31 - i;
|
|
break;
|
|
}
|
|
}
|
|
cpu->reg_set (cpu, rd, val);
|
|
return (0);
|
|
}
|
|
|
|
static int clo_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rd = bits (insn, 11, 15);
|
|
int i;
|
|
m_uint32_t val;
|
|
val = 32;
|
|
for (i = 31; i >= 0; i--) {
|
|
if (! (cpu->gpr[rs] & (1 << i))) {
|
|
val = 31 - i;
|
|
break;
|
|
}
|
|
}
|
|
cpu->reg_set (cpu, rd, val);
|
|
return (0);
|
|
}
|
|
|
|
static int cop0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
uint16_t special_func = bits (insn, 21, 25);
|
|
//printf ("cop0 instruction. func %x\n", special_func);
|
|
return mips_cop0_opcodes[special_func].func (cpu, insn);
|
|
}
|
|
|
|
static int cop1_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if SOFT_FPU
|
|
mips_exec_soft_fpu (cpu);
|
|
return (1);
|
|
#else
|
|
return unknown_op (cpu, insn);
|
|
#endif
|
|
}
|
|
|
|
static int cop1x_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if SOFT_FPU
|
|
mips_exec_soft_fpu (cpu);
|
|
return (1);
|
|
#else
|
|
return unknown_op (cpu, insn);
|
|
#endif
|
|
}
|
|
|
|
static int cop2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dadd_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int daddi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int daddiu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int daddu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ddiv_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ddivu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
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];
|
|
|
|
cpu->lo = sign_extend (cpu->lo, 32);
|
|
cpu->hi = sign_extend (cpu->hi, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int divu_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)
|
|
return (0);
|
|
|
|
cpu->lo = (m_uint32_t) cpu->gpr[rs] / (m_uint32_t) cpu->gpr[rt];
|
|
cpu->hi = (m_uint32_t) cpu->gpr[rs] % (m_uint32_t) cpu->gpr[rt];
|
|
|
|
cpu->lo = sign_extend (cpu->lo, 32);
|
|
cpu->hi = sign_extend (cpu->hi, 32);
|
|
return (0);
|
|
|
|
}
|
|
|
|
static int dmfc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dmtc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dmult_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dmultu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsll_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsllv_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsrlv_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsrav_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsub_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsubu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsrl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsra_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsll32_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsrl32_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int dsra32_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int eret_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if 1
|
|
if (cpu->trace_syscall &&
|
|
(cpu->cp0.reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_UM))
|
|
{
|
|
if (cpu->gpr[2] == 0xffffffff)
|
|
printf (" syscall failed, errno %u\n", cpu->gpr[8]);
|
|
else {
|
|
if (cpu->gpr[2] & ~0xffff)
|
|
printf (" syscall returned %08x\n", cpu->gpr[2]);
|
|
else
|
|
printf (" syscall returned %u\n", cpu->gpr[2]);
|
|
}
|
|
cpu->trace_syscall = 0;
|
|
}
|
|
#endif
|
|
mips_exec_eret (cpu);
|
|
return (1);
|
|
}
|
|
|
|
static int deret_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_exec_deret (cpu);
|
|
return (1);
|
|
}
|
|
|
|
static int j_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 & ~((1 << 28) - 1);
|
|
new_pc |= instr_index << 2;
|
|
|
|
/* exec the instruction in the delay slot */
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
if (likely (!ins_res))
|
|
cpu->pc = new_pc;
|
|
return (1);
|
|
}
|
|
|
|
static int jal_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->pc = new_pc;
|
|
|
|
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);
|
|
int rd = bits (insn, 11, 15);
|
|
m_va_t new_pc;
|
|
|
|
/* set the return pc (instruction after the delay slot) in GPR[rd] */
|
|
cpu->reg_set (cpu, rd, cpu->pc + 8);
|
|
|
|
/* get the new pc */
|
|
new_pc = cpu->gpr[rs];
|
|
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
if (likely (!ins_res)) {
|
|
cpu->is_mips16e = new_pc & 1;
|
|
cpu->pc = new_pc & 0xFFFFFFFE;
|
|
}
|
|
return (1);
|
|
|
|
}
|
|
|
|
static int jr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_va_t new_pc;
|
|
|
|
/* get the new pc */
|
|
new_pc = cpu->gpr[rs];
|
|
|
|
int ins_res = mips_exec_bdslot (cpu);
|
|
if (likely (!ins_res)) {
|
|
cpu->is_mips16e = new_pc & 1;
|
|
cpu->pc = new_pc & 0xFFFFFFFE;
|
|
}
|
|
return (1);
|
|
|
|
}
|
|
|
|
static int lb_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LB, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int lbu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LBU, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int ld_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ldc1_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ldc2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ldl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ldr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int lh_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LH, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int lhu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LHU, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int ll_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LL, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int lld_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int lui_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
|
|
cpu->reg_set (cpu, rt, sign_extend (imm, 16) << 16);
|
|
return (0);
|
|
}
|
|
|
|
static int lw_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LW, base, offset, rt, TRUE));
|
|
|
|
}
|
|
|
|
static int lwc1_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if SOFT_FPU
|
|
mips_exec_soft_fpu (cpu);
|
|
return (1);
|
|
#else
|
|
return unknown_op (cpu, insn);
|
|
#endif
|
|
|
|
}
|
|
|
|
static int lwc2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int lwl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWL, base, offset, rt, TRUE));
|
|
|
|
}
|
|
|
|
static int lwr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWR, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int lwu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_LWU, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int spec3_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int index = bits (insn, 0, 5);
|
|
return mips_spec3_opcodes[index].func (cpu, insn);
|
|
}
|
|
|
|
static int bshfl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sa = bits (insn, 6, 10);
|
|
//printf ("seh rt=%d, rd=%d, sa=%x\n", rt, rd, sa);
|
|
switch (sa) {
|
|
case 0x02:
|
|
/* wsbh - word swap bytes within halfwords */
|
|
cpu->reg_set (cpu, rd, bits (cpu->gpr[rt], 16, 23) << 24 |
|
|
bits (cpu->gpr[rt], 24, 31) << 16 |
|
|
bits (cpu->gpr[rt], 0, 7) << 8 |
|
|
bits (cpu->gpr[rt], 8, 15));
|
|
return (0);
|
|
case 0x10:
|
|
/* seb - sign extend byte */
|
|
cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rt], 8));
|
|
return (0);
|
|
case 0x18:
|
|
/* seh - sign extend halfword */
|
|
cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rt], 16));
|
|
return (0);
|
|
}
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int ext_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int msbd = bits (insn, 11, 15);
|
|
int lsb = bits (insn, 6, 10);
|
|
|
|
/* Extract bit field */
|
|
cpu->reg_set (cpu, rt, (cpu->gpr[rs] >> lsb) & (~0U >> (31 - msbd)));
|
|
return (0);
|
|
}
|
|
|
|
static int ins_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int msb = bits (insn, 11, 15);
|
|
int lsb = bits (insn, 6, 10);
|
|
|
|
/* Insert bit field */
|
|
int mask = ~0U >> (31-msb+lsb) << lsb;
|
|
cpu->gpr[rt] &= ~mask;
|
|
cpu->gpr[rt] |= (cpu->gpr[rs] << lsb) & mask;
|
|
return (0);
|
|
}
|
|
|
|
static int spec2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int index = bits (insn, 0, 5);
|
|
return mips_spec2_opcodes[index].func (cpu, insn);
|
|
}
|
|
|
|
static int madd_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val, temp;
|
|
|
|
val = (m_int32_t) (m_int32_t) cpu->gpr[rs];
|
|
val *= (m_int32_t) (m_int32_t) cpu->gpr[rt];
|
|
|
|
temp = cpu->hi;
|
|
temp = temp << 32;
|
|
temp += cpu->lo;
|
|
val += temp;
|
|
|
|
cpu->lo = sign_extend (val, 32);
|
|
cpu->hi = sign_extend (val >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int maddu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val, temp;
|
|
|
|
val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs];
|
|
val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt];
|
|
|
|
temp = cpu->hi;
|
|
temp = temp << 32;
|
|
temp += cpu->lo;
|
|
val += temp;
|
|
|
|
cpu->lo = sign_extend (val, 32);
|
|
cpu->hi = sign_extend (val >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int mfc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sel = bits (insn, 0, 2);
|
|
//mfc rt,rd
|
|
|
|
mips_cp0_exec_mfc0 (cpu, rt, rd, sel);
|
|
return (0);
|
|
}
|
|
|
|
static int mfhi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
if (rd)
|
|
cpu->reg_set (cpu, rd, cpu->hi);
|
|
return (0);
|
|
}
|
|
|
|
static int mflo_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
if (rd)
|
|
cpu->reg_set (cpu, rd, cpu->lo);
|
|
return (0);
|
|
}
|
|
|
|
static int movc_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int movz_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rd = bits (insn, 11, 15);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((cpu->gpr[rt]) == 0)
|
|
cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rs], 32));
|
|
return (0);
|
|
}
|
|
|
|
static int movn_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rd = bits (insn, 11, 15);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
// printf("pc %x rs %x rd %x rt %x\n",cpu->pc,rs,rd,rt);
|
|
if ((cpu->gpr[rt]) != 0)
|
|
cpu->reg_set (cpu, rd, sign_extend (cpu->gpr[rs], 32));
|
|
return (0);
|
|
}
|
|
|
|
static int msub_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val, temp;
|
|
|
|
val = (m_int32_t) (m_int32_t) cpu->gpr[rs];
|
|
val *= (m_int32_t) (m_int32_t) cpu->gpr[rt];
|
|
|
|
temp = cpu->hi;
|
|
temp = temp << 32;
|
|
temp += cpu->lo;
|
|
|
|
temp -= val;
|
|
//val += temp;
|
|
|
|
cpu->lo = sign_extend (temp, 32);
|
|
cpu->hi = sign_extend (temp >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int msubu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val, temp;
|
|
|
|
val = (m_uint32_t) (m_uint32_t) cpu->gpr[rs];
|
|
val *= (m_uint32_t) (m_uint32_t) cpu->gpr[rt];
|
|
|
|
temp = cpu->hi;
|
|
temp = temp << 32;
|
|
temp += cpu->lo;
|
|
|
|
temp -= val;
|
|
//val += temp;
|
|
|
|
cpu->lo = sign_extend (temp, 32);
|
|
cpu->hi = sign_extend (temp >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int mtc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sel = bits (insn, 0, 2);
|
|
|
|
//printf("cpu->pc %x insn %x\n",cpu->pc,insn);
|
|
mips_cp0_exec_mtc0 (cpu, rt, rd, sel);
|
|
return (0);
|
|
}
|
|
|
|
static int mthi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
|
|
cpu->hi = cpu->gpr[rs];
|
|
return (0);
|
|
}
|
|
|
|
static int mtlo_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
|
|
cpu->lo = cpu->gpr[rs];
|
|
return (0);
|
|
}
|
|
|
|
static int mul_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_int32_t val;
|
|
|
|
/* note: after this instruction, HI/LO regs are undefined */
|
|
val = (m_int32_t) cpu->gpr[rs] * (m_int32_t) cpu->gpr[rt];
|
|
cpu->reg_set (cpu, rd, sign_extend (val, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int mult_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val;
|
|
|
|
val = (m_int64_t) (m_int32_t) cpu->gpr[rs];
|
|
val *= (m_int64_t) (m_int32_t) cpu->gpr[rt];
|
|
|
|
cpu->lo = sign_extend (val, 32);
|
|
cpu->hi = sign_extend (val >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int multu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
m_int64_t val; //must be 64 bit. not m_reg_t !!!
|
|
|
|
val = (m_reg_t) (m_uint32_t) cpu->gpr[rs];
|
|
val *= (m_reg_t) (m_uint32_t) cpu->gpr[rt];
|
|
cpu->lo = sign_extend (val, 32);
|
|
cpu->hi = sign_extend (val >> 32, 32);
|
|
return (0);
|
|
}
|
|
|
|
static int nor_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
cpu->reg_set (cpu, rd, ~(cpu->gpr[rs] | cpu->gpr[rt]));
|
|
return (0);
|
|
}
|
|
|
|
static int or_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
cpu->reg_set (cpu, rd, cpu->gpr[rs] | cpu->gpr[rt]);
|
|
return (0);
|
|
}
|
|
|
|
static int ori_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
|
|
cpu->reg_set (cpu, rt, cpu->gpr[rs] | imm);
|
|
return (0);
|
|
}
|
|
|
|
static int pref_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int sb_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SB, base, offset, rt, FALSE));
|
|
}
|
|
|
|
static int sc_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SC, base, offset, rt, TRUE));
|
|
}
|
|
|
|
static int scd_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int sd_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int sdc1_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if SOFT_FPU
|
|
mips_exec_soft_fpu (cpu);
|
|
return (1);
|
|
#else
|
|
return unknown_op (cpu, insn);
|
|
#endif
|
|
}
|
|
|
|
static int sdc2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int sdl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int sdr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int sh_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SH, base, offset, rt, FALSE));
|
|
}
|
|
|
|
static int sll_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sa = bits (insn, 6, 10);
|
|
m_uint32_t res;
|
|
|
|
res = (m_uint32_t) cpu->gpr[rt] << sa;
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int sllv_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_uint32_t res;
|
|
|
|
res = (m_uint32_t) cpu->gpr[rt] << (cpu->gpr[rs] & 0x1f);
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int slt_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
if ((m_ireg_t) cpu->gpr[rs] < (m_ireg_t) cpu->gpr[rt])
|
|
cpu->reg_set (cpu, rd, 1);
|
|
else
|
|
cpu->reg_set (cpu, rd, 0);
|
|
return (0);
|
|
}
|
|
|
|
static int slti_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
m_ireg_t val = sign_extend (imm, 16);
|
|
|
|
if ((m_ireg_t) cpu->gpr[rs] < val)
|
|
cpu->reg_set (cpu, rt, 1);
|
|
else
|
|
cpu->reg_set (cpu, rt, 0);
|
|
return (0);
|
|
}
|
|
|
|
static int sltiu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
m_reg_t val = sign_extend (imm, 16);
|
|
|
|
if (rs == 0 && rt == 0 && cpu->magic_opcodes) {
|
|
if (imm == 0xabc1) {
|
|
printf ("%08x: Test FAIL\n", cpu->pc);
|
|
printf ("\n--- Stop simulation\n");
|
|
fprintf (stderr, "Test FAIL\n");
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
if (imm == 0xabc2) {
|
|
printf ("%08x: Test PASS\n", cpu->pc);
|
|
printf ("\n--- Stop simulation\n");
|
|
fprintf (stderr, "Test PASS\n");
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
}
|
|
|
|
if (cpu->gpr[rs] < val)
|
|
cpu->reg_set (cpu, rt, 1);
|
|
else
|
|
cpu->reg_set (cpu, rt, 0);
|
|
return (0);
|
|
}
|
|
|
|
static int sltu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
if (cpu->gpr[rs] < cpu->gpr[rt])
|
|
cpu->reg_set (cpu, rd, 1);
|
|
else
|
|
cpu->reg_set (cpu, rd, 0);
|
|
return (0);
|
|
}
|
|
|
|
static int spec_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
uint16_t special_func = bits (insn, 0, 5);
|
|
return mips_spec_opcodes[special_func].func (cpu, insn);
|
|
}
|
|
|
|
static int sra_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sa = bits (insn, 6, 10);
|
|
m_int32_t res;
|
|
|
|
res = (m_int32_t) cpu->gpr[rt] >> sa;
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int srav_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_int32_t res;
|
|
|
|
res = (m_int32_t) cpu->gpr[rt] >> (cpu->gpr[rs] & 0x1f);
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int srl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int sa = bits (insn, 6, 10);
|
|
m_uint32_t res;
|
|
|
|
/* srl */
|
|
res = (m_uint32_t) cpu->gpr[rt] >> sa;
|
|
if ((insn >> 21) & 1) {
|
|
/* rotr */
|
|
res |= (m_uint32_t) cpu->gpr[rt] << (32 - sa);
|
|
}
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int srlv_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_uint32_t res, sa;
|
|
|
|
/* srlv */
|
|
sa = cpu->gpr[rs] & 0x1f;
|
|
res = (m_uint32_t) cpu->gpr[rt] >> sa;
|
|
if ((insn >> 6) & 1) {
|
|
/* rotrv */
|
|
res |= (m_uint32_t) cpu->gpr[rt] << (32 - sa);
|
|
}
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int sub_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_uint32_t res;
|
|
|
|
/* TODO: Exception handling */
|
|
res = (m_uint32_t) cpu->gpr[rs] - (m_uint32_t) cpu->gpr[rt];
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int subu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
m_uint32_t res;
|
|
res = (m_uint32_t) cpu->gpr[rs] - (m_uint32_t) cpu->gpr[rt];
|
|
cpu->reg_set (cpu, rd, sign_extend (res, 32));
|
|
return (0);
|
|
}
|
|
|
|
static int sw_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SW, base, offset, rt, FALSE));
|
|
}
|
|
|
|
static int swc1_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
#if SOFT_FPU
|
|
mips_exec_soft_fpu (cpu);
|
|
return (1);
|
|
#else
|
|
return unknown_op (cpu, insn);
|
|
#endif
|
|
}
|
|
|
|
static int swc2_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int swl_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SWL, base, offset, rt,
|
|
FALSE));
|
|
}
|
|
|
|
static int swr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int base = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int offset = bits (insn, 0, 15);
|
|
|
|
return (mips_exec_memop2 (cpu, MIPS_MEMOP_SWR, base, offset, rt,
|
|
FALSE));
|
|
}
|
|
|
|
static int sync_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
static int syscall_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_exec_syscall (cpu);
|
|
return (1);
|
|
}
|
|
|
|
static int teq_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if (unlikely (cpu->gpr[rs] == cpu->gpr[rt])) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int teqi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int imm = bits (insn, 0, 15);
|
|
m_reg_t val = sign_extend (imm, 16);
|
|
|
|
if (unlikely (cpu->gpr[rs] == val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int mfmc0_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
int func = bits (insn, 0, 5);
|
|
|
|
if (rd != 12)
|
|
return unknown_op (cpu, insn);
|
|
|
|
cpu->reg_set (cpu, rt, cpu->cp0.reg [MIPS_CP0_STATUS]);
|
|
if (func & 0x20) {
|
|
/* ei - enable interrupts */
|
|
cpu->cp0.reg [MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_IE;
|
|
} else {
|
|
/* di - disable interrupts */
|
|
cpu->cp0.reg [MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_IE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int tlb_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
uint16_t func = bits (insn, 0, 5);
|
|
return mips_tlb_opcodes[func].func (cpu, insn);
|
|
}
|
|
|
|
static int tlbp_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_cp0_exec_tlbp (cpu);
|
|
return (0);
|
|
}
|
|
|
|
static int tlbr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_cp0_exec_tlbr (cpu);
|
|
return (0);
|
|
}
|
|
|
|
static int tlbwi_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_cp0_exec_tlbwi (cpu);
|
|
return (0);
|
|
}
|
|
|
|
static int tlbwr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
mips_cp0_exec_tlbwr (cpu);
|
|
return (0);
|
|
}
|
|
|
|
static int tge_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((m_ireg_t) cpu->gpr[rs] >= (m_ireg_t) cpu->gpr[rt]) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tgei_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_ireg_t val = sign_extend (bits (insn, 0, 15), 16);
|
|
|
|
if (unlikely ((m_ireg_t) cpu->gpr[rs] >= val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tgeiu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_reg_t val = sign_extend (bits (insn, 0, 15), 16);
|
|
|
|
if (unlikely ((m_reg_t) cpu->gpr[rs] >= val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tgeu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((m_reg_t) cpu->gpr[rs] >= (m_reg_t) cpu->gpr[rt]) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tlt_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((m_ireg_t) cpu->gpr[rs] < (m_ireg_t) cpu->gpr[rt]) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tlti_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_ireg_t val = sign_extend (bits (insn, 0, 15), 16);
|
|
|
|
if (unlikely ((m_ireg_t) cpu->gpr[rs] < val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tltiu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_reg_t val = sign_extend (bits (insn, 0, 15), 16);
|
|
|
|
if (unlikely ((m_reg_t) cpu->gpr[rs] < val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tltu_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((m_reg_t) cpu->gpr[rs] < (m_reg_t) cpu->gpr[rt]) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tne_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
|
|
if ((m_ireg_t) cpu->gpr[rs] != (m_ireg_t) cpu->gpr[rt]) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int tnei_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
m_reg_t val = sign_extend (bits (insn, 0, 15), 16);
|
|
|
|
if (unlikely (cpu->gpr[rs] != val)) {
|
|
mips_trigger_trap_exception (cpu);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int wait_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
if (! (cpu->cp0.reg [MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IE)) {
|
|
/* Wait instruction with interrupts disabled - stop the simulator. */
|
|
printf ("%08x: wait instruction with interrupts disabled - stop the simulator.\n",
|
|
cpu->pc);
|
|
kill (0, SIGQUIT);
|
|
}
|
|
usleep (1000);
|
|
return (0);
|
|
}
|
|
|
|
static int xor_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
cpu->reg_set (cpu, rd, cpu->gpr[rs] ^ cpu->gpr[rt]);
|
|
return (0);
|
|
}
|
|
|
|
static int rdpgpr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
printf ("%08x: unsupported RDPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt);
|
|
return (0);
|
|
}
|
|
|
|
static int wrpgpr_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rt = bits (insn, 16, 20);
|
|
int rd = bits (insn, 11, 15);
|
|
|
|
printf ("%08x: unsupported WRPGPR $%u,$%u instruction.\n", cpu->pc, rd, rt);
|
|
return (0);
|
|
}
|
|
|
|
static int xori_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
int rs = bits (insn, 21, 25);
|
|
int rt = bits (insn, 16, 20);
|
|
int imm = bits (insn, 0, 15);
|
|
|
|
cpu->reg_set (cpu, rt, cpu->gpr[rs] ^ imm);
|
|
return (0);
|
|
}
|
|
|
|
static int sdbbp_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
/* Clear status of previos Debug exception. */
|
|
cpu->cp0.reg[MIPS_CP0_DEBUG] &= ~MIPS_CP0_DEBUG_DEXCCODE;
|
|
|
|
if (cpu->cp0.reg[MIPS_CP0_DEBUG] & MIPS_CP0_DEBUG_DM) {
|
|
/* Already in Debug mode: take nested debug exception. */
|
|
mips_trigger_debug_exception (cpu, 0);
|
|
|
|
/* Set nested exception type. */
|
|
cpu->cp0.reg[MIPS_CP0_DEBUG] |=
|
|
MIPS_CP0_CAUSE_BP << MIPS_CP0_DEBUG_DEXCCODE_SHIFT;
|
|
|
|
} else {
|
|
/* Take a Breakpoint exception. */
|
|
mips_trigger_debug_exception (cpu, MIPS_CP0_DEBUG_DBP);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int undef_op (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_bcond (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_cop0 (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_spec2 (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_spec3 (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_spec (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
static int undef_tlb (cpu_mips_t * cpu, mips_insn_t insn)
|
|
{
|
|
return unknown_op (cpu, insn);
|
|
}
|
|
|
|
/*
|
|
* Main instruction table, indexed by bits 31:26 of opcode.
|
|
*/
|
|
static const struct mips_op_desc mips_opcodes[] = {
|
|
{"spec", spec_op, 0x00}, /* indexed by FUNC field */
|
|
{"bcond", bcond_op, 0x01}, /* indexed by RT field */
|
|
{"j", j_op, 0x02},
|
|
{"jal", jal_op, 0x03},
|
|
{"beq", beq_op, 0x04},
|
|
{"bne", bne_op, 0x05},
|
|
{"blez", blez_op, 0x06},
|
|
{"bgtz", bgtz_op, 0x07},
|
|
{"addi", addi_op, 0x08},
|
|
{"addiu", addiu_op, 0x09},
|
|
{"slti", slti_op, 0x0A},
|
|
{"sltiu", sltiu_op, 0x0B},
|
|
{"andi", andi_op, 0x0C},
|
|
{"ori", ori_op, 0x0D},
|
|
{"xori", xori_op, 0x0E},
|
|
{"lui", lui_op, 0x0F},
|
|
{"cop0", cop0_op, 0x10}, /* indexed by RS field */
|
|
{"cop1", cop1_op, 0x11},
|
|
{"cop2", cop2_op, 0x12},
|
|
{"cop1x", cop1x_op, 0x13},
|
|
{"beql", beql_op, 0x14},
|
|
{"bnel", bnel_op, 0x15},
|
|
{"blezl", blezl_op, 0x16},
|
|
{"bgtzl", bgtzl_op, 0x17},
|
|
{"daddi", daddi_op, 0x18},
|
|
{"daddiu", daddiu_op, 0x19},
|
|
{"ldl", ldl_op, 0x1A},
|
|
{"ldr", ldr_op, 0x1B},
|
|
{"spec2", spec2_op, 0x1C}, /* indexed by FUNC field */
|
|
{"jalx", jalx_op, 0x1D},
|
|
{"undef", undef_op, 0x1E},
|
|
{"spec3", spec3_op, 0x1F}, /* indexed by FUNC field */
|
|
{"lb", lb_op, 0x20},
|
|
{"lh", lh_op, 0x21},
|
|
{"lwl", lwl_op, 0x22},
|
|
{"lw", lw_op, 0x23},
|
|
{"lbu", lbu_op, 0x24},
|
|
{"lhu", lhu_op, 0x25},
|
|
{"lwr", lwr_op, 0x26},
|
|
{"lwu", lwu_op, 0x27},
|
|
{"sb", sb_op, 0x28},
|
|
{"sh", sh_op, 0x29},
|
|
{"swl", swl_op, 0x2A},
|
|
{"sw", sw_op, 0x2B},
|
|
{"sdl", sdl_op, 0x2C},
|
|
{"sdr", sdr_op, 0x2D},
|
|
{"swr", swr_op, 0x2E},
|
|
{"cache", cache_op, 0x2F},
|
|
{"ll", ll_op, 0x30},
|
|
{"lwc1", lwc1_op, 0x31},
|
|
{"lwc2", lwc2_op, 0x32},
|
|
{"pref", pref_op, 0x33},
|
|
{"lld", lld_op, 0x34},
|
|
{"ldc1", ldc1_op, 0x35},
|
|
{"ldc2", ldc2_op, 0x36},
|
|
{"ld", ld_op, 0x37},
|
|
{"sc", sc_op, 0x38},
|
|
{"swc1", swc1_op, 0x39},
|
|
{"swc2", swc2_op, 0x3A},
|
|
{"undef", undef_op, 0x3B},
|
|
{"scd", scd_op, 0x3C},
|
|
{"sdc1", sdc1_op, 0x3D},
|
|
{"sdc2", sdc2_op, 0x3E},
|
|
{"sd", sd_op, 0x3F},
|
|
};
|
|
|
|
/*
|
|
* SPEC opcode: indexed by FUNC field.
|
|
*/
|
|
static const struct mips_op_desc mips_spec_opcodes[] = {
|
|
{"sll", sll_op, 0x00},
|
|
{"movc", movc_op, 0x01},
|
|
{"srl", srl_op, 0x02},
|
|
{"sra", sra_op, 0x03},
|
|
{"sllv", sllv_op, 0x04},
|
|
{"?spec", undef_spec, 0x05},
|
|
{"srlv", srlv_op, 0x06},
|
|
{"srav", srav_op, 0x07},
|
|
{"jr", jr_op, 0x08},
|
|
{"jalr", jalr_op, 0x09},
|
|
{"movz", movz_op, 0x0A},
|
|
{"movn", movn_op, 0x0B},
|
|
{"syscall", syscall_op, 0x0C},
|
|
{"break", break_op, 0x0D},
|
|
{"spim", undef_spec, 0x0E},
|
|
{"sync", sync_op, 0x0F},
|
|
{"mfhi", mfhi_op, 0x10},
|
|
{"mthi", mthi_op, 0x11},
|
|
{"mflo", mflo_op, 0x12},
|
|
{"mtlo", mtlo_op, 0x13},
|
|
{"dsllv", dsllv_op, 0x14},
|
|
{"?spec", undef_spec, 0x15},
|
|
{"dsrlv", dsrlv_op, 0x16},
|
|
{"dsrav", dsrav_op, 0x17},
|
|
{"mult", mult_op, 0x18},
|
|
{"multu", multu_op, 0x19},
|
|
{"div", div_op, 0x1A},
|
|
{"divu", divu_op, 0x1B},
|
|
{"dmult", dmult_op, 0x1C},
|
|
{"dmultu", dmultu_op, 0x1D},
|
|
{"ddiv", ddiv_op, 0x1E},
|
|
{"ddivu", ddivu_op, 0x1F},
|
|
{"add", add_op, 0x20},
|
|
{"addu", addu_op, 0x21},
|
|
{"sub", sub_op, 0x22},
|
|
{"subu", subu_op, 0x23},
|
|
{"and", and_op, 0x24},
|
|
{"or", or_op, 0x25},
|
|
{"xor", xor_op, 0x26},
|
|
{"nor", nor_op, 0x27},
|
|
{"?spec", undef_spec, 0x28},
|
|
{"?spec", undef_spec, 0x29},
|
|
{"slt", slt_op, 0x2A},
|
|
{"sltu", sltu_op, 0x2B},
|
|
{"dadd", dadd_op, 0x2C},
|
|
{"daddu", daddu_op, 0x2D},
|
|
{"dsub", dsub_op, 0x2E},
|
|
{"dsubu", dsubu_op, 0x2F},
|
|
{"tge", tge_op, 0x30},
|
|
{"tgeu", tgeu_op, 0x31},
|
|
{"tlt", tlt_op, 0x32},
|
|
{"tltu", tltu_op, 0x33},
|
|
{"teq", teq_op, 0x34},
|
|
{"?spec", undef_spec, 0x35},
|
|
{"tne", tne_op, 0x36},
|
|
{"?spec", undef_spec, 0x37},
|
|
{"dsll", dsll_op, 0x38},
|
|
{"?spec", undef_spec, 0x39},
|
|
{"dsrl", dsrl_op, 0x3A},
|
|
{"dsra", dsra_op, 0x3B},
|
|
{"dsll32", dsll32_op, 0x3C},
|
|
{"?spec", undef_spec, 0x3D},
|
|
{"dsrl32", dsrl32_op, 0x3E},
|
|
{"dsra32", dsra32_op, 0x3F}
|
|
};
|
|
|
|
/*
|
|
* BCOND opcode: indexed by RT field.
|
|
*/
|
|
static const struct mips_op_desc mips_bcond_opcodes[] = {
|
|
{"bltz", bltz_op, 0x00},
|
|
{"bgez", bgez_op, 0x01},
|
|
{"bltzl", bltzl_op, 0x02},
|
|
{"bgezl", bgezl_op, 0x03},
|
|
{"spimi", undef_bcond,0x04},
|
|
{"?bcond", undef_bcond,0x05},
|
|
{"?bcond", undef_bcond,0x06},
|
|
{"?bcond", undef_bcond,0x07},
|
|
{"tgei", tgei_op, 0x08},
|
|
{"tgeiu", tgeiu_op, 0x09},
|
|
{"tlti", tlti_op, 0x0A},
|
|
{"tltiu", tltiu_op, 0x0B},
|
|
{"teqi", teqi_op, 0x0C},
|
|
{"?bcond", undef_bcond,0x0D},
|
|
{"tnei", tnei_op, 0x0E},
|
|
{"?bcond", undef_bcond,0x0F},
|
|
{"bltzal", bltzal_op, 0x10},
|
|
{"bgezal", bgezal_op, 0x11},
|
|
{"bltzall", bltzall_op, 0x12},
|
|
{"bgezall", bgezall_op, 0x13},
|
|
{"?bcond", undef_bcond,0x14},
|
|
{"?bcond", undef_bcond,0x15},
|
|
{"?bcond", undef_bcond,0x16},
|
|
{"?bcond", undef_bcond,0x17},
|
|
{"?bcond", undef_bcond,0x18},
|
|
{"?bcond", undef_bcond,0x19},
|
|
{"?bcond", undef_bcond,0x1A},
|
|
{"?bcond", undef_bcond,0x1B},
|
|
{"?bcond", undef_bcond,0x1C},
|
|
{"?bcond", undef_bcond,0x1D},
|
|
{"?bcond", undef_bcond,0x1E},
|
|
{"?bcond", undef_bcond,0x1F}
|
|
};
|
|
|
|
/*
|
|
* COP0 opcode: indexed by RS field.
|
|
*/
|
|
static const struct mips_op_desc mips_cop0_opcodes[] = {
|
|
{"mfc0", mfc0_op, 0x0},
|
|
{"dmfc0", dmfc0_op, 0x1},
|
|
{"cfc0", cfc0_op, 0x2},
|
|
{"?cop0", undef_cop0, 0x3},
|
|
{"mtc0", mtc0_op, 0x4},
|
|
{"dmtc0", dmtc0_op, 0x5},
|
|
{"?cop0", undef_cop0, 0x6},
|
|
{"?cop0", undef_cop0, 0x7},
|
|
{"?cop0", undef_cop0, 0x8},
|
|
{"?cop0", undef_cop0, 0x9},
|
|
{"?cop0", rdpgpr_op, 0xa},
|
|
{"?cop0", mfmc0_op, 0xb},
|
|
{"?cop0", undef_cop0, 0xc},
|
|
{"?cop0", undef_cop0, 0xd},
|
|
{"wrpgpr", wrpgpr_op, 0xe},
|
|
{"?cop0", undef_cop0, 0xf},
|
|
{"tlb", tlb_op, 0x10}, /* indexed by FUNC field */
|
|
{"?cop0", undef_cop0, 0x11},
|
|
{"?cop0", undef_cop0, 0x12},
|
|
{"?cop0", undef_cop0, 0x13},
|
|
{"?cop0", undef_cop0, 0x14},
|
|
{"?cop0", undef_cop0, 0x15},
|
|
{"?cop0", undef_cop0, 0x16},
|
|
{"?cop0", undef_cop0, 0x17},
|
|
{"?cop0", undef_cop0, 0x18},
|
|
{"?cop0", undef_cop0, 0x19},
|
|
{"?cop0", undef_cop0, 0x1a},
|
|
{"?cop0", undef_cop0, 0x1b},
|
|
{"?cop0", undef_cop0, 0x1c},
|
|
{"?cop0", undef_cop0, 0x1d},
|
|
{"?cop0", undef_cop0, 0x1e},
|
|
{"?cop0", undef_cop0, 0x1f},
|
|
};
|
|
|
|
/*
|
|
* SPEC2 opcode: indexed by FUNC field.
|
|
*/
|
|
static const struct mips_op_desc mips_spec2_opcodes[] = {
|
|
{"madd", madd_op, 0x0},
|
|
{"maddu", maddu_op, 0x1},
|
|
{"mul", mul_op, 0x2},
|
|
{"?spec2", undef_spec2,0x3},
|
|
{"msub", msub_op, 0x4},
|
|
{"msubu", msubu_op, 0x5},
|
|
{"?spec2", undef_spec2,0x6},
|
|
{"?spec2", undef_spec2,0x7},
|
|
{"?spec2", undef_spec2,0x8},
|
|
{"?spec2", undef_spec2,0x9},
|
|
{"?spec2", undef_spec2,0xa},
|
|
{"?spec2", undef_spec2,0xb},
|
|
{"?spec2", undef_spec2,0xc},
|
|
{"?spec2", undef_spec2,0xd},
|
|
{"?spec2", undef_spec2,0xe},
|
|
{"?spec2", undef_spec2,0xf},
|
|
{"?spec2", undef_spec2,0x10},
|
|
{"?spec2", undef_spec2,0x11},
|
|
{"?spec2", undef_spec2,0x12},
|
|
{"?spec2", undef_spec2,0x13},
|
|
{"?spec2", undef_spec2,0x14},
|
|
{"?spec2", undef_spec2,0x15},
|
|
{"?spec2", undef_spec2,0x16},
|
|
{"?spec2", undef_spec2,0x17},
|
|
{"?spec2", undef_spec2,0x18},
|
|
{"?spec2", undef_spec2,0x19},
|
|
{"?spec2", undef_spec2,0x1a},
|
|
{"?spec2", undef_spec2,0x1b},
|
|
{"?spec2", undef_spec2,0x1c},
|
|
{"?spec2", undef_spec2,0x1d},
|
|
{"?spec2", undef_spec2,0x1e},
|
|
{"?spec2", undef_spec2,0x1f},
|
|
{"clz", clz_op, 0x20},
|
|
{"clo", clo_op, 0x21},
|
|
{"?spec2", undef_spec2,0x22},
|
|
{"?spec2", undef_spec2,0x23},
|
|
{"?spec2", undef_spec2,0x24},
|
|
{"?spec2", undef_spec2,0x25},
|
|
{"?spec2", undef_spec2,0x26},
|
|
{"?spec2", undef_spec2,0x27},
|
|
{"?spec2", undef_spec2,0x28},
|
|
{"?spec2", undef_spec2,0x29},
|
|
{"?spec2", undef_spec2,0x2a},
|
|
{"?spec2", undef_spec2,0x2b},
|
|
{"?spec2", undef_spec2,0x2c},
|
|
{"?spec2", undef_spec2,0x2d},
|
|
{"?spec2", undef_spec2,0x2e},
|
|
{"?spec2", undef_spec2,0x2f},
|
|
{"?spec2", undef_spec2,0x30},
|
|
{"?spec2", undef_spec2,0x31},
|
|
{"?spec2", undef_spec2,0x32},
|
|
{"?spec2", undef_spec2,0x33},
|
|
{"?spec2", undef_spec2,0x34},
|
|
{"?spec2", undef_spec2,0x35},
|
|
{"?spec2", undef_spec2,0x36},
|
|
{"?spec2", undef_spec2,0x37},
|
|
{"?spec2", undef_spec2,0x38},
|
|
{"?spec2", undef_spec2,0x39},
|
|
{"?spec2", undef_spec2,0x3a},
|
|
{"?spec2", undef_spec2,0x3b},
|
|
{"?spec2", undef_spec2,0x3c},
|
|
{"?spec2", undef_spec2,0x3d},
|
|
{"?spec2", undef_spec2,0x3e},
|
|
{"?spec2", sdbbp_op, 0x3f},
|
|
};
|
|
|
|
/*
|
|
* SPEC3 opcode: indexed by FUNC field.
|
|
*/
|
|
static const struct mips_op_desc mips_spec3_opcodes[] = {
|
|
{"ext", ext_op, 0x0},
|
|
{"?spec3", undef_spec3,0x1},
|
|
{"?spec3", undef_spec3,0x2},
|
|
{"?spec3", undef_spec3,0x3},
|
|
{"ins", ins_op, 0x4},
|
|
{"?spec3", undef_spec3,0x5},
|
|
{"?spec3", undef_spec3,0x6},
|
|
{"?spec3", undef_spec3,0x7},
|
|
{"?spec3", undef_spec3,0x8},
|
|
{"?spec3", undef_spec3,0x9},
|
|
{"?spec3", undef_spec3,0xa},
|
|
{"?spec3", undef_spec3,0xb},
|
|
{"?spec3", undef_spec3,0xc},
|
|
{"?spec3", undef_spec3,0xd},
|
|
{"?spec3", undef_spec3,0xe},
|
|
{"?spec3", undef_spec3,0xf},
|
|
{"?spec3", undef_spec3,0x10},
|
|
{"?spec3", undef_spec3,0x11},
|
|
{"?spec3", undef_spec3,0x12},
|
|
{"?spec3", undef_spec3,0x13},
|
|
{"?spec3", undef_spec3,0x14},
|
|
{"?spec3", undef_spec3,0x15},
|
|
{"?spec3", undef_spec3,0x16},
|
|
{"?spec3", undef_spec3,0x17},
|
|
{"?spec3", undef_spec3,0x18},
|
|
{"?spec3", undef_spec3,0x19},
|
|
{"?spec3", undef_spec3,0x1a},
|
|
{"?spec3", undef_spec3,0x1b},
|
|
{"?spec3", undef_spec3,0x1c},
|
|
{"?spec3", undef_spec3,0x1d},
|
|
{"?spec3", undef_spec3,0x1e},
|
|
{"?spec3", undef_spec3,0x1f},
|
|
{"bshfl", bshfl_op, 0x20},
|
|
{"?spec3", undef_spec3,0x21},
|
|
{"?spec3", undef_spec3,0x22},
|
|
{"?spec3", undef_spec3,0x23},
|
|
{"?spec3", undef_spec3,0x24},
|
|
{"?spec3", undef_spec3,0x25},
|
|
{"?spec3", undef_spec3,0x26},
|
|
{"?spec3", undef_spec3,0x27},
|
|
{"?spec3", undef_spec3,0x28},
|
|
{"?spec3", undef_spec3,0x29},
|
|
{"?spec3", undef_spec3,0x2a},
|
|
{"?spec3", undef_spec3,0x2b},
|
|
{"?spec3", undef_spec3,0x2c},
|
|
{"?spec3", undef_spec3,0x2d},
|
|
{"?spec3", undef_spec3,0x2e},
|
|
{"?spec3", undef_spec3,0x2f},
|
|
{"?spec3", undef_spec3,0x30},
|
|
{"?spec3", undef_spec3,0x31},
|
|
{"?spec3", undef_spec3,0x32},
|
|
{"?spec3", undef_spec3,0x33},
|
|
{"?spec3", undef_spec3,0x34},
|
|
{"?spec3", undef_spec3,0x35},
|
|
{"?spec3", undef_spec3,0x36},
|
|
{"?spec3", undef_spec3,0x37},
|
|
{"?spec3", undef_spec3,0x38},
|
|
{"?spec3", undef_spec3,0x39},
|
|
{"?spec3", undef_spec3,0x3a},
|
|
{"?spec3", undef_spec3,0x3b},
|
|
{"?spec3", undef_spec3,0x3c},
|
|
{"?spec3", undef_spec3,0x3d},
|
|
{"?spec3", undef_spec3,0x3e},
|
|
{"?spec3", undef_spec3,0x3f},
|
|
};
|
|
|
|
/*
|
|
* TLB opcode: indexed by FUNC field.
|
|
*/
|
|
static const struct mips_op_desc mips_tlb_opcodes[] = {
|
|
{"?tlb", undef_tlb, 0x0},
|
|
{"tlbr", tlbr_op, 0x1},
|
|
{"tlbwi", tlbwi_op, 0x2},
|
|
{"?tlb", undef_tlb, 0x3},
|
|
{"?tlb", undef_tlb, 0x4},
|
|
{"?tlb", undef_tlb, 0x5},
|
|
{"tlbwi", tlbwr_op, 0x6},
|
|
{"?tlb", undef_tlb, 0x7},
|
|
{"tlbp", tlbp_op, 0x8},
|
|
{"?tlb", undef_tlb, 0x9},
|
|
{"?tlb", undef_tlb, 0xa},
|
|
{"?tlb", undef_tlb, 0xb},
|
|
{"?tlb", undef_tlb, 0xc},
|
|
{"?tlb", undef_tlb, 0xd},
|
|
{"?tlb", undef_tlb, 0xe},
|
|
{"?tlb", undef_tlb, 0xf},
|
|
{"?tlb", undef_tlb, 0x10},
|
|
{"?tlb", undef_tlb, 0x11},
|
|
{"?tlb", undef_tlb, 0x12},
|
|
{"?tlb", undef_tlb, 0x13},
|
|
{"?tlb", undef_tlb, 0x14},
|
|
{"?tlb", undef_tlb, 0x15},
|
|
{"?tlb", undef_tlb, 0x16},
|
|
{"?tlb", undef_tlb, 0x17},
|
|
{"eret", eret_op, 0x18},
|
|
{"?tlb", undef_tlb, 0x19},
|
|
{"?tlb", undef_tlb, 0x1a},
|
|
{"?tlb", undef_tlb, 0x1b},
|
|
{"?tlb", undef_tlb, 0x1c},
|
|
{"?tlb", undef_tlb, 0x1d},
|
|
{"?tlb", undef_tlb, 0x1e},
|
|
{"deret", deret_op, 0x1f},
|
|
{"wait", wait_op, 0x20},
|
|
{"?tlb", undef_tlb, 0x21},
|
|
{"?tlb", undef_tlb, 0x22},
|
|
{"?tlb", undef_tlb, 0x23},
|
|
{"?tlb", undef_tlb, 0x24},
|
|
{"?tlb", undef_tlb, 0x25},
|
|
{"?tlb", undef_tlb, 0x26},
|
|
{"?tlb", undef_tlb, 0x27},
|
|
{"?tlb", undef_tlb, 0x28},
|
|
{"?tlb", undef_tlb, 0x29},
|
|
{"?tlb", undef_tlb, 0x2a},
|
|
{"?tlb", undef_tlb, 0x2b},
|
|
{"?tlb", undef_tlb, 0x2c},
|
|
{"?tlb", undef_tlb, 0x2d},
|
|
{"?tlb", undef_tlb, 0x2e},
|
|
{"?tlb", undef_tlb, 0x2f},
|
|
{"?tlb", undef_tlb, 0x30},
|
|
{"?tlb", undef_tlb, 0x31},
|
|
{"?tlb", undef_tlb, 0x32},
|
|
{"?tlb", undef_tlb, 0x33},
|
|
{"?tlb", undef_tlb, 0x34},
|
|
{"?tlb", undef_tlb, 0x35},
|
|
{"?tlb", undef_tlb, 0x36},
|
|
{"?tlb", undef_tlb, 0x37},
|
|
{"?tlb", undef_tlb, 0x38},
|
|
{"?tlb", undef_tlb, 0x39},
|
|
{"?tlb", undef_tlb, 0x3a},
|
|
{"?tlb", undef_tlb, 0x3b},
|
|
{"?tlb", undef_tlb, 0x3c},
|
|
{"?tlb", undef_tlb, 0x3d},
|
|
{"?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
|
|
// TBD!!! handle memory errors better
|
|
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
|
|
// TBD!!! handle memory errors better
|
|
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
|
|
}
|