diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj
index 16157c4d3d..05917ca096 100644
--- a/Source/Core/DSPCore/DSPCore.vcproj
+++ b/Source/Core/DSPCore/DSPCore.vcproj
@@ -457,6 +457,10 @@
RelativePath=".\Src\Jit\DSPJitUtil.cpp"
>
+
+
> 5) & 0x1f;
+
+ u16 val = dsp_op_read_reg(sreg);
+ dsp_op_write_reg(dreg, val);
+ dsp_conditional_extend_accum(dreg);
+}
+*/
+
+// LRI $D, #I
+// 0000 0000 100d dddd
+// iiii iiii iiii iiii
+// Load immediate value I to register $D.
+// FIXME: Perform additional operation depending on destination register.
+//
+// DSPSpy discovery: This, and possibly other instructions that load a
+// register, has a different behaviour in S40 mode if loaded to AC0.M: The
+// value gets sign extended to the whole accumulator! This does not happen in
+// S16 mode.
+/*void DSPEmitter::lri(const UDSPInstruction opc)
+{
+ u8 reg = opc & DSP_REG_MASK;
+ u16 imm = dsp_fetch_code();
+ dsp_op_write_reg(reg, imm);
+ dsp_conditional_extend_accum(reg);
+}
+
+
+// LRIS $(0x18+D), #I
+// 0000 1ddd iiii iiii
+// Load immediate value I (8-bit sign extended) to accumulator register.
+// FIXME: Perform additional operation depending on destination register.
+void DSPEmitter::lris(const UDSPInstruction opc)
+{
+ u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;
+ u16 imm = (s8)opc;
+ dsp_op_write_reg(reg, imm);
+ dsp_conditional_extend_accum(reg);
+}
+
+//----
+
+// NX
+// 1000 -000 xxxx xxxx
+// No operation, but can be extended with extended opcode.
+// This opcode is supposed to do nothing - it's used if you want to use
+// an opcode extension but not do anything. At least according to duddie.
+void DSPEmitter::nx(const UDSPInstruction opc)
+{
+ zeroWriteBackLog();
+}
+*/
+//----
+
+// DAR $arD
+// 0000 0000 0000 01dd
+// Decrement address register $arD.
+void DSPEmitter::dar(const UDSPInstruction opc)
+{
+ // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3);
+ decrement_addr_reg(opc & 0x3);
+
+}
+
+// IAR $arD
+// 0000 0000 0000 10dd
+// Increment address register $arD.
+void DSPEmitter::iar(const UDSPInstruction opc)
+{
+ // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3);
+ increment_addr_reg(opc & 0x3);
+}
+
+// SUBARN $arD
+// 0000 0000 0000 11dd
+// Subtract indexing register $ixD from an addressing register $arD.
+// used only in IPL-NTSC ucode
+void DSPEmitter::subarn(const UDSPInstruction opc)
+{
+ // u8 dreg = opc & 0x3;
+ // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
+ decrease_addr_reg(opc & 0x3);
+}
+
+// ADDARN $arD, $ixS
+// 0000 0000 0001 ssdd
+// Adds indexing register $ixS to an addressing register $arD.
+// It is critical for the Zelda ucode that this one wraps correctly.
+void DSPEmitter::addarn(const UDSPInstruction opc)
+{
+ // u8 dreg = opc & 0x3;
+ // u8 sreg = (opc >> 2) & 0x3;
+ // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
+
+ // From looking around it is always called with the matching index register
+ increase_addr_reg(opc & 0x3);
+}
+
+//----
+
+
+void DSPEmitter::setSR(u16 bit) {
+
+ // (1 << bit)
+ MOV(32, R(EAX), Imm32(1));
+ SHR(32, R(EAX), Imm32(bit));
+
+ // g_dsp.r[DSP_REG_SR] |= EAX
+ MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_SR]));
+ OR(32, R(ECX), R(EAX));
+
+ compileSR |= (1 << bit);
+}
+
+void DSPEmitter::clrSR(u16 bit) {
+ // ~(1 << bit)
+ MOV(32, R(EAX), Imm32(1));
+ SHR(32, R(EAX), Imm32(bit));
+ NOT(32, R(EAX));
+
+ // g_dsp.r[DSP_REG_SR] &= EAX
+ MOV(16, R(ECX), M(&g_dsp.r[DSP_REG_SR]));
+ AND(32, R(ECX), R(EAX));
+
+ compileSR &= ~(1 << bit);
+}
+// SBCLR #I
+// 0001 0011 aaaa aiii
+// bit of status register $sr. Bit number is calculated by adding 6 to
+// immediate value I.
+void DSPEmitter::sbclr(const UDSPInstruction opc)
+{
+ u16 bit = (opc & 0x7) + 6;
+
+ clrSR(bit);
+}
+
+// SBSET #I
+// 0001 0010 aaaa aiii
+// Set bit of status register $sr. Bit number is calculated by adding 6 to
+// immediate value I.
+void DSPEmitter::sbset(const UDSPInstruction opc)
+{
+ u8 bit = (opc & 0x7) + 6;
+ setSR(bit);
+}
+
+// This is a bunch of flag setters, flipping bits in SR. So far so good,
+// but it's harder to know exactly what effect they have.
+void DSPEmitter::srbith(const UDSPInstruction opc)
+{
+ ABI_CallFunction((void *)zeroWriteBackLog);
+ switch ((opc >> 8) & 0xf)
+ {
+ // M0/M2 change the multiplier mode (it can multiply by 2 for free).
+ case 0xa: // M2
+ clrSR(SR_MUL_MODIFY);
+ break;
+ case 0xb: // M0
+ setSR(SR_MUL_MODIFY);
+ break;
+
+ // If set, treat multiplicands as unsigned.
+ // If clear, treat them as signed.
+ case 0xc: // CLR15
+ clrSR(SR_MUL_UNSIGNED);
+ break;
+ case 0xd: // SET15
+ setSR(SR_MUL_UNSIGNED);
+ break;
+
+ // Automatic 40-bit sign extension when loading ACx.M.
+ // SET40 changes something very important: see the LRI instruction above.
+ case 0xe: // SET16 (CLR40)
+ clrSR(SR_40_MODE_BIT);
+ break;
+
+ case 0xf: // SET40
+ setSR(SR_40_MODE_BIT);
+ g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT;
+ break;
+
+ default:
+ break;
+ }
+}
+
diff --git a/Source/Core/DSPCore/Src/SConscript b/Source/Core/DSPCore/Src/SConscript
index 8433d084a1..61b7016bb7 100644
--- a/Source/Core/DSPCore/Src/SConscript
+++ b/Source/Core/DSPCore/Src/SConscript
@@ -26,7 +26,7 @@ files = [
"DSPTables.cpp",
"Jit/DSPJitExtOps.cpp",
"Jit/DSPJitUtil.cpp",
-
+ "Jit/DSPJitMisc.cpp",
]
acenv = env.Clone()