Virtualmips: handle overflow in div, add, addi and sub instructions.

This commit is contained in:
Serge Vakulenko
2015-10-29 20:15:10 -07:00
parent 7d3e799c82
commit d8708af48a

View File

@@ -42,15 +42,21 @@ static int cop_unusable(cpu_mips_t * cpu, int cop_index)
return 1;
}
static int add_op (cpu_mips_t * cpu, mips_insn_t insn)
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;
m_ireg_t a = cpu->gpr[rs];
m_ireg_t b = cpu->gpr[rt];
m_ireg_t res = a + b;
/* TODO: Exception handling */
res = (m_uint32_t) cpu->gpr[rs] + (m_uint32_t) cpu->gpr[rt];
if ((a > 0 && b > 0 && res < 0) ||
(a < 0 && b < 0 && res >= 0)) {
/* Take overflow exception. */
mips_trigger_exception (cpu, MIPS_CP0_CAUSE_OVFLW, cpu->is_in_bdslot);
return 1;
}
cpu->reg_set (cpu, rd, sign_extend (res, 32));
return (0);
}
@@ -60,10 +66,16 @@ 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);
m_ireg_t a = cpu->gpr[rs];
m_ireg_t b = sign_extend (imm, 16);
m_ireg_t res = a + b;
/* TODO: Exception handling */
res = (m_uint32_t) cpu->gpr[rs] + val;
if ((a > 0 && b > 0 && res < 0) ||
(a < 0 && b < 0 && res >= 0)) {
/* Take overflow exception. */
mips_trigger_exception (cpu, MIPS_CP0_CAUSE_OVFLW, cpu->is_in_bdslot);
return 1;
}
cpu->reg_set (cpu, rt, sign_extend (res, 32));
return (0);
}
@@ -619,10 +631,15 @@ 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))
if (cpu->gpr[rt] == 0)
return (0);
if (cpu->gpr[rs] == 0x80000000 && cpu->gpr[rt] == 0xFFFFFFFF) {
cpu->lo = 0x80000000;
cpu->hi = 0;
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];
@@ -1347,10 +1364,16 @@ 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;
m_ireg_t a = cpu->gpr[rs];
m_ireg_t b = cpu->gpr[rt];
m_ireg_t res = a - b;
/* TODO: Exception handling */
res = (m_uint32_t) cpu->gpr[rs] - (m_uint32_t) cpu->gpr[rt];
if ((a > 0 && b < 0 && res < 0) ||
(a < 0 && b > 0 && res >= 0)) {
/* Take overflow exception. */
mips_trigger_exception (cpu, MIPS_CP0_CAUSE_OVFLW, cpu->is_in_bdslot);
return 1;
}
cpu->reg_set (cpu, rd, sign_extend (res, 32));
return (0);
}