Files
retrobsd/tools/virtualmips/mips_codetable.c
Serge Vakulenko b0705e54ab Virtualmips modified to allow access to SRSCtl register.
When only one GPR set supported, opcodes RDPGPR and WRPGPR
behave like MOVE instruction.
2014-05-15 10:48:33 -07:00

2172 lines
53 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_insn_mips (cpu->pc, insn, 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 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);
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 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 & ~((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 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->pc = new_pc;
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->pc = new_pc;
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 (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)
{
return unknown_op (cpu, insn);
}
static int tgei_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tgeiu_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tgeu_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tlt_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tlti_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tltiu_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
static int tltu_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
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]) {
/*take a trap */
mips_trigger_trap_exception (cpu);
return (1);
} else
return (0);
}
static int tnei_op (cpu_mips_t * cpu, mips_insn_t insn)
{
return unknown_op (cpu, insn);
}
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);
/* Only one GPR set supported: RDPGPR works as move. */
cpu->reg_set (cpu, rd, cpu->gpr[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);
/* Only one GPR set supported: WRPGPR works as move. */
cpu->reg_set (cpu, rd, cpu->gpr[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 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.
*/
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 */
{"undef", undef_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},
{"?spec2", undef_spec2,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", undef_spec2,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},
{"?tlb", undef_tlb, 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},
};