DSPLLE: Handle cr, sr, and prod.h masking
This commit is contained in:
parent
3d6ff60a96
commit
858d0675b9
|
@ -200,7 +200,7 @@ enum : u16
|
||||||
SR_LOGIC_ZERO = 0x0040,
|
SR_LOGIC_ZERO = 0x0040,
|
||||||
SR_OVERFLOW_STICKY =
|
SR_OVERFLOW_STICKY =
|
||||||
0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same
|
0x0080, // Set at the same time as 0x2 (under same conditions) - but not cleared the same
|
||||||
SR_100 = 0x0100, // Unknown
|
SR_100 = 0x0100, // Unknown, always reads back as 0
|
||||||
SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so.
|
SR_INT_ENABLE = 0x0200, // Not 100% sure but duddie says so. This should replace the hack, if so.
|
||||||
SR_400 = 0x0400, // Unknown
|
SR_400 = 0x0400, // Unknown
|
||||||
SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts
|
SR_EXT_INT_ENABLE = 0x0800, // Appears in zelda - seems to disable external interrupts
|
||||||
|
|
|
@ -687,7 +687,7 @@ void Interpreter::OpWriteRegister(int reg_, u16 val)
|
||||||
|
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
// 8-bit sign extended registers. Should look at prod.h too...
|
// 8-bit sign extended registers.
|
||||||
case DSP_REG_ACH0:
|
case DSP_REG_ACH0:
|
||||||
case DSP_REG_ACH1:
|
case DSP_REG_ACH1:
|
||||||
// sign extend from the bottom 8 bits.
|
// sign extend from the bottom 8 bits.
|
||||||
|
@ -720,10 +720,10 @@ void Interpreter::OpWriteRegister(int reg_, u16 val)
|
||||||
state.r.wr[reg - DSP_REG_WR0] = val;
|
state.r.wr[reg - DSP_REG_WR0] = val;
|
||||||
break;
|
break;
|
||||||
case DSP_REG_CR:
|
case DSP_REG_CR:
|
||||||
state.r.cr = val;
|
state.r.cr = val & 0x00ff;
|
||||||
break;
|
break;
|
||||||
case DSP_REG_SR:
|
case DSP_REG_SR:
|
||||||
state.r.sr = val;
|
state.r.sr = val & ~SR_100;
|
||||||
break;
|
break;
|
||||||
case DSP_REG_PRODL:
|
case DSP_REG_PRODL:
|
||||||
state.r.prod.l = val;
|
state.r.prod.l = val;
|
||||||
|
@ -732,7 +732,8 @@ void Interpreter::OpWriteRegister(int reg_, u16 val)
|
||||||
state.r.prod.m = val;
|
state.r.prod.m = val;
|
||||||
break;
|
break;
|
||||||
case DSP_REG_PRODH:
|
case DSP_REG_PRODH:
|
||||||
state.r.prod.h = val;
|
// Unlike ac0.h and ac1.h, prod.h is not sign-extended
|
||||||
|
state.r.prod.h = val & 0x00ff;
|
||||||
break;
|
break;
|
||||||
case DSP_REG_PRODM2:
|
case DSP_REG_PRODM2:
|
||||||
state.r.prod.m2 = val;
|
state.r.prod.m2 = val;
|
||||||
|
|
|
@ -751,6 +751,7 @@ void DSPJitRegCache::PutReg(int reg, bool dirty)
|
||||||
else if (oparg.IsImm())
|
else if (oparg.IsImm())
|
||||||
{
|
{
|
||||||
// TODO: Immediates?
|
// TODO: Immediates?
|
||||||
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -772,6 +773,58 @@ void DSPJitRegCache::PutReg(int reg, bool dirty)
|
||||||
m_emitter.SAR(64, oparg, Imm8(64 - 40));
|
m_emitter.SAR(64, oparg, Imm8(64 - 40));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DSP_REG_CR:
|
||||||
|
case DSP_REG_PRODH:
|
||||||
|
if (dirty)
|
||||||
|
{
|
||||||
|
if (oparg.IsSimpleReg())
|
||||||
|
{
|
||||||
|
// register is already shifted correctly
|
||||||
|
// (if at all)
|
||||||
|
|
||||||
|
// Zero extend from the bottom 8 bits.
|
||||||
|
m_emitter.MOVZX(16, 8, oparg.GetSimpleReg(), oparg);
|
||||||
|
}
|
||||||
|
else if (oparg.IsImm())
|
||||||
|
{
|
||||||
|
// TODO: Immediates?
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This works on the memory, so use reg instead
|
||||||
|
// of real_reg, since it has the right loc
|
||||||
|
X64Reg tmp = GetFreeXReg();
|
||||||
|
// Zero extend from the bottom 8 bits.
|
||||||
|
m_emitter.MOVZX(16, 8, tmp, m_regs[reg].loc);
|
||||||
|
m_emitter.MOV(16, m_regs[reg].loc, R(tmp));
|
||||||
|
PutXReg(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DSP_REG_SR:
|
||||||
|
if (dirty)
|
||||||
|
{
|
||||||
|
if (oparg.IsSimpleReg())
|
||||||
|
{
|
||||||
|
// register is already shifted correctly
|
||||||
|
// (if at all)
|
||||||
|
|
||||||
|
// Clear SR_100, which always reads back as 0
|
||||||
|
m_emitter.AND(16, R(oparg.GetSimpleReg()), Gen::Imm16(~SR_100));
|
||||||
|
}
|
||||||
|
else if (oparg.IsImm())
|
||||||
|
{
|
||||||
|
// TODO: Immediates?
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clear SR_100, which always reads back as 0
|
||||||
|
m_emitter.AND(16, m_regs[reg].loc, Gen::Imm16(~SR_100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
incdir "tests"
|
||||||
|
include "dsp_base.inc"
|
||||||
|
|
||||||
|
; Test what happens various values are written to every register
|
||||||
|
LRI $ar0, #0xffff
|
||||||
|
CALL set_all_regs
|
||||||
|
CALL send_back
|
||||||
|
|
||||||
|
LRI $ar0, #0x0000
|
||||||
|
CALL set_all_regs
|
||||||
|
CALL send_back
|
||||||
|
|
||||||
|
LRI $ar0, #0x007f
|
||||||
|
CALL set_all_regs
|
||||||
|
CALL send_back
|
||||||
|
|
||||||
|
LRI $ar0, #0x0080
|
||||||
|
CALL set_all_regs
|
||||||
|
CALL send_back
|
||||||
|
|
||||||
|
LRI $ar0, #0x0100
|
||||||
|
CALL set_all_regs
|
||||||
|
CALL send_back
|
||||||
|
|
||||||
|
; We're done, DO NOT DELETE THIS LINE
|
||||||
|
JMP end_of_test
|
||||||
|
|
||||||
|
; Copy $ar0 to all other registers
|
||||||
|
set_all_regs:
|
||||||
|
SET16
|
||||||
|
MRR $ar1, $ar0
|
||||||
|
MRR $ar2, $ar0
|
||||||
|
MRR $ar3, $ar0
|
||||||
|
MRR $ix0, $ar0
|
||||||
|
MRR $ix1, $ar0
|
||||||
|
MRR $ix2, $ar0
|
||||||
|
MRR $ix3, $ar0
|
||||||
|
MRR $wr0, $ar0
|
||||||
|
MRR $wr1, $ar0
|
||||||
|
MRR $wr2, $ar0
|
||||||
|
MRR $wr3, $ar0
|
||||||
|
; Don't write to the stacks; returning from this function breaks otherwise
|
||||||
|
; They don't show up in DSPSpy anyways
|
||||||
|
;MRR $st0, $ar0
|
||||||
|
;MRR $st1, $ar0
|
||||||
|
;MRR $st2, $ar0
|
||||||
|
;MRR $st3, $ar0
|
||||||
|
MRR $ac0.h, $ar0
|
||||||
|
MRR $ac1.h, $ar0
|
||||||
|
MRR $cr, $ar0
|
||||||
|
; Wait to set $sr, as it can change the way stores work
|
||||||
|
MRR $prod.l, $ar0
|
||||||
|
MRR $prod.m1, $ar0
|
||||||
|
MRR $prod.h, $ar0
|
||||||
|
MRR $prod.m2, $ar0
|
||||||
|
MRR $ax0.l, $ar0
|
||||||
|
MRR $ax1.l, $ar0
|
||||||
|
MRR $ax0.h, $ar0
|
||||||
|
MRR $ax1.h, $ar0
|
||||||
|
MRR $ac0.l, $ar0
|
||||||
|
MRR $ac1.l, $ar0
|
||||||
|
MRR $ac0.m, $ar0
|
||||||
|
MRR $ac1.m, $ar0
|
||||||
|
MRR $sr, $ar0
|
||||||
|
RET
|
Loading…
Reference in New Issue