+//Let's not, until we do the stalling correctly...
+//But, we gotta while we're doing the comparison core...!
+//Or do we? cycles--;
+//Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
+//will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
+//to model this clock cycle behavior correctly...
+//Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
+//don't affect the reads at stage 1...
+#ifdef DSP_DEBUG_STALL
+if (doDSPDis)
+ WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
+#endif
+}
+
+#ifdef DSP_DEBUG_PL2
+if (doDSPDis)
+{
+WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
+WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
+WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
+WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
+WriteLog("\n");
+}
+#endif
+ // Stage 3: Write back register/memory address
+ if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
+ {
+/*if (pipeline[plPtrWrite].writebackRegister == 3
+ && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
+ && !doDSPDis)
+{
+ WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
+ doDSPDis = true;
+}//*/
+ if (pipeline[plPtrWrite].writebackRegister != 0xFF)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFE)
+ dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
+ else
+ {
+ if (pipeline[plPtrWrite].type == TYPE_BYTE)
+ JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else if (pipeline[plPtrWrite].type == TYPE_WORD)
+ JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else
+ JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ }
+ }
+
+#ifndef NEW_SCOREBOARD
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ scoreboard[pipeline[plPtrWrite].operand2] = false;
+#else
+//Yup, sequential MOVEQ # problem fixing (I hope!)...
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ if (scoreboard[pipeline[plPtrWrite].operand2])
+ scoreboard[pipeline[plPtrWrite].operand2]--;
+#endif
+ }
+
+ // Push instructions through the pipeline...
+ plPtrRead = (++plPtrRead) & 0x03;
+ plPtrExec = (++plPtrExec) & 0x03;
+ plPtrWrite = (++plPtrWrite) & 0x03;
+ }
+
+ dsp_in_exec--;
+}
+
+
+
+/*
+//#define DSP_DEBUG_PL3
+//Let's try a 2 stage pipeline....
+void DSPExecP3(int32_t cycles)
+{
+ dsp_releaseTimeSlice_flag = 0;
+ dsp_in_exec++;
+
+ while (cycles > 0 && DSP_RUNNING)
+ {
+//if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
+// doDSPDis = true;
+#ifdef DSP_DEBUG_PL3
+WriteLog("DSPExecP: Pipeline status...\n");
+WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
+WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
+WriteLog(" --> Scoreboard: ");
+for(int i=0; i<32; i++)
+ WriteLog("%s ", scoreboard[i] ? "T" : "F");
+WriteLog("\n");
+#endif
+ // Stage 1a: Instruction fetch
+ pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
+ pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
+ pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
+ pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
+ if (pipeline[plPtrRead].opcode == 38)
+ pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
+ | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
+#ifdef DSP_DEBUG_PL3
+WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
+WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
+WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
+WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
+#endif
+ // Stage 1b: Read registers
+ if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
+ || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
+ // We have a hit in the scoreboard, so we have to stall the pipeline...
+#ifdef DSP_DEBUG_PL3
+{
+WriteLog(" --> Stalling pipeline: ");
+if (readAffected[pipeline[plPtrRead].opcode][0])
+ WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
+if (readAffected[pipeline[plPtrRead].opcode][1])
+ WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
+WriteLog("\n");
+#endif
+ pipeline[plPtrRead].opcode = PIPELINE_STALL;
+#ifdef DSP_DEBUG_PL3
+}
+#endif
+ else
+ {
+ pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
+ pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
+ pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
+
+ // Shouldn't we be more selective with the register scoreboarding?
+ // Yes, we should. !!! FIX !!! [Kinda DONE]
+ scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
+
+//Advance PC here??? Yes.
+ dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
+ }
+
+#ifdef DSP_DEBUG_PL3
+WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
+WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
+WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
+#endif
+ // Stage 2a: Execute
+ if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
+ {
+#ifdef DSP_DEBUG_PL3
+WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
+#endif
+ DSPOpcode[pipeline[plPtrExec].opcode]();
+ dsp_opcode_use[pipeline[plPtrExec].opcode]++;
+ cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
+ }
+ else
+ cycles--;
+
+#ifdef DSP_DEBUG_PL3
+WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
+WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
+WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
+WriteLog("\n");
+#endif
+ // Stage 2b: Write back register
+ if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
+ {
+ if (pipeline[plPtrExec].writebackRegister != 0xFF)
+ dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
+
+ if (affectsScoreboard[pipeline[plPtrExec].opcode])
+ scoreboard[pipeline[plPtrExec].operand2] = false;
+ }
+
+ // Push instructions through the pipeline...
+ plPtrRead = (++plPtrRead) & 0x03;
+ plPtrExec = (++plPtrExec) & 0x03;
+ }
+
+ dsp_in_exec--;
+}*/
+
+//
+// DSP pipelined opcode handlers
+//
+
+#define PRM pipeline[plPtrExec].reg1
+#define PRN pipeline[plPtrExec].reg2
+#define PIMM1 pipeline[plPtrExec].operand1
+#define PIMM2 pipeline[plPtrExec].operand2
+#define PRES pipeline[plPtrExec].result
+#define PWBR pipeline[plPtrExec].writebackRegister
+#define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
+//#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
+#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2))
+#define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
+
+static void DSP_abs(void)
+{
+#ifdef DSP_DIS_ABS
+ if (doDSPDis)
+ WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t _Rn = PRN;
+
+ if (_Rn == 0x80000000)
+ dsp_flag_n = 1;
+ else
+ {
+ dsp_flag_c = ((_Rn & 0x80000000) >> 31);
+ PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
+ CLR_ZN; SET_Z(PRES);
+ }
+#ifdef DSP_DIS_ABS
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_add(void)
+{
+#ifdef DSP_DIS_ADD
+ if (doDSPDis)
+ WriteLog("%06X: ADD R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t res = PRN + PRM;
+ SET_ZNC_ADD(PRN, PRM, res);
+ PRES = res;
+#ifdef DSP_DIS_ADD
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_addc(void)
+{
+#ifdef DSP_DIS_ADDC
+ if (doDSPDis)
+ WriteLog("%06X: ADDC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t res = PRN + PRM + dsp_flag_c;
+ uint32_t carry = dsp_flag_c;
+// SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
+ SET_ZNC_ADD(PRN + carry, PRM, res);
+// SET_ZNC_ADD(PRN, PRM + carry, res);
+ PRES = res;
+#ifdef DSP_DIS_ADDC
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_addq(void)
+{
+#ifdef DSP_DIS_ADDQ
+ if (doDSPDis)
+ WriteLog("%06X: ADDQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t r1 = dsp_convert_zero[PIMM1];
+ uint32_t res = PRN + r1;
+ CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
+ PRES = res;
+#ifdef DSP_DIS_ADDQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_addqmod(void)
+{
+#ifdef DSP_DIS_ADDQMOD
+ if (doDSPDis)
+ WriteLog("%06X: ADDQMOD #%u, R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_MOD=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_modulo);
+#endif
+ uint32_t r1 = dsp_convert_zero[PIMM1];
+ uint32_t r2 = PRN;
+ uint32_t res = r2 + r1;
+ res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
+ PRES = res;
+ SET_ZNC_ADD(r2, r1, res);
+#ifdef DSP_DIS_ADDQMOD
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_addqt(void)
+{
+#ifdef DSP_DIS_ADDQT
+ if (doDSPDis)
+ WriteLog("%06X: ADDQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = PRN + dsp_convert_zero[PIMM1];
+#ifdef DSP_DIS_ADDQT
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_and(void)
+{
+#ifdef DSP_DIS_AND
+ if (doDSPDis)
+ WriteLog("%06X: AND R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = PRN & PRM;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_AND
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_bclr(void)
+{
+#ifdef DSP_DIS_BCLR
+ if (doDSPDis)
+ WriteLog("%06X: BCLR #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = PRN & ~(1 << PIMM1);
+ SET_ZN(PRES);
+#ifdef DSP_DIS_BCLR
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_bset(void)
+{
+#ifdef DSP_DIS_BSET
+ if (doDSPDis)
+ WriteLog("%06X: BSET #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = PRN | (1 << PIMM1);
+ SET_ZN(PRES);
+#ifdef DSP_DIS_BSET
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_btst(void)
+{
+#ifdef DSP_DIS_BTST
+ if (doDSPDis)
+ WriteLog("%06X: BTST #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ dsp_flag_z = (~PRN >> PIMM1) & 1;
+ NO_WRITEBACK;
+#ifdef DSP_DIS_BTST
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+}
+
+static void DSP_cmp(void)
+{
+#ifdef DSP_DIS_CMP
+ if (doDSPDis)
+ WriteLog("%06X: CMP R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t res = PRN - PRM;
+ SET_ZNC_SUB(PRN, PRM, res);
+ NO_WRITEBACK;
+#ifdef DSP_DIS_CMP
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
+#endif
+}
+
+static void DSP_cmpq(void)
+{
+ static int32_t sqtable[32] =
+ { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 };
+#ifdef DSP_DIS_CMPQ
+ if (doDSPDis)
+ WriteLog("%06X: CMPQ #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, sqtable[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
+ uint32_t res = PRN - r1;
+ SET_ZNC_SUB(PRN, r1, res);
+ NO_WRITEBACK;
+#ifdef DSP_DIS_CMPQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
+#endif
+}
+
+static void DSP_div(void)
+{
+ uint32_t _Rm = PRM, _Rn = PRN;
+
+ if (_Rm)
+ {
+ if (dsp_div_control & 1)
+ {
+ dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
+ if (dsp_remain & 0x80000000)
+ dsp_remain -= _Rm;
+ PRES = (((uint64_t)_Rn) << 16) / _Rm;
+ }
+ else
+ {
+ dsp_remain = _Rn % _Rm;
+ if (dsp_remain & 0x80000000)
+ dsp_remain -= _Rm;
+ PRES = PRN / _Rm;
+ }
+ }
+ else
+ PRES = 0xFFFFFFFF;
+}
+
+static void DSP_imacn(void)
+{
+#ifdef DSP_DIS_IMACN
+ if (doDSPDis)
+ WriteLog("%06X: IMACN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ int32_t res = (int16_t)PRM * (int16_t)PRN;
+ dsp_acc += (int64_t)res;
+//Should we AND the result to fit into 40 bits here???
+ NO_WRITEBACK;
+#ifdef DSP_DIS_IMACN
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
+#endif
+}
+
+static void DSP_imult(void)
+{
+#ifdef DSP_DIS_IMULT
+ if (doDSPDis)
+ WriteLog("%06X: IMULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = (int16_t)PRN * (int16_t)PRM;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_IMULT
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_imultn(void)
+{
+#ifdef DSP_DIS_IMULTN
+ if (doDSPDis)
+ WriteLog("%06X: IMULTN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ // This is OK, since this multiply won't overflow 32 bits...
+ int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
+ dsp_acc = (int64_t)res;
+ SET_ZN(res);
+ NO_WRITEBACK;
+#ifdef DSP_DIS_IMULTN
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
+#endif
+}
+
+static void DSP_illegal(void)
+{
+#ifdef DSP_DIS_ILLEGAL
+ if (doDSPDis)
+ WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
+#endif
+ NO_WRITEBACK;
+}
+
+// There is a problem here with interrupt handlers the JUMP and JR instructions that
+// can cause trouble because an interrupt can occur *before* the instruction following the
+// jump can execute... !!! FIX !!!
+// This can probably be solved by judicious coding in the pipeline execution core...
+// And should be fixed now...
+static void DSP_jr(void)
+{
+#ifdef DSP_DIS_JR
+const char * condition[32] =
+{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
+ "c z", "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
+ "???", "???", "???", "F" };
+ if (doDSPDis)
+//How come this is always off by 2???
+ WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", DSP_PPC, condition[PIMM2], DSP_PPC+((PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1) * 2)+2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
+#endif
+ // KLUDGE: Used by BRANCH_CONDITION macro
+ uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
+
+ if (BRANCH_CONDITION(PIMM2))
+ {
+#ifdef DSP_DIS_JR
+ if (doDSPDis)
+ WriteLog("Branched!\n");
+#endif
+ int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
+//Account for pipeline effects...
+ uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
+//WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
+
+ // Now that we've branched, we have to make sure that the following instruction
+ // is executed atomically with this one and then flush the pipeline before setting
+ // the new PC.
+
+ // Step 1: Handle writebacks at stage 3 of pipeline
+/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFF)
+ dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
+
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ scoreboard[pipeline[plPtrWrite].operand2] = false;
+ }//*/
+ if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFF)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFE)
+ dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
+ else
+ {
+ if (pipeline[plPtrWrite].type == TYPE_BYTE)
+ JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else if (pipeline[plPtrWrite].type == TYPE_WORD)
+ JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else
+ JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ }
+ }
+
+#ifndef NEW_SCOREBOARD
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ scoreboard[pipeline[plPtrWrite].operand2] = false;
+#else
+//Yup, sequential MOVEQ # problem fixing (I hope!)...
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ if (scoreboard[pipeline[plPtrWrite].operand2])
+ scoreboard[pipeline[plPtrWrite].operand2]--;
+#endif
+ }
+
+ // Step 2: Push instruction through pipeline & execute following instruction
+ // NOTE: By putting our following instruction at stage 3 of the pipeline,
+ // we effectively handle the final push of the instruction through the
+ // pipeline when the new PC takes effect (since when we return, the
+ // pipeline code will be executing the writeback stage. If we reverse
+ // the execution order of the pipeline stages, this will no longer be
+ // the case!)...
+ pipeline[plPtrExec] = pipeline[plPtrRead];
+//This is BAD. We need to get that next opcode and execute it!
+//NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
+// remove this crap.
+ if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
+ {
+ uint16_t instruction = DSPReadWord(dsp_pc, DSP);
+ pipeline[plPtrExec].opcode = instruction >> 10;
+ pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
+ pipeline[plPtrExec].operand2 = instruction & 0x1F;
+ pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
+ pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
+ pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
+ }//*/
+ dsp_pc += 2; // For DSP_DIS_* accuracy
+ DSPOpcode[pipeline[plPtrExec].opcode]();
+ dsp_opcode_use[pipeline[plPtrExec].opcode]++;
+ pipeline[plPtrWrite] = pipeline[plPtrExec];
+
+ // Step 3: Flush pipeline & set new PC
+ pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
+ dsp_pc = newPC;
+ }
+ else
+#ifdef DSP_DIS_JR
+ {
+ if (doDSPDis)
+ WriteLog("Branch NOT taken.\n");
+#endif
+ NO_WRITEBACK;
+#ifdef DSP_DIS_JR
+ }
+#endif
+// WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
+}
+
+static void DSP_jump(void)
+{
+#ifdef DSP_DIS_JUMP
+const char * condition[32] =
+{ "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
+ "c z", "???", "???", "???", "???", "???", "???", "???", "???",
+ "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
+ "???", "???", "???", "F" };
+ if (doDSPDis)
+ WriteLog("%06X: JUMP %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", DSP_PPC, condition[PIMM2], PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM);
+#endif
+ // KLUDGE: Used by BRANCH_CONDITION macro
+ uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
+
+ if (BRANCH_CONDITION(PIMM2))
+ {
+#ifdef DSP_DIS_JUMP
+ if (doDSPDis)
+ WriteLog("Branched!\n");
+#endif
+ uint32_t PCSave = PRM;
+ // Now that we've branched, we have to make sure that the following instruction
+ // is executed atomically with this one and then flush the pipeline before setting
+ // the new PC.
+
+ // Step 1: Handle writebacks at stage 3 of pipeline
+/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFF)
+ dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
+
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ scoreboard[pipeline[plPtrWrite].operand2] = false;
+ }//*/
+ if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFF)
+ {
+ if (pipeline[plPtrWrite].writebackRegister != 0xFE)
+ dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
+ else
+ {
+ if (pipeline[plPtrWrite].type == TYPE_BYTE)
+ JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else if (pipeline[plPtrWrite].type == TYPE_WORD)
+ JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ else
+ JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
+ }
+ }
+
+#ifndef NEW_SCOREBOARD
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ scoreboard[pipeline[plPtrWrite].operand2] = false;
+#else
+//Yup, sequential MOVEQ # problem fixing (I hope!)...
+ if (affectsScoreboard[pipeline[plPtrWrite].opcode])
+ if (scoreboard[pipeline[plPtrWrite].operand2])
+ scoreboard[pipeline[plPtrWrite].operand2]--;
+#endif
+ }
+
+ // Step 2: Push instruction through pipeline & execute following instruction
+ // NOTE: By putting our following instruction at stage 3 of the pipeline,
+ // we effectively handle the final push of the instruction through the
+ // pipeline when the new PC takes effect (since when we return, the
+ // pipeline code will be executing the writeback stage. If we reverse
+ // the execution order of the pipeline stages, this will no longer be
+ // the case!)...
+ pipeline[plPtrExec] = pipeline[plPtrRead];
+//This is BAD. We need to get that next opcode and execute it!
+//Also, same problem in JR!
+//NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
+// remove this crap.
+ if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
+ {
+ uint16_t instruction = DSPReadWord(dsp_pc, DSP);
+ pipeline[plPtrExec].opcode = instruction >> 10;
+ pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
+ pipeline[plPtrExec].operand2 = instruction & 0x1F;
+ pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
+ pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
+ pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
+ }//*/
+ dsp_pc += 2; // For DSP_DIS_* accuracy
+ DSPOpcode[pipeline[plPtrExec].opcode]();
+ dsp_opcode_use[pipeline[plPtrExec].opcode]++;
+ pipeline[plPtrWrite] = pipeline[plPtrExec];
+
+ // Step 3: Flush pipeline & set new PC
+ pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
+ dsp_pc = PCSave;
+ }
+ else
+#ifdef DSP_DIS_JUMP
+ {
+ if (doDSPDis)
+ WriteLog("Branch NOT taken.\n");
+#endif
+ NO_WRITEBACK;
+#ifdef DSP_DIS_JUMP
+ }
+#endif
+}
+
+static void DSP_load(void)
+{
+#ifdef DSP_DIS_LOAD
+ if (doDSPDis)
+ WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
+#else
+ PRES = DSPReadLong(PRM, DSP);
+#endif
+#ifdef DSP_DIS_LOAD
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_loadb(void)
+{
+#ifdef DSP_DIS_LOADB
+ if (doDSPDis)
+ WriteLog("%06X: LOADB (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+ PRES = DSPReadLong(PRM, DSP) & 0xFF;
+ else
+ PRES = JaguarReadByte(PRM, DSP);
+#ifdef DSP_DIS_LOADB
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_loadw(void)
+{
+#ifdef DSP_DIS_LOADW
+ if (doDSPDis)
+ WriteLog("%06X: LOADW (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+ PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
+ else
+ PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
+#else
+ if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+ PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
+ else
+ PRES = JaguarReadWord(PRM, DSP);
+#endif
+#ifdef DSP_DIS_LOADW
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_load_r14_i(void)
+{
+#ifdef DSP_DIS_LOAD14I
+ if (doDSPDis)
+ WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1] << 2, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[PIMM1] << 2, dsp_reg[14]+(dsp_convert_zero[PIMM1] << 2), PIMM2, PRN);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
+#else
+ PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
+#endif
+#ifdef DSP_DIS_LOAD14I
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_load_r14_r(void)
+{
+#ifdef DSP_DIS_LOAD14R
+ if (doDSPDis)
+ WriteLog("%06X: LOAD (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM+dsp_reg[14], PIMM2, PRES);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
+#else
+ PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
+#endif
+#ifdef DSP_DIS_LOAD14R
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_load_r15_i(void)
+{
+#ifdef DSP_DIS_LOAD15I
+ if (doDSPDis)
+ WriteLog("%06X: LOAD (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1] << 2, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[PIMM1] << 2, dsp_reg[15]+(dsp_convert_zero[PIMM1] << 2), PIMM2, PRN);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
+#else
+ PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
+#endif
+#ifdef DSP_DIS_LOAD15I
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_load_r15_r(void)
+{
+#ifdef DSP_DIS_LOAD15R
+ if (doDSPDis)
+ WriteLog("%06X: LOAD (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM+dsp_reg[15], PIMM2, PRN);
+#endif
+#ifdef DSP_CORRECT_ALIGNMENT
+ PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
+#else
+ PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
+#endif
+#ifdef DSP_DIS_LOAD15R
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_mirror(void)
+{
+ uint32_t r1 = PRN;
+ PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
+ SET_ZN(PRES);
+}
+
+static void DSP_mmult(void)
+{
+ int count = dsp_matrix_control&0x0f;
+ uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
+ int64_t accum = 0;
+ uint32_t res;
+
+ if (!(dsp_matrix_control & 0x10))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ int16_t a;
+ if (i&0x01)
+ a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
+ else
+ a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
+ int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
+ accum += a*b;
+ addr += 4;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < count; i++)
+ {
+ int16_t a;
+ if (i&0x01)
+ a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
+ else
+ a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
+ int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
+ accum += a*b;
+ addr += 4 * count;
+ }
+ }
+
+ PRES = res = (int32_t)accum;
+ // carry flag to do
+//NOTE: The flags are set based upon the last add/multiply done...
+ SET_ZN(PRES);
+}
+
+static void DSP_move(void)
+{
+#ifdef DSP_DIS_MOVE
+ if (doDSPDis)
+ WriteLog("%06X: MOVE R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = PRM;
+#ifdef DSP_DIS_MOVE
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_movefa(void)
+{
+#ifdef DSP_DIS_MOVEFA
+ if (doDSPDis)
+// WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, ALTERNATE_RM, PIMM2, PRN);
+ WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, dsp_alternate_reg[PIMM1], PIMM2, PRN);
+#endif
+// PRES = ALTERNATE_RM;
+ PRES = dsp_alternate_reg[PIMM1];
+#ifdef DSP_DIS_MOVEFA
+ if (doDSPDis)
+// WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, ALTERNATE_RM, PIMM2, PRN);
+ WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, dsp_alternate_reg[PIMM1], PIMM2, PRES);
+#endif
+}
+
+static void DSP_movei(void)
+{
+#ifdef DSP_DIS_MOVEI
+ if (doDSPDis)
+ WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PRES, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+// // This instruction is followed by 32-bit value in LSW / MSW format...
+// PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
+// dsp_pc += 4;
+#ifdef DSP_DIS_MOVEI
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_movepc(void)
+{
+#ifdef DSP_DIS_MOVEPC
+ if (doDSPDis)
+ WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+//Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
+// PRES = dsp_pc - 2;
+//Account for pipeline effects...
+ PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
+#ifdef DSP_DIS_MOVEPC
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_moveq(void)
+{
+#ifdef DSP_DIS_MOVEQ
+ if (doDSPDis)
+ WriteLog("%06X: MOVEQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = PIMM1;
+#ifdef DSP_DIS_MOVEQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_moveta(void)
+{
+#ifdef DSP_DIS_MOVETA
+ if (doDSPDis)
+// WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, ALTERNATE_RN);
+ WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, dsp_alternate_reg[PIMM2]);
+#endif
+// ALTERNATE_RN = PRM;
+ dsp_alternate_reg[PIMM2] = PRM;
+ NO_WRITEBACK;
+#ifdef DSP_DIS_MOVETA
+ if (doDSPDis)
+// WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, ALTERNATE_RN);
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, dsp_alternate_reg[PIMM2]);
+#endif
+}
+
+static void DSP_mtoi(void)
+{
+ PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
+ SET_ZN(PRES);
+}
+
+static void DSP_mult(void)
+{
+#ifdef DSP_DIS_MULT
+ if (doDSPDis)
+ WriteLog("%06X: MULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = (uint16_t)PRM * (uint16_t)PRN;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_MULT
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_neg(void)
+{
+#ifdef DSP_DIS_NEG
+ if (doDSPDis)
+ WriteLog("%06X: NEG R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t res = -PRN;
+ SET_ZNC_SUB(0, PRN, res);
+ PRES = res;
+#ifdef DSP_DIS_NEG
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_nop(void)
+{
+#ifdef DSP_DIS_NOP
+ if (doDSPDis)
+ WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
+#endif
+ NO_WRITEBACK;
+}
+
+static void DSP_normi(void)
+{
+ uint32_t _Rm = PRM;
+ uint32_t res = 0;
+
+ if (_Rm)
+ {
+ while ((_Rm & 0xffc00000) == 0)
+ {
+ _Rm <<= 1;
+ res--;
+ }
+ while ((_Rm & 0xff800000) != 0)
+ {
+ _Rm >>= 1;
+ res++;
+ }
+ }
+ PRES = res;
+ SET_ZN(PRES);
+}
+
+static void DSP_not(void)
+{
+#ifdef DSP_DIS_NOT
+ if (doDSPDis)
+ WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = ~PRN;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_NOT
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_or(void)
+{
+#ifdef DSP_DIS_OR
+ if (doDSPDis)
+ WriteLog("%06X: OR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = PRN | PRM;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_OR
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_resmac(void)
+{
+#ifdef DSP_DIS_RESMAC
+ if (doDSPDis)
+ WriteLog("%06X: RESMAC R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_ACC=%02X%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
+#endif
+ PRES = (uint32_t)dsp_acc;
+#ifdef DSP_DIS_RESMAC
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+}
+
+static void DSP_ror(void)
+{
+#ifdef DSP_DIS_ROR
+ if (doDSPDis)
+ WriteLog("%06X: ROR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t r1 = PRM & 0x1F;
+ uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
+ SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
+ PRES = res;
+#ifdef DSP_DIS_ROR
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_rorq(void)
+{
+#ifdef DSP_DIS_RORQ
+ if (doDSPDis)
+ WriteLog("%06X: RORQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
+ uint32_t r2 = PRN;
+ uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
+ PRES = res;
+ SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
+#ifdef DSP_DIS_RORQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_sat16s(void)
+{
+ int32_t r2 = PRN;
+ uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
+ PRES = res;
+ SET_ZN(res);
+}
+
+static void DSP_sat32s(void)
+{
+ int32_t r2 = (uint32_t)PRN;
+ int32_t temp = dsp_acc >> 32;
+ uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
+ PRES = res;
+ SET_ZN(res);
+}
+
+static void DSP_sh(void)
+{
+ int32_t sRm = (int32_t)PRM;
+ uint32_t _Rn = PRN;
+
+ if (sRm < 0)
+ {
+ uint32_t shift = -sRm;
+
+ if (shift >= 32)
+ shift = 32;
+
+ dsp_flag_c = (_Rn & 0x80000000) >> 31;
+
+ while (shift)
+ {
+ _Rn <<= 1;
+ shift--;
+ }
+ }
+ else
+ {
+ uint32_t shift = sRm;
+
+ if (shift >= 32)
+ shift = 32;
+
+ dsp_flag_c = _Rn & 0x1;
+
+ while (shift)
+ {
+ _Rn >>= 1;
+ shift--;
+ }
+ }
+
+ PRES = _Rn;
+ SET_ZN(PRES);
+}
+
+static void DSP_sha(void)
+{
+ int32_t sRm = (int32_t)PRM;
+ uint32_t _Rn = PRN;
+
+ if (sRm < 0)
+ {
+ uint32_t shift = -sRm;
+
+ if (shift >= 32)
+ shift = 32;
+
+ dsp_flag_c = (_Rn & 0x80000000) >> 31;
+
+ while (shift)
+ {
+ _Rn <<= 1;
+ shift--;
+ }
+ }
+ else
+ {
+ uint32_t shift = sRm;
+
+ if (shift >= 32)
+ shift = 32;
+
+ dsp_flag_c = _Rn & 0x1;
+
+ while (shift)
+ {
+ _Rn = ((int32_t)_Rn) >> 1;
+ shift--;
+ }
+ }
+
+ PRES = _Rn;
+ SET_ZN(PRES);
+}
+
+static void DSP_sharq(void)
+{
+#ifdef DSP_DIS_SHARQ
+ if (doDSPDis)
+ WriteLog("%06X: SHARQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
+ SET_ZN(res); dsp_flag_c = PRN & 0x01;
+ PRES = res;
+#ifdef DSP_DIS_SHARQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_shlq(void)
+{
+#ifdef DSP_DIS_SHLQ
+ if (doDSPDis)
+ WriteLog("%06X: SHLQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, 32 - PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ int32_t r1 = 32 - PIMM1;
+ uint32_t res = PRN << r1;
+ SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
+ PRES = res;
+#ifdef DSP_DIS_SHLQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_shrq(void)
+{
+#ifdef DSP_DIS_SHRQ
+ if (doDSPDis)
+ WriteLog("%06X: SHRQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ int32_t r1 = dsp_convert_zero[PIMM1];
+ uint32_t res = PRN >> r1;
+ SET_ZN(res); dsp_flag_c = PRN & 1;
+ PRES = res;
+#ifdef DSP_DIS_SHRQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_store(void)
+{
+#ifdef DSP_DIS_STORE
+ if (doDSPDis)
+ WriteLog("%06X: STORE R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM);
+#endif
+// DSPWriteLong(PRM, PRN, DSP);
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
+#else
+ pipeline[plPtrExec].address = PRM;
+#endif
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ WRITEBACK_ADDR;
+}
+
+static void DSP_storeb(void)
+{
+#ifdef DSP_DIS_STOREB
+ if (doDSPDis)
+ WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM);
+#endif
+// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+// DSPWriteLong(PRM, PRN & 0xFF, DSP);
+// else
+// JaguarWriteByte(PRM, PRN, DSP);
+//
+// NO_WRITEBACK;
+ pipeline[plPtrExec].address = PRM;
+
+ if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+ {
+ pipeline[plPtrExec].value = PRN & 0xFF;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ }
+ else
+ {
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_BYTE;
+ }
+
+ WRITEBACK_ADDR;
+}
+
+static void DSP_storew(void)
+{
+#ifdef DSP_DIS_STOREW
+ if (doDSPDis)
+ WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", DSP_PPC, PIMM2, PIMM1, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, PIMM1, PRM);
+#endif
+// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+// DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
+// else
+// JaguarWriteWord(PRM, PRN, DSP);
+//
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
+#else
+ pipeline[plPtrExec].address = PRM;
+#endif
+
+ if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
+ {
+ pipeline[plPtrExec].value = PRN & 0xFFFF;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ }
+ else
+ {
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_WORD;
+ }
+ WRITEBACK_ADDR;
+}
+
+static void DSP_store_r14_i(void)
+{
+#ifdef DSP_DIS_STORE14I
+ if (doDSPDis)
+ WriteLog("%06X: STORE R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", DSP_PPC, PIMM2, dsp_convert_zero[PIMM1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_convert_zero[PIMM1] << 2, dsp_reg[14]+(dsp_convert_zero[PIMM1] << 2));
+#endif
+// DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
+#else
+ pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
+#endif
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ WRITEBACK_ADDR;
+}
+
+static void DSP_store_r14_r(void)
+{
+// DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
+#else
+ pipeline[plPtrExec].address = dsp_reg[14] + PRM;
+#endif
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ WRITEBACK_ADDR;
+}
+
+static void DSP_store_r15_i(void)
+{
+#ifdef DSP_DIS_STORE15I
+ if (doDSPDis)
+ WriteLog("%06X: STORE R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", DSP_PPC, PIMM2, dsp_convert_zero[PIMM1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN, dsp_convert_zero[PIMM1] << 2, dsp_reg[15]+(dsp_convert_zero[PIMM1] << 2));
+#endif
+// DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
+#else
+ pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
+#endif
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ WRITEBACK_ADDR;
+}
+
+static void DSP_store_r15_r(void)
+{
+// DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
+// NO_WRITEBACK;
+#ifdef DSP_CORRECT_ALIGNMENT_STORE
+ pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
+#else
+ pipeline[plPtrExec].address = dsp_reg[15] + PRM;
+#endif
+ pipeline[plPtrExec].value = PRN;
+ pipeline[plPtrExec].type = TYPE_DWORD;
+ WRITEBACK_ADDR;
+}
+
+static void DSP_sub(void)
+{
+#ifdef DSP_DIS_SUB
+ if (doDSPDis)
+ WriteLog("%06X: SUB R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t res = PRN - PRM;
+ SET_ZNC_SUB(PRN, PRM, res);
+ PRES = res;
+#ifdef DSP_DIS_SUB
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_subc(void)
+{
+#ifdef DSP_DIS_SUBC
+ if (doDSPDis)
+ WriteLog("%06X: SUBC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ uint32_t res = PRN - PRM - dsp_flag_c;
+ uint32_t borrow = dsp_flag_c;
+ SET_ZNC_SUB(PRN - borrow, PRM, res);
+ PRES = res;
+#ifdef DSP_DIS_SUBC
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif
+}
+
+static void DSP_subq(void)
+{
+#ifdef DSP_DIS_SUBQ
+ if (doDSPDis)
+ WriteLog("%06X: SUBQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ uint32_t r1 = dsp_convert_zero[PIMM1];
+ uint32_t res = PRN - r1;
+ SET_ZNC_SUB(PRN, r1, res);
+ PRES = res;
+#ifdef DSP_DIS_SUBQ
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_subqmod(void)
+{
+ uint32_t r1 = dsp_convert_zero[PIMM1];
+ uint32_t r2 = PRN;
+ uint32_t res = r2 - r1;
+ res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
+ PRES = res;
+ SET_ZNC_SUB(r2, r1, res);
+}
+
+static void DSP_subqt(void)
+{
+#ifdef DSP_DIS_SUBQT
+ if (doDSPDis)
+ WriteLog("%06X: SUBQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, dsp_convert_zero[PIMM1], PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
+#endif
+ PRES = PRN - dsp_convert_zero[PIMM1];
+#ifdef DSP_DIS_SUBQT
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
+#endif
+}
+
+static void DSP_xor(void)
+{
+#ifdef DSP_DIS_XOR
+ if (doDSPDis)
+ WriteLog("%06X: XOR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
+#endif
+ PRES = PRN ^ PRM;
+ SET_ZN(PRES);
+#ifdef DSP_DIS_XOR
+ if (doDSPDis)
+ WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
+#endif