]> Shamusworld >> Repos - virtualjaguar/blob - src/dsp.cpp
Various changes to improve code readability, added mouse hiding.
[virtualjaguar] / src / dsp.cpp
1 //
2 // DSP core
3 //
4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James Hammons
7 // (C) 2010 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -------------------------------------------------------------
13 // JLH  01/16/2010  Created this log ;-)
14 // JLH  11/26/2011  Added fixes for LOAD/STORE alignment issues
15 //
16
17 #include "dsp.h"
18
19 #include <SDL.h>                                                                // Used only for SDL_GetTicks...
20 #include <stdlib.h>
21 #include "dac.h"
22 #include "gpu.h"
23 #include "jagdasm.h"
24 #include "jaguar.h"
25 #include "jerry.h"
26 #include "log.h"
27 #include "m68000/m68kinterface.h"
28 //#include "memory.h"
29
30
31 // Seems alignment in loads & stores was off...
32 #define DSP_CORRECT_ALIGNMENT
33 //#define DSP_CORRECT_ALIGNMENT_STORE
34
35 //#define DSP_DEBUG
36 //#define DSP_DEBUG_IRQ
37 //#define DSP_DEBUG_PL2
38 //#define DSP_DEBUG_STALL
39 //#define DSP_DEBUG_CC
40 #define NEW_SCOREBOARD
41
42 // Disassembly definitions
43
44 #if 0
45 #define DSP_DIS_ABS
46 #define DSP_DIS_ADD
47 #define DSP_DIS_ADDC
48 #define DSP_DIS_ADDQ
49 #define DSP_DIS_ADDQMOD
50 #define DSP_DIS_ADDQT
51 #define DSP_DIS_AND
52 #define DSP_DIS_BCLR
53 #define DSP_DIS_BSET
54 #define DSP_DIS_BTST
55 #define DSP_DIS_CMP
56 #define DSP_DIS_CMPQ
57 #define DSP_DIS_IMACN
58 #define DSP_DIS_IMULT
59 #define DSP_DIS_IMULTN
60 #define DSP_DIS_ILLEGAL
61 #define DSP_DIS_JR
62 #define DSP_DIS_JUMP
63 #define DSP_DIS_LOAD
64 #define DSP_DIS_LOAD14I
65 #define DSP_DIS_LOAD14R
66 #define DSP_DIS_LOAD15I
67 #define DSP_DIS_LOAD15R
68 #define DSP_DIS_LOADB
69 #define DSP_DIS_LOADW
70 #define DSP_DIS_MOVE
71 #define DSP_DIS_MOVEI
72 #define DSP_DIS_MOVEQ
73 #define DSP_DIS_MOVEFA
74 #define DSP_DIS_MOVEPC                                                          // Pipeline only!
75 #define DSP_DIS_MOVETA
76 #define DSP_DIS_MULT
77 #define DSP_DIS_NEG
78 #define DSP_DIS_NOP
79 #define DSP_DIS_NOT
80 #define DSP_DIS_OR
81 #define DSP_DIS_RESMAC
82 #define DSP_DIS_ROR
83 #define DSP_DIS_RORQ
84 #define DSP_DIS_SHARQ
85 #define DSP_DIS_SHLQ
86 #define DSP_DIS_SHRQ
87 #define DSP_DIS_STORE
88 #define DSP_DIS_STORE14I
89 #define DSP_DIS_STORE15I
90 #define DSP_DIS_STOREB
91 #define DSP_DIS_STOREW
92 #define DSP_DIS_SUB
93 #define DSP_DIS_SUBC
94 #define DSP_DIS_SUBQ
95 #define DSP_DIS_SUBQT
96 #define DSP_DIS_XOR
97 //*/
98 bool doDSPDis = false;
99 //bool doDSPDis = true;
100 #endif
101 bool doDSPDis = false;
102 //#define DSP_DIS_JR
103 //#define DSP_DIS_JUMP
104
105 /*
106 No dis yet:
107 +       subqt 4560
108 +       mult 1472
109 +       imultn 395024
110 +       resmac 395024
111 +       imacn 395024
112 +       addqmod 93328
113
114 dsp opcodes use:
115 +       add 1672497
116 +       addq 4366576
117 +       addqt 44405640
118 +       sub 94833
119 +       subq 111769
120 +       and 47416
121 +       btst 94521
122 +       bset 2277826
123 +       bclr 3223372
124 +       mult 47104
125 +       imult 237080
126 +       shlq 365464
127 +       shrq 141624
128 +       sharq 318368
129 +       cmp 45175078
130 +       move 2238994
131 +       moveq 335305
132 +       moveta 19
133 +       movefa 47406440
134 +       movei 1920664
135 +       loadb 94832
136 +       load 4031281
137 +       load_r15_indexed 284500
138 +       store 2161732
139 +       store_r15_indexed 47416
140 +       jump 3872424
141 +       jr 46386967
142 +       nop 3300029
143 +       load_r14_ri 1229448
144 */
145
146 // Pipeline structures
147
148 const bool affectsScoreboard[64] =
149 {
150          true,  true,  true,  true,
151          true,  true,  true,  true,
152          true,  true,  true,  true,
153          true, false,  true,  true,
154
155          true,  true, false,  true,
156         false,  true,  true,  true,
157          true,  true,  true,  true,
158          true,  true, false, false,
159
160          true,  true,  true,  true,
161         false,  true,  true,  true,
162          true,  true,  true,  true,
163          true, false, false, false,
164
165          true, false, false,  true,
166         false, false,  true,  true,
167          true, false,  true,  true,
168         false, false, false,  true
169 };
170
171 struct PipelineStage
172 {
173         uint16_t instruction;
174         uint8_t opcode, operand1, operand2;
175         uint32_t reg1, reg2, areg1, areg2;
176         uint32_t result;
177         uint8_t writebackRegister;
178         // General memory store...
179         uint32_t address;
180         uint32_t value;
181         uint8_t type;
182 };
183
184 #define TYPE_BYTE                       0
185 #define TYPE_WORD                       1
186 #define TYPE_DWORD                      2
187 #define PIPELINE_STALL          64                                              // Set to # of opcodes + 1
188 #ifndef NEW_SCOREBOARD
189 bool scoreboard[32];
190 #else
191 uint8_t scoreboard[32];
192 #endif
193 uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
194 PipelineStage pipeline[4];
195 bool IMASKCleared = false;
196
197 // DSP flags (old--have to get rid of this crap)
198
199 #define CINT0FLAG                       0x00200
200 #define CINT1FLAG                       0x00400
201 #define CINT2FLAG                       0x00800
202 #define CINT3FLAG                       0x01000
203 #define CINT4FLAG                       0x02000
204 #define CINT04FLAGS                     (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
205 #define CINT5FLAG                       0x20000         /* DSP only */
206
207 // DSP_FLAGS bits
208
209 #define ZERO_FLAG               0x00001
210 #define CARRY_FLAG              0x00002
211 #define NEGA_FLAG               0x00004
212 #define IMASK                   0x00008
213 #define INT_ENA0                0x00010
214 #define INT_ENA1                0x00020
215 #define INT_ENA2                0x00040
216 #define INT_ENA3                0x00080
217 #define INT_ENA4                0x00100
218 #define INT_CLR0                0x00200
219 #define INT_CLR1                0x00400
220 #define INT_CLR2                0x00800
221 #define INT_CLR3                0x01000
222 #define INT_CLR4                0x02000
223 #define REGPAGE                 0x04000
224 #define DMAEN                   0x08000
225 #define INT_ENA5                0x10000
226 #define INT_CLR5                0x20000
227
228 // DSP_CTRL bits
229
230 #define DSPGO                   0x00001
231 #define CPUINT                  0x00002
232 #define DSPINT0                 0x00004
233 #define SINGLE_STEP             0x00008
234 #define SINGLE_GO               0x00010
235 // Bit 5 is unused!
236 #define INT_LAT0                0x00040
237 #define INT_LAT1                0x00080
238 #define INT_LAT2                0x00100
239 #define INT_LAT3                0x00200
240 #define INT_LAT4                0x00400
241 #define BUS_HOG                 0x00800
242 #define VERSION                 0x0F000
243 #define INT_LAT5                0x10000
244
245 extern uint32_t jaguar_mainRom_crc32;
246
247 // Is opcode 62 *really* a NOP? Seems like it...
248 static void dsp_opcode_abs(void);
249 static void dsp_opcode_add(void);
250 static void dsp_opcode_addc(void);
251 static void dsp_opcode_addq(void);
252 static void dsp_opcode_addqmod(void);
253 static void dsp_opcode_addqt(void);
254 static void dsp_opcode_and(void);
255 static void dsp_opcode_bclr(void);
256 static void dsp_opcode_bset(void);
257 static void dsp_opcode_btst(void);
258 static void dsp_opcode_cmp(void);
259 static void dsp_opcode_cmpq(void);
260 static void dsp_opcode_div(void);
261 static void dsp_opcode_imacn(void);
262 static void dsp_opcode_imult(void);
263 static void dsp_opcode_imultn(void);
264 static void dsp_opcode_jr(void);
265 static void dsp_opcode_jump(void);
266 static void dsp_opcode_load(void);
267 static void dsp_opcode_loadb(void);
268 static void dsp_opcode_loadw(void);
269 static void dsp_opcode_load_r14_indexed(void);
270 static void dsp_opcode_load_r14_ri(void);
271 static void dsp_opcode_load_r15_indexed(void);
272 static void dsp_opcode_load_r15_ri(void);
273 static void dsp_opcode_mirror(void);
274 static void dsp_opcode_mmult(void);
275 static void dsp_opcode_move(void);
276 static void dsp_opcode_movei(void);
277 static void dsp_opcode_movefa(void);
278 static void dsp_opcode_move_pc(void);
279 static void dsp_opcode_moveq(void);
280 static void dsp_opcode_moveta(void);
281 static void dsp_opcode_mtoi(void);
282 static void dsp_opcode_mult(void);
283 static void dsp_opcode_neg(void);
284 static void dsp_opcode_nop(void);
285 static void dsp_opcode_normi(void);
286 static void dsp_opcode_not(void);
287 static void dsp_opcode_or(void);
288 static void dsp_opcode_resmac(void);
289 static void dsp_opcode_ror(void);
290 static void dsp_opcode_rorq(void);
291 static void dsp_opcode_xor(void);
292 static void dsp_opcode_sat16s(void);
293 static void dsp_opcode_sat32s(void);
294 static void dsp_opcode_sh(void);
295 static void dsp_opcode_sha(void);
296 static void dsp_opcode_sharq(void);
297 static void dsp_opcode_shlq(void);
298 static void dsp_opcode_shrq(void);
299 static void dsp_opcode_store(void);
300 static void dsp_opcode_storeb(void);
301 static void dsp_opcode_storew(void);
302 static void dsp_opcode_store_r14_indexed(void);
303 static void dsp_opcode_store_r14_ri(void);
304 static void dsp_opcode_store_r15_indexed(void);
305 static void dsp_opcode_store_r15_ri(void);
306 static void dsp_opcode_sub(void);
307 static void dsp_opcode_subc(void);
308 static void dsp_opcode_subq(void);
309 static void dsp_opcode_subqmod(void);
310 static void dsp_opcode_subqt(void);
311 static void dsp_opcode_illegal(void);
312
313 /*uint8_t dsp_opcode_cycles[64] =
314 {
315         3,  3,  3,  3,  3,  3,  3,  3,
316         3,  3,  3,  3,  3,  3,  3,  3,
317         3,  3,  1,  3,  1, 18,  3,  3,
318         3,  3,  3,  3,  3,  3,  3,  3,
319         3,  3,  2,  2,  2,  2,  3,  4,
320         5,  4,  5,  6,  6,  1,  1,  1,
321         1,  2,  2,  2,  1,  1,  9,  3,
322         3,  1,  6,  6,  2,  2,  3,  3
323 };//*/
324 //Here's a QnD kludge...
325 //This is wrong, wrong, WRONG, but it seems to work for the time being...
326 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
327 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
328 // Yup, without cheating like this, the sound in things like Rayman, FACTS, &
329 // Tripper Getem get starved for time and sounds like crap. So we have to figure
330 // out how to fix that. :-/
331 uint8_t dsp_opcode_cycles[64] =
332 {
333         1,  1,  1,  1,  1,  1,  1,  1,
334         1,  1,  1,  1,  1,  1,  1,  1,
335         1,  1,  1,  1,  1,  9,  1,  1,
336         1,  1,  1,  1,  1,  1,  1,  1,
337         1,  1,  1,  1,  1,  1,  1,  2,
338         2,  2,  2,  3,  3,  1,  1,  1,
339         1,  1,  1,  1,  1,  1,  4,  1,
340         1,  1,  3,  3,  1,  1,  1,  1
341 };//*/
342
343 void (* dsp_opcode[64])() =
344 {
345         dsp_opcode_add,                                 dsp_opcode_addc,                                dsp_opcode_addq,                                dsp_opcode_addqt,
346         dsp_opcode_sub,                                 dsp_opcode_subc,                                dsp_opcode_subq,                                dsp_opcode_subqt,
347         dsp_opcode_neg,                                 dsp_opcode_and,                                 dsp_opcode_or,                                  dsp_opcode_xor,
348         dsp_opcode_not,                                 dsp_opcode_btst,                                dsp_opcode_bset,                                dsp_opcode_bclr,
349         dsp_opcode_mult,                                dsp_opcode_imult,                               dsp_opcode_imultn,                              dsp_opcode_resmac,
350         dsp_opcode_imacn,                               dsp_opcode_div,                                 dsp_opcode_abs,                                 dsp_opcode_sh,
351         dsp_opcode_shlq,                                dsp_opcode_shrq,                                dsp_opcode_sha,                                 dsp_opcode_sharq,
352         dsp_opcode_ror,                                 dsp_opcode_rorq,                                dsp_opcode_cmp,                                 dsp_opcode_cmpq,
353         dsp_opcode_subqmod,                             dsp_opcode_sat16s,                              dsp_opcode_move,                                dsp_opcode_moveq,
354         dsp_opcode_moveta,                              dsp_opcode_movefa,                              dsp_opcode_movei,                               dsp_opcode_loadb,
355         dsp_opcode_loadw,                               dsp_opcode_load,                                dsp_opcode_sat32s,                              dsp_opcode_load_r14_indexed,
356         dsp_opcode_load_r15_indexed,    dsp_opcode_storeb,                              dsp_opcode_storew,                              dsp_opcode_store,
357         dsp_opcode_mirror,                              dsp_opcode_store_r14_indexed,   dsp_opcode_store_r15_indexed,   dsp_opcode_move_pc,
358         dsp_opcode_jump,                                dsp_opcode_jr,                                  dsp_opcode_mmult,                               dsp_opcode_mtoi,
359         dsp_opcode_normi,                               dsp_opcode_nop,                                 dsp_opcode_load_r14_ri,                 dsp_opcode_load_r15_ri,
360         dsp_opcode_store_r14_ri,                dsp_opcode_store_r15_ri,                dsp_opcode_illegal,                             dsp_opcode_addqmod,
361 };
362
363 uint32_t dsp_opcode_use[65];
364
365 const char * dsp_opcode_str[65]=
366 {
367         "add",                          "addc",                         "addq",                         "addqt",
368         "sub",                          "subc",                         "subq",                         "subqt",
369         "neg",                          "and",                          "or",                           "xor",
370         "not",                          "btst",                         "bset",                         "bclr",
371         "mult",                         "imult",                        "imultn",                       "resmac",
372         "imacn",                        "div",                          "abs",                          "sh",
373         "shlq",                         "shrq",                         "sha",                          "sharq",
374         "ror",                          "rorq",                         "cmp",                          "cmpq",
375         "subqmod",                      "sat16s",                       "move",                         "moveq",
376         "moveta",                       "movefa",                       "movei",                        "loadb",
377         "loadw",                        "load",                         "sat32s",                       "load_r14_indexed",
378         "load_r15_indexed",     "storeb",                       "storew",                       "store",
379         "mirror",                       "store_r14_indexed","store_r15_indexed","move_pc",
380         "jump",                         "jr",                           "mmult",                        "mtoi",
381         "normi",                        "nop",                          "load_r14_ri",          "load_r15_ri",
382         "store_r14_ri",         "store_r15_ri",         "illegal",                      "addqmod",
383         "STALL"
384 };
385
386 uint32_t dsp_pc;
387 static uint64_t dsp_acc;                                                                // 40 bit register, NOT 32!
388 static uint32_t dsp_remain;
389 static uint32_t dsp_modulo;
390 static uint32_t dsp_flags;
391 static uint32_t dsp_matrix_control;
392 static uint32_t dsp_pointer_to_matrix;
393 static uint32_t dsp_data_organization;
394 uint32_t dsp_control;
395 static uint32_t dsp_div_control;
396 static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
397 static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
398 uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
399
400 static uint32_t dsp_opcode_first_parameter;
401 static uint32_t dsp_opcode_second_parameter;
402
403 #define DSP_RUNNING                     (dsp_control & 0x01)
404
405 #define RM                                      dsp_reg[dsp_opcode_first_parameter]
406 #define RN                                      dsp_reg[dsp_opcode_second_parameter]
407 #define ALTERNATE_RM            dsp_alternate_reg[dsp_opcode_first_parameter]
408 #define ALTERNATE_RN            dsp_alternate_reg[dsp_opcode_second_parameter]
409 #define IMM_1                           dsp_opcode_first_parameter
410 #define IMM_2                           dsp_opcode_second_parameter
411
412 #define CLR_Z                           (dsp_flag_z = 0)
413 #define CLR_ZN                          (dsp_flag_z = dsp_flag_n = 0)
414 #define CLR_ZNC                         (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
415 #define SET_Z(r)                        (dsp_flag_z = ((r) == 0))
416 #define SET_N(r)                        (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
417 #define SET_C_ADD(a,b)          (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
418 #define SET_C_SUB(a,b)          (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
419 #define SET_ZN(r)                       SET_N(r); SET_Z(r)
420 #define SET_ZNC_ADD(a,b,r)      SET_N(r); SET_Z(r); SET_C_ADD(a,b)
421 #define SET_ZNC_SUB(a,b,r)      SET_N(r); SET_Z(r); SET_C_SUB(a,b)
422
423 uint32_t dsp_convert_zero[32] = {
424         32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
425         17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
426 };
427
428 uint8_t dsp_branch_condition_table[32 * 8];
429 static uint16_t mirror_table[65536];
430 static uint8_t dsp_ram_8[0x2000];
431
432 #define BRANCH_CONDITION(x)             dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
433
434 static uint32_t dsp_in_exec = 0;
435 static uint32_t dsp_releaseTimeSlice_flag = 0;
436
437 FILE * dsp_fp;
438
439 #ifdef DSP_DEBUG_CC
440 // Comparison core vars (used only for core comparison! :-)
441 static uint64_t count = 0;
442 static uint8_t ram1[0x2000], ram2[0x2000];
443 static uint32_t regs1[64], regs2[64];
444 static uint32_t ctrl1[14], ctrl2[14];
445 #endif
446
447 // Private function prototypes
448
449 void DSPDumpRegisters(void);
450 void DSPDumpDisassembly(void);
451 void FlushDSPPipeline(void);
452
453
454 void dsp_reset_stats(void)
455 {
456         for(int i=0; i<65; i++)
457                 dsp_opcode_use[i] = 0;
458 }
459
460 void DSPReleaseTimeslice(void)
461 {
462 //This does absolutely nothing!!! !!! FIX !!!
463         dsp_releaseTimeSlice_flag = 1;
464 }
465
466 void dsp_build_branch_condition_table(void)
467 {
468         // Fill in the mirror table
469         for(int i=0; i<65536; i++)
470         {
471                 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
472                         | ((i >> 11) & 0x0004) | ((i >> 9)  & 0x0008)
473                         | ((i >> 7)  & 0x0010) | ((i >> 5)  & 0x0020)
474                         | ((i >> 3)  & 0x0040) | ((i >> 1)  & 0x0080)
475                         | ((i << 1)  & 0x0100) | ((i << 3)  & 0x0200)
476                         | ((i << 5)  & 0x0400) | ((i << 7)  & 0x0800)
477                         | ((i << 9)  & 0x1000) | ((i << 11) & 0x2000)
478                         | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
479         }
480
481         // Fill in the condition table
482         for(int i=0; i<8; i++)
483         {
484                 for(int j=0; j<32; j++)
485                 {
486                         int result = 1;
487
488                         if ((j & 1) && (i & ZERO_FLAG))
489                                 result = 0;
490
491                         if ((j & 2) && (!(i & ZERO_FLAG)))
492                                 result = 0;
493
494                         if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
495                                 result = 0;
496
497                         if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
498                                 result = 0;
499
500                         dsp_branch_condition_table[i * 32 + j] = result;
501                 }
502         }
503 }
504
505 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
506 {
507         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
508                 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
509 // battlemorph
510 //      if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
511 //              return(0xffff);
512         // mutant penguin
513 /*      if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
514         {
515                 if (offset==0xF1CFE0)
516                         return(0xff);
517         }*/
518         if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
519                 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
520
521         if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
522         {
523                 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
524
525                 if ((offset&0x03)==0)
526                         return(data>>24);
527                 else
528                 if ((offset&0x03)==1)
529                         return((data>>16)&0xff);
530                 else
531                 if ((offset&0x03)==2)
532                         return((data>>8)&0xff);
533                 else
534                 if ((offset&0x03)==3)
535                         return(data&0xff);
536         }
537
538         return JaguarReadByte(offset, who);
539 }
540
541 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
542 {
543         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
544                 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
545         //???
546         offset &= 0xFFFFFFFE;
547
548         if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
549         {
550                 offset -= DSP_WORK_RAM_BASE;
551 /*              uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
552                 return data;*/
553                 return GET16(dsp_ram_8, offset);
554         }
555         else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
556         {
557                 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
558
559                 if (offset & 0x03)
560                         return data & 0xFFFF;
561                 else
562                         return data >> 16;
563         }
564
565         return JaguarReadWord(offset, who);
566 }
567
568 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
569 {
570         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
571                 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
572
573         // ??? WHY ???
574         offset &= 0xFFFFFFFC;
575 /*if (offset == 0xF1BCF4)
576 {
577         WriteLog("DSPReadLong: Reading from 0xF1BCF4... -> %08X [%02X %02X %02X %02X][%04X %04X]\n", GET32(dsp_ram_8, 0x0CF4), dsp_ram_8[0x0CF4], dsp_ram_8[0x0CF5], dsp_ram_8[0x0CF6], dsp_ram_8[0x0CF7], JaguarReadWord(0xF1BCF4, DSP), JaguarReadWord(0xF1BCF6, DSP));
578         DSPDumpDisassembly();
579 }*/
580         if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
581         {
582                 offset -= DSP_WORK_RAM_BASE;
583                 return GET32(dsp_ram_8, offset);
584         }
585 //NOTE: Didn't return DSP_ACCUM!!!
586 //Mebbe it's not 'spose to! Yes, it is!
587         if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
588         {
589                 offset &= 0x3F;
590                 switch (offset)
591                 {
592                 case 0x00:
593                         dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
594                         return dsp_flags & 0xFFFFC1FF;
595                 case 0x04: return dsp_matrix_control;
596                 case 0x08: return dsp_pointer_to_matrix;
597                 case 0x0C: return dsp_data_organization;
598                 case 0x10: return dsp_pc;
599                 case 0x14: return dsp_control;
600                 case 0x18: return dsp_modulo;
601                 case 0x1C: return dsp_remain;
602                 case 0x20:
603                         return (int32_t)((int8_t)(dsp_acc >> 32));      // Top 8 bits of 40-bit accumulator, sign extended
604                 }
605                 // unaligned long read-- !!! FIX !!!
606                 return 0xFFFFFFFF;
607         }
608
609         return JaguarReadLong(offset, who);
610 }
611
612 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
613 {
614         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
615                 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
616
617         if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
618         {
619                 offset -= DSP_WORK_RAM_BASE;
620                 dsp_ram_8[offset] = data;
621 //This is rather stupid! !!! FIX !!!
622 /*              if (dsp_in_exec == 0)
623                 {
624                         m68k_end_timeslice();
625                         dsp_releaseTimeslice();
626                 }*/
627                 return;
628         }
629         if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
630         {
631                 uint32_t reg = offset & 0x1C;
632                 int bytenum = offset & 0x03;
633
634                 if ((reg >= 0x1C) && (reg <= 0x1F))
635                         dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
636                 else
637                 {
638 //This looks funky. !!! FIX !!!
639                         uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
640                         bytenum = 3 - bytenum; // convention motorola !!!
641                         old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
642                         DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
643                 }
644                 return;
645         }
646 //      WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
647 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
648         JaguarWriteByte(offset, data, who);
649 }
650
651 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
652 {
653         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
654                 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
655         offset &= 0xFFFFFFFE;
656 /*if (offset == 0xF1BCF4)
657 {
658         WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
659 }*/
660 //      WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
661         if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
662         {
663 /*if (offset == 0xF1B2F4)
664 {
665         WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
666 }//*/
667                 offset -= DSP_WORK_RAM_BASE;
668                 dsp_ram_8[offset] = data >> 8;
669                 dsp_ram_8[offset+1] = data & 0xFF;
670 //This is rather stupid! !!! FIX !!!
671 /*              if (dsp_in_exec == 0)
672                 {
673 //                      WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
674                         m68k_end_timeslice();
675                         dsp_releaseTimeslice();
676                 }*/
677 //CC only!
678 #ifdef DSP_DEBUG_CC
679 SET16(ram1, offset, data),
680 SET16(ram2, offset, data);
681 #endif
682 //!!!!!!!!
683                 return;
684         }
685         else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
686         {
687                 if ((offset & 0x1C) == 0x1C)
688                 {
689                         if (offset & 0x03)
690                                 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
691                         else
692                                 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
693                 }
694                 else
695                 {
696                         uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
697
698                         if (offset & 0x03)
699                                 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
700                         else
701                                 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
702
703                         DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
704                 }
705
706                 return;
707         }
708
709         JaguarWriteWord(offset, data, who);
710 }
711
712 //bool badWrite = false;
713 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
714 {
715         if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
716                 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
717         // ??? WHY ???
718         offset &= 0xFFFFFFFC;
719 /*if (offset == 0xF1BCF4)
720 {
721         WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
722 }*/
723 //      WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
724         if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
725         {
726 /*if (offset == 0xF1BE2C)
727 {
728         WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
729 }//*/
730                 offset -= DSP_WORK_RAM_BASE;
731                 SET32(dsp_ram_8, offset, data);
732 //CC only!
733 #ifdef DSP_DEBUG_CC
734 SET32(ram1, offset, data),
735 SET32(ram2, offset, data);
736 #endif
737 //!!!!!!!!
738                 return;
739         }
740         else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
741         {
742                 offset &= 0x1F;
743                 switch (offset)
744                 {
745                 case 0x00:
746                 {
747 #ifdef DSP_DEBUG
748                         WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
749 #endif
750 //                      bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
751                         IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
752                         // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
753                         //       IRQ logic can set it. So we mask it out here to prevent problems...
754                         dsp_flags = data & (~IMASK);
755                         dsp_flag_z = dsp_flags & 0x01;
756                         dsp_flag_c = (dsp_flags >> 1) & 0x01;
757                         dsp_flag_n = (dsp_flags >> 2) & 0x01;
758                         DSPUpdateRegisterBanks();
759                         dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
760                         dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
761                         break;
762                 }
763                 case 0x04:
764                         dsp_matrix_control = data;
765                         break;
766                 case 0x08:
767                         // According to JTRM, only lines 2-11 are addressable, the rest being
768                         // hardwired to $F1Bxxx.
769                         dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
770                         break;
771                 case 0x0C:
772                         dsp_data_organization = data;
773                         break;
774                 case 0x10:
775                         dsp_pc = data;
776 #ifdef DSP_DEBUG
777                         WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
778 #endif
779 //CC only!
780 #ifdef DSP_DEBUG_CC
781 if (who != DSP)
782         ctrl1[0] = ctrl2[0] = data;
783 #endif
784 //!!!!!!!!
785                         break;
786                 case 0x14:
787                 {
788 //#ifdef DSP_DEBUG
789 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
790 //#endif
791                         bool wasRunning = DSP_RUNNING;
792 //                      uint32_t dsp_was_running = DSP_RUNNING;
793                         // Check for DSP -> CPU interrupt
794                         if (data & CPUINT)
795                         {
796 #ifdef DSP_DEBUG
797                                 WriteLog("DSP: DSP -> CPU interrupt\n");
798 #endif
799
800 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
801                                 if (JERRYIRQEnabled(IRQ2_DSP))
802                                 {
803                                         JERRYSetPendingIRQ(IRQ2_DSP);
804                                         DSPReleaseTimeslice();
805                                         m68k_set_irq(2);                        // Set 68000 IPL 2...
806                                 }
807                                 data &= ~CPUINT;
808                         }
809                         // Check for CPU -> DSP interrupt
810                         if (data & DSPINT0)
811                         {
812 #ifdef DSP_DEBUG
813                                 WriteLog("DSP: CPU -> DSP interrupt\n");
814 #endif
815                                 m68k_end_timeslice();
816                                 DSPReleaseTimeslice();
817                                 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
818                                 data &= ~DSPINT0;
819                         }
820                         // single stepping
821                         if (data & SINGLE_STEP)
822                         {
823 //                              WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
824                         }
825
826                         // Protect writes to VERSION and the interrupt latches...
827                         uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
828                         dsp_control = (dsp_control & mask) | (data & ~mask);
829 //CC only!
830 #ifdef DSP_DEBUG_CC
831 if (who != DSP)
832         ctrl1[8] = ctrl2[8] = dsp_control;
833 #endif
834 //!!!!!!!!
835
836                         // if dsp wasn't running but is now running
837                         // execute a few cycles
838 //This is just plain wrong, wrong, WRONG!
839 #ifndef DSP_SINGLE_STEPPING
840 /*                      if (!dsp_was_running && DSP_RUNNING)
841                         {
842                                 DSPExec(200);
843                         }*/
844 #else
845 //This is WRONG! !!! FIX !!!
846                         if (dsp_control & 0x18)
847                                 DSPExec(1);
848 #endif
849 #ifdef DSP_DEBUG
850 if (DSP_RUNNING)
851         WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
852 else
853         WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
854 WriteLog("\n");
855 #endif  // DSP_DEBUG
856 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
857 // !!! FIX !!! [DONE]
858                         if (DSP_RUNNING)
859                         {
860                                 if (who == M68K)
861                                         m68k_end_timeslice();
862                                 else if (who == DSP)
863                                         DSPReleaseTimeslice();
864
865                                 if (!wasRunning)
866                                         FlushDSPPipeline();
867 //DSPDumpDisassembly();
868                         }
869                         break;
870                 }
871                 case 0x18:
872 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
873                         dsp_modulo = data;
874                         break;
875                 case 0x1C:
876                         dsp_div_control = data;
877                         break;
878 //              default:   // unaligned long read
879                                    //__asm int 3
880                 }
881                 return;
882         }
883
884 //We don't have to break this up like this! We CAN do 32 bit writes!
885 //      JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
886 //      JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
887 //if (offset > 0xF1FFFF)
888 //      badWrite = true;
889         JaguarWriteLong(offset, data, who);
890 }
891
892 //
893 // Update the DSP register file pointers depending on REGPAGE bit
894 //
895 void DSPUpdateRegisterBanks(void)
896 {
897         int bank = (dsp_flags & REGPAGE);
898
899         if (dsp_flags & IMASK)
900                 bank = 0;                                                       // IMASK forces main bank to be bank 0
901
902         if (bank)
903                 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
904         else
905                 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
906
907 #ifdef DSP_DEBUG_IRQ
908         WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
909 #endif
910 }
911
912 //
913 // Check for and handle any asserted DSP IRQs
914 //
915 void DSPHandleIRQs(void)
916 {
917         if (dsp_flags & IMASK)                                                  // Bail if we're already inside an interrupt
918                 return;
919
920         // Get the active interrupt bits (latches) & interrupt mask (enables)
921         uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
922                 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
923
924 //      WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
925         bits &= mask;
926
927         if (!bits)                                                                              // Bail if nothing is enabled
928                 return;
929
930         int which = 0;                                                                  // Determine which interrupt
931
932         if (bits & 0x01)
933                 which = 0;
934         if (bits & 0x02)
935                 which = 1;
936         if (bits & 0x04)
937                 which = 2;
938         if (bits & 0x08)
939                 which = 3;
940         if (bits & 0x10)
941                 which = 4;
942         if (bits & 0x20)
943                 which = 5;
944
945 #ifdef DSP_DEBUG_IRQ
946         WriteLog("DSP: Generating interrupt #%i...", which);
947 #endif
948 //temp... !!!!!
949 //if (which == 0)       doDSPDis = true;
950
951         // NOTE: Since the actual Jaguar hardware injects the code sequence below
952         //       directly into the pipeline, it has the side effect of ensuring that the
953         //       instruction interrupted also gets to do its writeback. We simulate that
954         //       behavior here.
955 /*      if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
956         {
957                 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
958                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
959
960                 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
961                         scoreboard[pipeline[plPtrWrite].operand2] = false;
962         }//*/
963 //This should be execute (or should it?--not sure now!)
964 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
965 //and what just executed is now in the Write position...). So why didn't it do the
966 //writeback into register 0?
967 #ifdef DSP_DEBUG_IRQ
968 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
969 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]);
970 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]);
971 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]);
972 #endif
973         if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
974         {
975                 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
976                 {
977                         if (pipeline[plPtrWrite].writebackRegister != 0xFE)
978                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
979                         else
980                         {
981                                 if (pipeline[plPtrWrite].type == TYPE_BYTE)
982                                         JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
983                                 else if (pipeline[plPtrWrite].type == TYPE_WORD)
984                                         JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
985                                 else
986                                         JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
987                         }
988                 }
989
990 #ifndef NEW_SCOREBOARD
991                 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
992                         scoreboard[pipeline[plPtrWrite].operand2] = false;
993 #else
994 //Yup, sequential MOVEQ # problem fixing (I hope!)...
995                 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
996                         if (scoreboard[pipeline[plPtrWrite].operand2])
997                                 scoreboard[pipeline[plPtrWrite].operand2]--;
998 #endif
999         }
1000
1001         dsp_flags |= IMASK;
1002 //CC only!
1003 #ifdef DSP_DEBUG_CC
1004 ctrl2[4] = dsp_flags;
1005 #endif
1006 //!!!!!!!!
1007         DSPUpdateRegisterBanks();
1008 #ifdef DSP_DEBUG_IRQ
1009 //      WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1010         WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), dsp_reg[31]);
1011 #endif
1012
1013         // subqt  #4,r31                ; pre-decrement stack pointer
1014         // move   pc,r30                ; address of interrupted code
1015         // store  r30,(r31)     ; store return address
1016         dsp_reg[31] -= 4;
1017 //CC only!
1018 #ifdef DSP_DEBUG_CC
1019 regs2[31] -= 4;
1020 #endif
1021 //!!!!!!!!
1022 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1023 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1024 //It missed the place that it was supposed to come back to, so this is WRONG!
1025 //
1026 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1027 //
1028 // R -> baz             (<- PC points here)
1029 // E -> bar             (when it should point here!)
1030 // W -> foo
1031 //
1032 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1033 // which means (assuming they're all 2 bytes long) that the code below will come back on
1034 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1035 // instruction stream...
1036
1037 //      DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1038         DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1039 //CC only!
1040 #ifdef DSP_DEBUG_CC
1041 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1042 #endif
1043 //!!!!!!!!
1044
1045         // movei  #service_address,r30  ; pointer to ISR entry
1046         // jump  (r30)                                  ; jump to ISR
1047         // nop
1048         dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1049 //CC only!
1050 #ifdef DSP_DEBUG_CC
1051 ctrl2[0] = regs2[30] = dsp_pc;
1052 #endif
1053 //!!!!!!!!
1054         FlushDSPPipeline();
1055 }
1056
1057 //
1058 // Non-pipelined version...
1059 //
1060 void DSPHandleIRQsNP(void)
1061 {
1062 //CC only!
1063 #ifdef DSP_DEBUG_CC
1064                 memcpy(dsp_ram_8, ram1, 0x2000);
1065                 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1066                 memcpy(dsp_reg_bank_1, &regs1[32], 32 * 4);
1067                 dsp_pc                                  = ctrl1[0];
1068                 dsp_acc                                 = ctrl1[1];
1069                 dsp_remain                              = ctrl1[2];
1070                 dsp_modulo                              = ctrl1[3];
1071                 dsp_flags                               = ctrl1[4];
1072                 dsp_matrix_control              = ctrl1[5];
1073                 dsp_pointer_to_matrix   = ctrl1[6];
1074                 dsp_data_organization   = ctrl1[7];
1075                 dsp_control                             = ctrl1[8];
1076                 dsp_div_control                 = ctrl1[9];
1077                 IMASKCleared                    = ctrl1[10];
1078                 dsp_flag_z                              = ctrl1[11];
1079                 dsp_flag_n                              = ctrl1[12];
1080                 dsp_flag_c                              = ctrl1[13];
1081 DSPUpdateRegisterBanks();
1082 #endif
1083 //!!!!!!!!
1084         if (dsp_flags & IMASK)                                                  // Bail if we're already inside an interrupt
1085                 return;
1086
1087         // Get the active interrupt bits (latches) & interrupt mask (enables)
1088         uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1089                 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1090
1091 //      WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1092         bits &= mask;
1093
1094         if (!bits)                                                                              // Bail if nothing is enabled
1095                 return;
1096
1097         int which = 0;                                                                  // Determine which interrupt
1098         if (bits & 0x01)
1099                 which = 0;
1100         if (bits & 0x02)
1101                 which = 1;
1102         if (bits & 0x04)
1103                 which = 2;
1104         if (bits & 0x08)
1105                 which = 3;
1106         if (bits & 0x10)
1107                 which = 4;
1108         if (bits & 0x20)
1109                 which = 5;
1110
1111         dsp_flags |= IMASK;             // Force Bank #0
1112 //CC only!
1113 #ifdef DSP_DEBUG_CC
1114 ctrl1[4] = dsp_flags;
1115 #endif
1116 //!!!!!!!!
1117 #ifdef DSP_DEBUG_IRQ
1118         WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1119         WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1120 #endif
1121         DSPUpdateRegisterBanks();
1122 #ifdef DSP_DEBUG_IRQ
1123         WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1124         WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1125 #endif
1126
1127 #ifdef DSP_DEBUG_IRQ
1128         WriteLog("DSP: Generating interrupt #%i...", which);
1129         WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1130 #endif
1131
1132         // subqt  #4,r31                ; pre-decrement stack pointer
1133         // move   pc,r30                ; address of interrupted code
1134         // store  r30,(r31)     ; store return address
1135         dsp_reg[31] -= 4;
1136         dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1137
1138 //CC only!
1139 #ifdef DSP_DEBUG_CC
1140 regs1[31] -= 4;
1141 #endif
1142 //!!!!!!!!
1143 //      DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1144         DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1145 //CC only!
1146 #ifdef DSP_DEBUG_CC
1147 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1148 #endif
1149 //!!!!!!!!
1150
1151         // movei  #service_address,r30  ; pointer to ISR entry
1152         // jump  (r30)                                  ; jump to ISR
1153         // nop
1154         dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1155 //CC only!
1156 #ifdef DSP_DEBUG_CC
1157 ctrl1[0] = regs1[30] = dsp_pc;
1158 #endif
1159 //!!!!!!!!
1160 }
1161
1162 //
1163 // Set the specified DSP IRQ line to a given state
1164 //
1165 void DSPSetIRQLine(int irqline, int state)
1166 {
1167 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1168         uint32_t mask = INT_LAT0 << irqline;
1169         dsp_control &= ~mask;                                                   // Clear the latch bit
1170 //CC only!
1171 #ifdef DSP_DEBUG_CC
1172 ctrl1[8] = ctrl2[8] = dsp_control;
1173 #endif
1174 //!!!!!!!!
1175
1176         if (state)
1177         {
1178                 dsp_control |= mask;                                            // Set the latch bit
1179 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1180 //              DSPHandleIRQs();
1181                 DSPHandleIRQsNP();
1182 //CC only!
1183 #ifdef DSP_DEBUG_CC
1184 ctrl1[8] = ctrl2[8] = dsp_control;
1185 DSPHandleIRQsNP();
1186 #endif
1187 //!!!!!!!!
1188         }
1189
1190         // Not sure if this is correct behavior, but according to JTRM,
1191         // the IRQ output of JERRY is fed to this IRQ in the GPU...
1192 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1193 //      GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1194 }
1195
1196 bool DSPIsRunning(void)
1197 {
1198         return (DSP_RUNNING ? true : false);
1199 }
1200
1201 void DSPInit(void)
1202 {
1203 //      memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1204 //      memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1205 //      memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1206
1207         dsp_build_branch_condition_table();
1208         DSPReset();
1209 }
1210
1211 void DSPReset(void)
1212 {
1213         dsp_pc                            = 0x00F1B000;
1214         dsp_acc                           = 0x00000000;
1215         dsp_remain                        = 0x00000000;
1216         dsp_modulo                        = 0xFFFFFFFF;
1217         dsp_flags                         = 0x00040000;
1218         dsp_matrix_control    = 0x00000000;
1219         dsp_pointer_to_matrix = 0x00000000;
1220         dsp_data_organization = 0xFFFFFFFF;
1221         dsp_control                       = 0x00002000;                         // Report DSP version 2
1222         dsp_div_control           = 0x00000000;
1223         dsp_in_exec                       = 0;
1224
1225         dsp_reg = dsp_reg_bank_0;
1226         dsp_alternate_reg = dsp_reg_bank_1;
1227
1228         for(int i=0; i<32; i++)
1229                 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1230
1231         CLR_ZNC;
1232         IMASKCleared = false;
1233         FlushDSPPipeline();
1234         dsp_reset_stats();
1235
1236         // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1237         for(uint32_t i=0; i<8192; i+=4)
1238                 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1239 }
1240
1241 void DSPDumpDisassembly(void)
1242 {
1243         char buffer[512];
1244
1245         WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1246         uint32_t j = 0xF1B000;
1247
1248         while (j <= 0xF1CFFF)
1249         {
1250                 uint32_t oldj = j;
1251                 j += dasmjag(JAGUAR_DSP, buffer, j);
1252                 WriteLog("\t%08X: %s\n", oldj, buffer);
1253         }
1254 }
1255
1256 void DSPDumpRegisters(void)
1257 {
1258 //Shoud add modulus, etc to dump here...
1259         WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1260         WriteLog("\nRegisters bank 0\n");
1261
1262         for(int j=0; j<8; j++)
1263         {
1264                 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1265                         (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1266                         (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1267                         (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1268                         (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1269         }
1270
1271         WriteLog("Registers bank 1\n");
1272
1273         for(int j=0; j<8; j++)
1274         {
1275                 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1276                         (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1277                         (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1278                         (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1279                         (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1280         }
1281 }
1282
1283 void DSPDone(void)
1284 {
1285         int i, j;
1286         WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1287         WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1288
1289         // get the active interrupt bits
1290         int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1291         // get the interrupt mask
1292         int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1293
1294         WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1295                 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1296                 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1297                 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1298         WriteLog("\nRegisters bank 0\n");
1299
1300         for(int j=0; j<8; j++)
1301         {
1302                 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1303                                                   (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1304                                                   (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1305                                                   (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1306                                                   (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1307         }
1308
1309         WriteLog("\nRegisters bank 1\n");
1310
1311         for (j=0; j<8; j++)
1312         {
1313                 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1314                                                   (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1315                                                   (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1316                                                   (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1317                                                   (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1318         }
1319
1320         WriteLog("\n");
1321
1322         static char buffer[512];
1323         j = DSP_WORK_RAM_BASE;
1324
1325         while (j <= 0xF1CFFF)
1326         {
1327                 uint32_t oldj = j;
1328                 j += dasmjag(JAGUAR_DSP, buffer, j);
1329                 WriteLog("\t%08X: %s\n", oldj, buffer);
1330         }//*/
1331
1332         WriteLog("DSP opcodes use:\n");
1333
1334         for (i=0;i<64;i++)
1335         {
1336                 if (dsp_opcode_use[i])
1337                         WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1338         }//*/
1339 }
1340
1341
1342
1343 //
1344 // DSP comparison core...
1345 //
1346 #ifdef DSP_DEBUG_CC
1347 static uint16_t lastExec;
1348 void DSPExecComp(int32_t cycles)
1349 {
1350         while (cycles > 0 && DSP_RUNNING)
1351         {
1352                 // Load up vars for non-pipelined core
1353                 memcpy(dsp_ram_8, ram1, 0x2000);
1354                 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1355                 memcpy(dsp_reg_bank_1, &regs1[32], 32 * 4);
1356                 dsp_pc                                  = ctrl1[0];
1357                 dsp_acc                                 = ctrl1[1];
1358                 dsp_remain                              = ctrl1[2];
1359                 dsp_modulo                              = ctrl1[3];
1360                 dsp_flags                               = ctrl1[4];
1361                 dsp_matrix_control              = ctrl1[5];
1362                 dsp_pointer_to_matrix   = ctrl1[6];
1363                 dsp_data_organization   = ctrl1[7];
1364                 dsp_control                             = ctrl1[8];
1365                 dsp_div_control                 = ctrl1[9];
1366                 IMASKCleared                    = ctrl1[10];
1367                 dsp_flag_z                              = ctrl1[11];
1368                 dsp_flag_n                              = ctrl1[12];
1369                 dsp_flag_c                              = ctrl1[13];
1370 DSPUpdateRegisterBanks();
1371
1372                 // Decrement cycles based on non-pipelined core...
1373                 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1374                 cycles -= dsp_opcode_cycles[instr1 >> 10];
1375
1376 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1377                 DSPExec(1);                                                                     // Do *one* instruction
1378
1379                 // Save vars
1380                 memcpy(ram1, dsp_ram_8, 0x2000);
1381                 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1382                 memcpy(&regs1[32], dsp_reg_bank_1, 32 * 4);
1383                 ctrl1[0]  = dsp_pc;
1384                 ctrl1[1]  = dsp_acc;
1385                 ctrl1[2]  = dsp_remain;
1386                 ctrl1[3]  = dsp_modulo;
1387                 ctrl1[4]  = dsp_flags;
1388                 ctrl1[5]  = dsp_matrix_control;
1389                 ctrl1[6]  = dsp_pointer_to_matrix;
1390                 ctrl1[7]  = dsp_data_organization;
1391                 ctrl1[8]  = dsp_control;
1392                 ctrl1[9]  = dsp_div_control;
1393                 ctrl1[10] = IMASKCleared;
1394                 ctrl1[11] = dsp_flag_z;
1395                 ctrl1[12] = dsp_flag_n;
1396                 ctrl1[13] = dsp_flag_c;
1397
1398                 // Load up vars for pipelined core
1399                 memcpy(dsp_ram_8, ram2, 0x2000);
1400                 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1401                 memcpy(dsp_reg_bank_1, &regs2[32], 32 * 4);
1402                 dsp_pc                                  = ctrl2[0];
1403                 dsp_acc                                 = ctrl2[1];
1404                 dsp_remain                              = ctrl2[2];
1405                 dsp_modulo                              = ctrl2[3];
1406                 dsp_flags                               = ctrl2[4];
1407                 dsp_matrix_control              = ctrl2[5];
1408                 dsp_pointer_to_matrix   = ctrl2[6];
1409                 dsp_data_organization   = ctrl2[7];
1410                 dsp_control                             = ctrl2[8];
1411                 dsp_div_control                 = ctrl2[9];
1412                 IMASKCleared                    = ctrl2[10];
1413                 dsp_flag_z                              = ctrl2[11];
1414                 dsp_flag_n                              = ctrl2[12];
1415                 dsp_flag_c                              = ctrl2[13];
1416 DSPUpdateRegisterBanks();
1417
1418 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1419                 DSPExecP2(1);                                                           // Do *one* instruction
1420
1421                 // Save vars
1422                 memcpy(ram2, dsp_ram_8, 0x2000);
1423                 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1424                 memcpy(&regs2[32], dsp_reg_bank_1, 32 * 4);
1425                 ctrl2[0]  = dsp_pc;
1426                 ctrl2[1]  = dsp_acc;
1427                 ctrl2[2]  = dsp_remain;
1428                 ctrl2[3]  = dsp_modulo;
1429                 ctrl2[4]  = dsp_flags;
1430                 ctrl2[5]  = dsp_matrix_control;
1431                 ctrl2[6]  = dsp_pointer_to_matrix;
1432                 ctrl2[7]  = dsp_data_organization;
1433                 ctrl2[8]  = dsp_control;
1434                 ctrl2[9]  = dsp_div_control;
1435                 ctrl2[10] = IMASKCleared;
1436                 ctrl2[11] = dsp_flag_z;
1437                 ctrl2[12] = dsp_flag_n;
1438                 ctrl2[13] = dsp_flag_c;
1439
1440                 if (instr1 != lastExec)
1441                 {
1442 //                      WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1443
1444 //                      uint32_t ppc = ctrl2[0] - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrWrite].opcode == 38 ? 6 : (pipeline[plPtrWrite].opcode == PIPELINE_STALL ? 0 : 2));
1445 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1446 //                      if (ctrl1[0] < ppc)                                             // P ran ahead of NP
1447 //How to test this crap???
1448 //                      if (1)
1449                         {
1450                 DSPExecP2(1);                                                           // Do one more instruction
1451
1452                 // Save vars
1453                 memcpy(ram2, dsp_ram_8, 0x2000);
1454                 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1455                 memcpy(&regs2[32], dsp_reg_bank_1, 32 * 4);
1456                 ctrl2[0]  = dsp_pc;
1457                 ctrl2[1]  = dsp_acc;
1458                 ctrl2[2]  = dsp_remain;
1459                 ctrl2[3]  = dsp_modulo;
1460                 ctrl2[4]  = dsp_flags;
1461                 ctrl2[5]  = dsp_matrix_control;
1462                 ctrl2[6]  = dsp_pointer_to_matrix;
1463                 ctrl2[7]  = dsp_data_organization;
1464                 ctrl2[8]  = dsp_control;
1465                 ctrl2[9]  = dsp_div_control;
1466                 ctrl2[10] = IMASKCleared;
1467                 ctrl2[11] = dsp_flag_z;
1468                 ctrl2[12] = dsp_flag_n;
1469                 ctrl2[13] = dsp_flag_c;
1470                         }
1471 //                      else                                                                    // NP ran ahead of P
1472                 if (instr1 != lastExec)                                         // Must be the other way...
1473
1474                         {
1475                 // Load up vars for non-pipelined core
1476                 memcpy(dsp_ram_8, ram1, 0x2000);
1477                 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1478                 memcpy(dsp_reg_bank_1, &regs1[32], 32 * 4);
1479                 dsp_pc                                  = ctrl1[0];
1480                 dsp_acc                                 = ctrl1[1];
1481                 dsp_remain                              = ctrl1[2];
1482                 dsp_modulo                              = ctrl1[3];
1483                 dsp_flags                               = ctrl1[4];
1484                 dsp_matrix_control              = ctrl1[5];
1485                 dsp_pointer_to_matrix   = ctrl1[6];
1486                 dsp_data_organization   = ctrl1[7];
1487                 dsp_control                             = ctrl1[8];
1488                 dsp_div_control                 = ctrl1[9];
1489                 IMASKCleared                    = ctrl1[10];
1490                 dsp_flag_z                              = ctrl1[11];
1491                 dsp_flag_n                              = ctrl1[12];
1492                 dsp_flag_c                              = ctrl1[13];
1493 DSPUpdateRegisterBanks();
1494
1495 for(int k=0; k<2; k++)
1496 {
1497                 // Decrement cycles based on non-pipelined core...
1498                 instr1 = DSPReadWord(dsp_pc, DSP);
1499                 cycles -= dsp_opcode_cycles[instr1 >> 10];
1500
1501 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1502                 DSPExec(1);                                                                     // Do *one* instruction
1503 }
1504
1505                 // Save vars
1506                 memcpy(ram1, dsp_ram_8, 0x2000);
1507                 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1508                 memcpy(&regs1[32], dsp_reg_bank_1, 32 * 4);
1509                 ctrl1[0]  = dsp_pc;
1510                 ctrl1[1]  = dsp_acc;
1511                 ctrl1[2]  = dsp_remain;
1512                 ctrl1[3]  = dsp_modulo;
1513                 ctrl1[4]  = dsp_flags;
1514                 ctrl1[5]  = dsp_matrix_control;
1515                 ctrl1[6]  = dsp_pointer_to_matrix;
1516                 ctrl1[7]  = dsp_data_organization;
1517                 ctrl1[8]  = dsp_control;
1518                 ctrl1[9]  = dsp_div_control;
1519                 ctrl1[10] = IMASKCleared;
1520                 ctrl1[11] = dsp_flag_z;
1521                 ctrl1[12] = dsp_flag_n;
1522                 ctrl1[13] = dsp_flag_c;
1523                         }
1524                 }
1525
1526                 if (instr1 != lastExec)
1527                 {
1528                         WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1529
1530                         WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1531                         WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1532
1533                         log_done();
1534                         exit(1);
1535                 }
1536
1537                 count++;
1538         }
1539 }
1540 #endif
1541
1542
1543 //
1544 // DSP execution core
1545 //
1546 //static bool R20Set = false, tripwire = false;
1547 //static uint32_t pcQueue[32], ptrPCQ = 0;
1548 void DSPExec(int32_t cycles)
1549 {
1550 #ifdef DSP_SINGLE_STEPPING
1551         if (dsp_control & 0x18)
1552         {
1553                 cycles = 1;
1554                 dsp_control &= ~0x10;
1555         }
1556 #endif
1557 //There is *no* good reason to do this here!
1558 //      DSPHandleIRQs();
1559         dsp_releaseTimeSlice_flag = 0;
1560         dsp_in_exec++;
1561
1562         while (cycles > 0 && DSP_RUNNING)
1563         {
1564 /*extern uint32_t totalFrames;
1565 //F1B2F6: LOAD   (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1566 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1567 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1568 //F1B140:
1569 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1570 {
1571         doDSPDis = true;
1572         WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1573 }
1574 if (dsp_pc == 0xF1B092)
1575         doDSPDis = false;//*/
1576 /*if (dsp_pc == 0xF1B140)
1577         doDSPDis = true;//*/
1578
1579                 if (IMASKCleared)                                               // If IMASK was cleared,
1580                 {
1581 #ifdef DSP_DEBUG_IRQ
1582                         WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1583 #endif
1584                         DSPHandleIRQsNP();                                      // See if any other interrupts are pending!
1585                         IMASKCleared = false;
1586                 }
1587
1588 /*if (badWrite)
1589 {
1590         WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1591         for(int i=0; i<80; i+=4)
1592                 WriteLog("     %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1593         WriteLog("\n");
1594 }//*/
1595 /*if (dsp_pc == 0xF1B55E)
1596 {
1597         WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1598 }//*/
1599 /*if (dsp_pc == 0xF1B7D2)       // Start here???
1600         doDSPDis = true;
1601 pcQueue[ptrPCQ++] = dsp_pc;
1602 ptrPCQ %= 32;*/
1603                 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1604                 uint32_t index = opcode >> 10;
1605                 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1606                 dsp_opcode_second_parameter = opcode & 0x1F;
1607                 dsp_pc += 2;
1608                 dsp_opcode[index]();
1609                 dsp_opcode_use[index]++;
1610                 cycles -= dsp_opcode_cycles[index];
1611 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1612 {
1613         WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1614         R20Set = true;
1615 }
1616 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1617 {
1618         WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1619         DSPDumpRegisters();
1620         DSPDumpDisassembly();
1621         exit(1);
1622 }
1623 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1624 {
1625         char buffer[512];
1626         WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1627         DSPDumpRegisters();
1628         tripwire = true;
1629         WriteLog("\nBacktrace:\n");
1630         for(int i=0; i<32; i++)
1631         {
1632                 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1633                 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1634         }
1635         WriteLog("\n");
1636 }*/
1637         }
1638
1639         dsp_in_exec--;
1640 }
1641
1642 //
1643 // DSP opcode handlers
1644 //
1645
1646 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1647 // can cause trouble because an interrupt can occur *before* the instruction following the
1648 // jump can execute... !!! FIX !!!
1649 static void dsp_opcode_jump(void)
1650 {
1651 #ifdef DSP_DIS_JUMP
1652 const char * condition[32] =
1653 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1654         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1655         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1656         "???", "???", "???", "F" };
1657         if (doDSPDis)
1658                 WriteLog("%06X: JUMP   %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", dsp_pc-2, condition[IMM_2], IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM);
1659 #endif
1660         // normalize flags
1661 /*      dsp_flag_c=dsp_flag_c?1:0;
1662         dsp_flag_z=dsp_flag_z?1:0;
1663         dsp_flag_n=dsp_flag_n?1:0;*/
1664         // KLUDGE: Used by BRANCH_CONDITION
1665         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1666
1667         if (BRANCH_CONDITION(IMM_2))
1668         {
1669 #ifdef DSP_DIS_JUMP
1670         if (doDSPDis)
1671                 WriteLog("Branched!\n");
1672 #endif
1673                 uint32_t delayed_pc = RM;
1674                 DSPExec(1);
1675                 dsp_pc = delayed_pc;
1676         }
1677 #ifdef DSP_DIS_JUMP
1678         else
1679                 if (doDSPDis)
1680                         WriteLog("Branch NOT taken.\n");
1681 #endif
1682 }
1683
1684 static void dsp_opcode_jr(void)
1685 {
1686 #ifdef DSP_DIS_JR
1687 const char * condition[32] =
1688 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1689         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1690         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1691         "???", "???", "???", "F" };
1692         if (doDSPDis)
1693                 WriteLog("%06X: JR     %s, %06X [NCZ:%u%u%u] ", dsp_pc-2, condition[IMM_2], dsp_pc+((IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1) * 2), dsp_flag_n, dsp_flag_c, dsp_flag_z);
1694 #endif
1695         // normalize flags
1696 /*      dsp_flag_c=dsp_flag_c?1:0;
1697         dsp_flag_z=dsp_flag_z?1:0;
1698         dsp_flag_n=dsp_flag_n?1:0;*/
1699         // KLUDGE: Used by BRANCH_CONDITION
1700         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1701
1702         if (BRANCH_CONDITION(IMM_2))
1703         {
1704 #ifdef DSP_DIS_JR
1705         if (doDSPDis)
1706                 WriteLog("Branched!\n");
1707 #endif
1708                 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1);           // Sign extend IMM_1
1709                 int32_t delayed_pc = dsp_pc + (offset * 2);
1710                 DSPExec(1);
1711                 dsp_pc = delayed_pc;
1712         }
1713 #ifdef DSP_DIS_JR
1714         else
1715                 if (doDSPDis)
1716                         WriteLog("Branch NOT taken.\n");
1717 #endif
1718 }
1719
1720 static void dsp_opcode_add(void)
1721 {
1722 #ifdef DSP_DIS_ADD
1723         if (doDSPDis)
1724                 WriteLog("%06X: ADD    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1725 #endif
1726         uint32_t res = RN + RM;
1727         SET_ZNC_ADD(RN, RM, res);
1728         RN = res;
1729 #ifdef DSP_DIS_ADD
1730         if (doDSPDis)
1731                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1732 #endif
1733 }
1734
1735 static void dsp_opcode_addc(void)
1736 {
1737 #ifdef DSP_DIS_ADDC
1738         if (doDSPDis)
1739                 WriteLog("%06X: ADDC   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1740 #endif
1741         uint32_t res = RN + RM + dsp_flag_c;
1742         uint32_t carry = dsp_flag_c;
1743 //      SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1744         SET_ZNC_ADD(RN + carry, RM, res);
1745 //      SET_ZNC_ADD(RN, RM + carry, res);
1746         RN = res;
1747 #ifdef DSP_DIS_ADDC
1748         if (doDSPDis)
1749                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1750 #endif
1751 }
1752
1753 static void dsp_opcode_addq(void)
1754 {
1755 #ifdef DSP_DIS_ADDQ
1756         if (doDSPDis)
1757                 WriteLog("%06X: ADDQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1758 #endif
1759         uint32_t r1 = dsp_convert_zero[IMM_1];
1760         uint32_t res = RN + r1;
1761         CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1762         RN = res;
1763 #ifdef DSP_DIS_ADDQ
1764         if (doDSPDis)
1765                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1766 #endif
1767 }
1768
1769 static void dsp_opcode_sub(void)
1770 {
1771 #ifdef DSP_DIS_SUB
1772         if (doDSPDis)
1773                 WriteLog("%06X: SUB    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1774 #endif
1775         uint32_t res = RN - RM;
1776         SET_ZNC_SUB(RN, RM, res);
1777         RN = res;
1778 #ifdef DSP_DIS_SUB
1779         if (doDSPDis)
1780                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1781 #endif
1782 }
1783
1784 static void dsp_opcode_subc(void)
1785 {
1786 #ifdef DSP_DIS_SUBC
1787         if (doDSPDis)
1788                 WriteLog("%06X: SUBC   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1789 #endif
1790         uint32_t res = RN - RM - dsp_flag_c;
1791         uint32_t borrow = dsp_flag_c;
1792         SET_ZNC_SUB(RN - borrow, RM, res);
1793         RN = res;
1794 #ifdef DSP_DIS_SUBC
1795         if (doDSPDis)
1796                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1797 #endif
1798 }
1799
1800 static void dsp_opcode_subq(void)
1801 {
1802 #ifdef DSP_DIS_SUBQ
1803         if (doDSPDis)
1804                 WriteLog("%06X: SUBQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1805 #endif
1806         uint32_t r1 = dsp_convert_zero[IMM_1];
1807         uint32_t res = RN - r1;
1808         SET_ZNC_SUB(RN, r1, res);
1809         RN = res;
1810 #ifdef DSP_DIS_SUBQ
1811         if (doDSPDis)
1812                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1813 #endif
1814 }
1815
1816 static void dsp_opcode_cmp(void)
1817 {
1818 #ifdef DSP_DIS_CMP
1819         if (doDSPDis)
1820                 WriteLog("%06X: CMP    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1821 #endif
1822         uint32_t res = RN - RM;
1823         SET_ZNC_SUB(RN, RM, res);
1824 #ifdef DSP_DIS_CMP
1825         if (doDSPDis)
1826                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1827 #endif
1828 }
1829
1830 static void dsp_opcode_cmpq(void)
1831 {
1832         static int32_t sqtable[32] =
1833                 { 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 };
1834 #ifdef DSP_DIS_CMPQ
1835         if (doDSPDis)
1836                 WriteLog("%06X: CMPQ   #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, sqtable[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1837 #endif
1838         uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1839         uint32_t res = RN - r1;
1840         SET_ZNC_SUB(RN, r1, res);
1841 #ifdef DSP_DIS_CMPQ
1842         if (doDSPDis)
1843                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1844 #endif
1845 }
1846
1847 static void dsp_opcode_and(void)
1848 {
1849 #ifdef DSP_DIS_AND
1850         if (doDSPDis)
1851                 WriteLog("%06X: AND    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1852 #endif
1853         RN = RN & RM;
1854         SET_ZN(RN);
1855 #ifdef DSP_DIS_AND
1856         if (doDSPDis)
1857                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1858 #endif
1859 }
1860
1861 static void dsp_opcode_or(void)
1862 {
1863 #ifdef DSP_DIS_OR
1864         if (doDSPDis)
1865                 WriteLog("%06X: OR     R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1866 #endif
1867         RN = RN | RM;
1868         SET_ZN(RN);
1869 #ifdef DSP_DIS_OR
1870         if (doDSPDis)
1871                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1872 #endif
1873 }
1874
1875 static void dsp_opcode_xor(void)
1876 {
1877 #ifdef DSP_DIS_XOR
1878         if (doDSPDis)
1879                 WriteLog("%06X: XOR    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1880 #endif
1881         RN = RN ^ RM;
1882         SET_ZN(RN);
1883 #ifdef DSP_DIS_XOR
1884         if (doDSPDis)
1885                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1886 #endif
1887 }
1888
1889 static void dsp_opcode_not(void)
1890 {
1891 #ifdef DSP_DIS_NOT
1892         if (doDSPDis)
1893                 WriteLog("%06X: NOT    R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1894 #endif
1895         RN = ~RN;
1896         SET_ZN(RN);
1897 #ifdef DSP_DIS_NOT
1898         if (doDSPDis)
1899                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1900 #endif
1901 }
1902
1903 static void dsp_opcode_move_pc(void)
1904 {
1905         RN = dsp_pc - 2;
1906 }
1907
1908 static void dsp_opcode_store_r14_indexed(void)
1909 {
1910 #ifdef DSP_DIS_STORE14I
1911         if (doDSPDis)
1912                 WriteLog("%06X: STORE  R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2));
1913 #endif
1914 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1915         DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1916 #else
1917         DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1918 #endif
1919 }
1920
1921 static void dsp_opcode_store_r15_indexed(void)
1922 {
1923 #ifdef DSP_DIS_STORE15I
1924         if (doDSPDis)
1925                 WriteLog("%06X: STORE  R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2));
1926 #endif
1927 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1928         DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1929 #else
1930         DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1931 #endif
1932 }
1933
1934 static void dsp_opcode_load_r14_ri(void)
1935 {
1936 #ifdef DSP_DIS_LOAD14R
1937         if (doDSPDis)
1938                 WriteLog("%06X: LOAD   (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[14], IMM_2, RN);
1939 #endif
1940 #ifdef DSP_CORRECT_ALIGNMENT
1941         RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1942 #else
1943         RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1944 #endif
1945 #ifdef DSP_DIS_LOAD14R
1946         if (doDSPDis)
1947                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1948 #endif
1949 }
1950
1951 static void dsp_opcode_load_r15_ri(void)
1952 {
1953 #ifdef DSP_DIS_LOAD15R
1954         if (doDSPDis)
1955                 WriteLog("%06X: LOAD   (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[15], IMM_2, RN);
1956 #endif
1957 #ifdef DSP_CORRECT_ALIGNMENT
1958         RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1959 #else
1960         RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1961 #endif
1962 #ifdef DSP_DIS_LOAD15R
1963         if (doDSPDis)
1964                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1965 #endif
1966 }
1967
1968 static void dsp_opcode_store_r14_ri(void)
1969 {
1970         DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1971 }
1972
1973 static void dsp_opcode_store_r15_ri(void)
1974 {
1975         DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1976 }
1977
1978 static void dsp_opcode_nop(void)
1979 {
1980 #ifdef DSP_DIS_NOP
1981         if (doDSPDis)
1982                 WriteLog("%06X: NOP    [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1983 #endif
1984 }
1985
1986 static void dsp_opcode_storeb(void)
1987 {
1988 #ifdef DSP_DIS_STOREB
1989         if (doDSPDis)
1990                 WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
1991 #endif
1992         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1993                 DSPWriteLong(RM, RN & 0xFF, DSP);
1994         else
1995                 JaguarWriteByte(RM, RN, DSP);
1996 }
1997
1998 static void dsp_opcode_storew(void)
1999 {
2000 #ifdef DSP_DIS_STOREW
2001         if (doDSPDis)
2002                 WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
2003 #endif
2004 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2005         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2006                 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2007         else
2008                 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2009 #else
2010         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2011                 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2012         else
2013                 JaguarWriteWord(RM, RN, DSP);
2014 #endif
2015 }
2016
2017 static void dsp_opcode_store(void)
2018 {
2019 #ifdef DSP_DIS_STORE
2020         if (doDSPDis)
2021                 WriteLog("%06X: STORE  R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
2022 #endif
2023 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2024         DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2025 #else
2026         DSPWriteLong(RM, RN, DSP);
2027 #endif
2028 }
2029
2030 static void dsp_opcode_loadb(void)
2031 {
2032 #ifdef DSP_DIS_LOADB
2033         if (doDSPDis)
2034                 WriteLog("%06X: LOADB  (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2035 #endif
2036         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037                 RN = DSPReadLong(RM, DSP) & 0xFF;
2038         else
2039                 RN = JaguarReadByte(RM, DSP);
2040 #ifdef DSP_DIS_LOADB
2041         if (doDSPDis)
2042                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2043 #endif
2044 }
2045
2046 static void dsp_opcode_loadw(void)
2047 {
2048 #ifdef DSP_DIS_LOADW
2049         if (doDSPDis)
2050                 WriteLog("%06X: LOADW  (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2051 #endif
2052 #ifdef DSP_CORRECT_ALIGNMENT
2053         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2054                 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2055         else
2056                 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2057 #else
2058         if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2059                 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2060         else
2061                 RN = JaguarReadWord(RM, DSP);
2062 #endif
2063 #ifdef DSP_DIS_LOADW
2064         if (doDSPDis)
2065                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2066 #endif
2067 }
2068
2069 static void dsp_opcode_load(void)
2070 {
2071 #ifdef DSP_DIS_LOAD
2072         if (doDSPDis)
2073                 WriteLog("%06X: LOAD   (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2074 #endif
2075 #ifdef DSP_CORRECT_ALIGNMENT
2076         RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2077 #else
2078         RN = DSPReadLong(RM, DSP);
2079 #endif
2080 #ifdef DSP_DIS_LOAD
2081         if (doDSPDis)
2082                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2083 #endif
2084 }
2085
2086 static void dsp_opcode_load_r14_indexed(void)
2087 {
2088 #ifdef DSP_DIS_LOAD14I
2089         if (doDSPDis)
2090                 WriteLog("%06X: LOAD   (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN);
2091 #endif
2092 #ifdef DSP_CORRECT_ALIGNMENT
2093         RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2094 #else
2095         RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2096 #endif
2097 #ifdef DSP_DIS_LOAD14I
2098         if (doDSPDis)
2099                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2100 #endif
2101 }
2102
2103 static void dsp_opcode_load_r15_indexed(void)
2104 {
2105 #ifdef DSP_DIS_LOAD15I
2106         if (doDSPDis)
2107                 WriteLog("%06X: LOAD   (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN);
2108 #endif
2109 #ifdef DSP_CORRECT_ALIGNMENT
2110         RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2111 #else
2112         RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2113 #endif
2114 #ifdef DSP_DIS_LOAD15I
2115         if (doDSPDis)
2116                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2117 #endif
2118 }
2119
2120 static void dsp_opcode_movei(void)
2121 {
2122 #ifdef DSP_DIS_MOVEI
2123         if (doDSPDis)
2124                 WriteLog("%06X: MOVEI  #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, (uint32_t)DSPReadWord(dsp_pc) | ((uint32_t)DSPReadWord(dsp_pc + 2) << 16), IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2125 #endif
2126         // This instruction is followed by 32-bit value in LSW / MSW format...
2127         RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2128         dsp_pc += 4;
2129 #ifdef DSP_DIS_MOVEI
2130         if (doDSPDis)
2131                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2132 #endif
2133 }
2134
2135 static void dsp_opcode_moveta(void)
2136 {
2137 #ifdef DSP_DIS_MOVETA
2138         if (doDSPDis)
2139                 WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2140 #endif
2141         ALTERNATE_RN = RM;
2142 #ifdef DSP_DIS_MOVETA
2143         if (doDSPDis)
2144                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2145 #endif
2146 }
2147
2148 static void dsp_opcode_movefa(void)
2149 {
2150 #ifdef DSP_DIS_MOVEFA
2151         if (doDSPDis)
2152                 WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2153 #endif
2154         RN = ALTERNATE_RM;
2155 #ifdef DSP_DIS_MOVEFA
2156         if (doDSPDis)
2157                 WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2158 #endif
2159 }
2160
2161 static void dsp_opcode_move(void)
2162 {
2163 #ifdef DSP_DIS_MOVE
2164         if (doDSPDis)
2165                 WriteLog("%06X: MOVE   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2166 #endif
2167         RN = RM;
2168 #ifdef DSP_DIS_MOVE
2169         if (doDSPDis)
2170                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2171 #endif
2172 }
2173
2174 static void dsp_opcode_moveq(void)
2175 {
2176 #ifdef DSP_DIS_MOVEQ
2177         if (doDSPDis)
2178                 WriteLog("%06X: MOVEQ  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2179 #endif
2180         RN = IMM_1;
2181 #ifdef DSP_DIS_MOVEQ
2182         if (doDSPDis)
2183                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2184 #endif
2185 }
2186
2187 static void dsp_opcode_resmac(void)
2188 {
2189 #ifdef DSP_DIS_RESMAC
2190         if (doDSPDis)
2191                 WriteLog("%06X: RESMAC R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_ACC=%02X%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2192 #endif
2193         RN = (uint32_t)dsp_acc;
2194 #ifdef DSP_DIS_RESMAC
2195         if (doDSPDis)
2196                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2197 #endif
2198 }
2199
2200 static void dsp_opcode_imult(void)
2201 {
2202 #ifdef DSP_DIS_IMULT
2203         if (doDSPDis)
2204                 WriteLog("%06X: IMULT  R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2205 #endif
2206         RN = (int16_t)RN * (int16_t)RM;
2207         SET_ZN(RN);
2208 #ifdef DSP_DIS_IMULT
2209         if (doDSPDis)
2210                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2211 #endif
2212 }
2213
2214 static void dsp_opcode_mult(void)
2215 {
2216 #ifdef DSP_DIS_MULT
2217         if (doDSPDis)
2218                 WriteLog("%06X: MULT   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2219 #endif
2220         RN = (uint16_t)RM * (uint16_t)RN;
2221         SET_ZN(RN);
2222 #ifdef DSP_DIS_MULT
2223         if (doDSPDis)
2224                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2225 #endif
2226 }
2227
2228 static void dsp_opcode_bclr(void)
2229 {
2230 #ifdef DSP_DIS_BCLR
2231         if (doDSPDis)
2232                 WriteLog("%06X: BCLR   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2233 #endif
2234         uint32_t res = RN & ~(1 << IMM_1);
2235         RN = res;
2236         SET_ZN(res);
2237 #ifdef DSP_DIS_BCLR
2238         if (doDSPDis)
2239                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2240 #endif
2241 }
2242
2243 static void dsp_opcode_btst(void)
2244 {
2245 #ifdef DSP_DIS_BTST
2246         if (doDSPDis)
2247                 WriteLog("%06X: BTST   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2248 #endif
2249         dsp_flag_z = (~RN >> IMM_1) & 1;
2250 #ifdef DSP_DIS_BTST
2251         if (doDSPDis)
2252                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2253 #endif
2254 }
2255
2256 static void dsp_opcode_bset(void)
2257 {
2258 #ifdef DSP_DIS_BSET
2259         if (doDSPDis)
2260                 WriteLog("%06X: BSET   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2261 #endif
2262         uint32_t res = RN | (1 << IMM_1);
2263         RN = res;
2264         SET_ZN(res);
2265 #ifdef DSP_DIS_BSET
2266         if (doDSPDis)
2267                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2268 #endif
2269 }
2270
2271 static void dsp_opcode_subqt(void)
2272 {
2273 #ifdef DSP_DIS_SUBQT
2274         if (doDSPDis)
2275                 WriteLog("%06X: SUBQT  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2276 #endif
2277         RN -= dsp_convert_zero[IMM_1];
2278 #ifdef DSP_DIS_SUBQT
2279         if (doDSPDis)
2280                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2281 #endif
2282 }
2283
2284 static void dsp_opcode_addqt(void)
2285 {
2286 #ifdef DSP_DIS_ADDQT
2287         if (doDSPDis)
2288                 WriteLog("%06X: ADDQT  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2289 #endif
2290         RN += dsp_convert_zero[IMM_1];
2291 #ifdef DSP_DIS_ADDQT
2292         if (doDSPDis)
2293                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2294 #endif
2295 }
2296
2297 static void dsp_opcode_imacn(void)
2298 {
2299 #ifdef DSP_DIS_IMACN
2300         if (doDSPDis)
2301                 WriteLog("%06X: IMACN  R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2302 #endif
2303         int32_t res = (int16_t)RM * (int16_t)RN;
2304         dsp_acc += (int64_t)res;
2305 //Should we AND the result to fit into 40 bits here???
2306 #ifdef DSP_DIS_IMACN
2307         if (doDSPDis)
2308                 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));
2309 #endif
2310 }
2311
2312 static void dsp_opcode_mtoi(void)
2313 {
2314         RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2315         SET_ZN(RN);
2316 }
2317
2318 static void dsp_opcode_normi(void)
2319 {
2320         uint32_t _Rm = RM;
2321         uint32_t res = 0;
2322
2323         if (_Rm)
2324         {
2325                 while ((_Rm & 0xffc00000) == 0)
2326                 {
2327                         _Rm <<= 1;
2328                         res--;
2329                 }
2330                 while ((_Rm & 0xff800000) != 0)
2331                 {
2332                         _Rm >>= 1;
2333                         res++;
2334                 }
2335         }
2336         RN = res;
2337         SET_ZN(RN);
2338 }
2339
2340 static void dsp_opcode_mmult(void)
2341 {
2342         int count       = dsp_matrix_control&0x0f;
2343         uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2344         int64_t accum = 0;
2345         uint32_t res;
2346
2347         if (!(dsp_matrix_control & 0x10))
2348         {
2349                 for (int i = 0; i < count; i++)
2350                 {
2351                         int16_t a;
2352                         if (i&0x01)
2353                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2354                         else
2355                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2356                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2357                         accum += a*b;
2358                         addr += 4;
2359                 }
2360         }
2361         else
2362         {
2363                 for (int i = 0; i < count; i++)
2364                 {
2365                         int16_t a;
2366                         if (i&0x01)
2367                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2368                         else
2369                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2370                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2371                         accum += a*b;
2372                         addr += 4 * count;
2373                 }
2374         }
2375         RN = res = (int32_t)accum;
2376         // carry flag to do
2377 //NOTE: The flags are set based upon the last add/multiply done...
2378         SET_ZN(RN);
2379 }
2380
2381 static void dsp_opcode_abs(void)
2382 {
2383 #ifdef DSP_DIS_ABS
2384         if (doDSPDis)
2385                 WriteLog("%06X: ABS    R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2386 #endif
2387         uint32_t _Rn = RN;
2388         uint32_t res;
2389
2390         if (_Rn == 0x80000000)
2391                 dsp_flag_n = 1;
2392         else
2393         {
2394                 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2395                 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2396                 CLR_ZN; SET_Z(res);
2397         }
2398 #ifdef DSP_DIS_ABS
2399         if (doDSPDis)
2400                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2401 #endif
2402 }
2403
2404 static void dsp_opcode_div(void)
2405 {
2406         uint32_t _Rm=RM;
2407         uint32_t _Rn=RN;
2408
2409         if (_Rm)
2410         {
2411                 if (dsp_div_control & 1)
2412                 {
2413                         dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2414                         if (dsp_remain&0x80000000)
2415                                 dsp_remain-=_Rm;
2416                         RN = (((uint64_t)_Rn) << 16) / _Rm;
2417                 }
2418                 else
2419                 {
2420                         dsp_remain = _Rn % _Rm;
2421                         if (dsp_remain&0x80000000)
2422                                 dsp_remain-=_Rm;
2423                         RN/=_Rm;
2424                 }
2425         }
2426         else
2427                 RN=0xffffffff;
2428 }
2429
2430 static void dsp_opcode_imultn(void)
2431 {
2432 #ifdef DSP_DIS_IMULTN
2433         if (doDSPDis)
2434                 WriteLog("%06X: IMULTN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2435 #endif
2436         // This is OK, since this multiply won't overflow 32 bits...
2437         int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2438         dsp_acc = (int64_t)res;
2439         SET_ZN(res);
2440 #ifdef DSP_DIS_IMULTN
2441         if (doDSPDis)
2442                 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));
2443 #endif
2444 }
2445
2446 static void dsp_opcode_neg(void)
2447 {
2448 #ifdef DSP_DIS_NEG
2449         if (doDSPDis)
2450                 WriteLog("%06X: NEG    R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2451 #endif
2452         uint32_t res = -RN;
2453         SET_ZNC_SUB(0, RN, res);
2454         RN = res;
2455 #ifdef DSP_DIS_NEG
2456         if (doDSPDis)
2457                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2458 #endif
2459 }
2460
2461 static void dsp_opcode_shlq(void)
2462 {
2463 #ifdef DSP_DIS_SHLQ
2464         if (doDSPDis)
2465                 WriteLog("%06X: SHLQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, 32 - IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2466 #endif
2467         // NB: This instruction is the *only* one that does (32 - immediate data).
2468         int32_t r1 = 32 - IMM_1;
2469         uint32_t res = RN << r1;
2470         SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2471         RN = res;
2472 #ifdef DSP_DIS_SHLQ
2473         if (doDSPDis)
2474                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2475 #endif
2476 }
2477
2478 static void dsp_opcode_shrq(void)
2479 {
2480 #ifdef DSP_DIS_SHRQ
2481         if (doDSPDis)
2482                 WriteLog("%06X: SHRQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2483 #endif
2484         int32_t r1 = dsp_convert_zero[IMM_1];
2485         uint32_t res = RN >> r1;
2486         SET_ZN(res); dsp_flag_c = RN & 1;
2487         RN = res;
2488 #ifdef DSP_DIS_SHRQ
2489         if (doDSPDis)
2490                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2491 #endif
2492 }
2493
2494 static void dsp_opcode_ror(void)
2495 {
2496 #ifdef DSP_DIS_ROR
2497         if (doDSPDis)
2498                 WriteLog("%06X: ROR    R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2499 #endif
2500         uint32_t r1 = RM & 0x1F;
2501         uint32_t res = (RN >> r1) | (RN << (32 - r1));
2502         SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2503         RN = res;
2504 #ifdef DSP_DIS_ROR
2505         if (doDSPDis)
2506                 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2507 #endif
2508 }
2509
2510 static void dsp_opcode_rorq(void)
2511 {
2512 #ifdef DSP_DIS_RORQ
2513         if (doDSPDis)
2514                 WriteLog("%06X: RORQ   #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2515 #endif
2516         uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2517         uint32_t r2 = RN;
2518         uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2519         RN = res;
2520         SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2521 #ifdef DSP_DIS_RORQ
2522         if (doDSPDis)
2523                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2524 #endif
2525 }
2526
2527 static void dsp_opcode_sha(void)
2528 {
2529         int32_t sRm=(int32_t)RM;
2530         uint32_t _Rn=RN;
2531
2532         if (sRm<0)
2533         {
2534                 uint32_t shift=-sRm;
2535                 if (shift>=32) shift=32;
2536                 dsp_flag_c=(_Rn&0x80000000)>>31;
2537                 while (shift)
2538                 {
2539                         _Rn<<=1;
2540                         shift--;
2541                 }
2542         }
2543         else
2544         {
2545                 uint32_t shift=sRm;
2546                 if (shift>=32) shift=32;
2547                 dsp_flag_c=_Rn&0x1;
2548                 while (shift)
2549                 {
2550                         _Rn=((int32_t)_Rn)>>1;
2551                         shift--;
2552                 }
2553         }
2554         RN = _Rn;
2555         SET_ZN(RN);
2556 }
2557
2558 static void dsp_opcode_sharq(void)
2559 {
2560 #ifdef DSP_DIS_SHARQ
2561         if (doDSPDis)
2562                 WriteLog("%06X: SHARQ  #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2563 #endif
2564         uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2565         SET_ZN(res); dsp_flag_c = RN & 0x01;
2566         RN = res;
2567 #ifdef DSP_DIS_SHARQ
2568         if (doDSPDis)
2569                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2570 #endif
2571 }
2572
2573 static void dsp_opcode_sh(void)
2574 {
2575         int32_t sRm=(int32_t)RM;
2576         uint32_t _Rn=RN;
2577
2578         if (sRm<0)
2579         {
2580                 uint32_t shift=(-sRm);
2581                 if (shift>=32) shift=32;
2582                 dsp_flag_c=(_Rn&0x80000000)>>31;
2583                 while (shift)
2584                 {
2585                         _Rn<<=1;
2586                         shift--;
2587                 }
2588         }
2589         else
2590         {
2591                 uint32_t shift=sRm;
2592                 if (shift>=32) shift=32;
2593                 dsp_flag_c=_Rn&0x1;
2594                 while (shift)
2595                 {
2596                         _Rn>>=1;
2597                         shift--;
2598                 }
2599         }
2600         RN = _Rn;
2601         SET_ZN(RN);
2602 }
2603
2604 void dsp_opcode_addqmod(void)
2605 {
2606 #ifdef DSP_DIS_ADDQMOD
2607         if (doDSPDis)
2608                 WriteLog("%06X: ADDQMOD #%u, R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_MOD=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_modulo);
2609 #endif
2610         uint32_t r1 = dsp_convert_zero[IMM_1];
2611         uint32_t r2 = RN;
2612         uint32_t res = r2 + r1;
2613         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2614         RN = res;
2615         SET_ZNC_ADD(r2, r1, res);
2616 #ifdef DSP_DIS_ADDQMOD
2617         if (doDSPDis)
2618                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2619 #endif
2620 }
2621
2622 void dsp_opcode_subqmod(void)
2623 {
2624         uint32_t r1 = dsp_convert_zero[IMM_1];
2625         uint32_t r2 = RN;
2626         uint32_t res = r2 - r1;
2627         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2628         RN = res;
2629
2630         SET_ZNC_SUB(r2, r1, res);
2631 }
2632
2633 void dsp_opcode_mirror(void)
2634 {
2635         uint32_t r1 = RN;
2636         RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2637         SET_ZN(RN);
2638 }
2639
2640 void dsp_opcode_sat32s(void)
2641 {
2642         int32_t r2 = (uint32_t)RN;
2643         int32_t temp = dsp_acc >> 32;
2644         uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2645         RN = res;
2646         SET_ZN(res);
2647 }
2648
2649 void dsp_opcode_sat16s(void)
2650 {
2651         int32_t r2 = RN;
2652         uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2653         RN = res;
2654         SET_ZN(res);
2655 }
2656
2657 void dsp_opcode_illegal(void)
2658 {
2659         // Don't know what it does, but it does *something*...
2660         WriteLog("%06X: illegal %u, %u [NCZ:%u%u%u]\n", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2661 }
2662
2663 //
2664 // New pipelined DSP core
2665 //
2666
2667 static void DSP_abs(void);
2668 static void DSP_add(void);
2669 static void DSP_addc(void);
2670 static void DSP_addq(void);
2671 static void DSP_addqmod(void);
2672 static void DSP_addqt(void);
2673 static void DSP_and(void);
2674 static void DSP_bclr(void);
2675 static void DSP_bset(void);
2676 static void DSP_btst(void);
2677 static void DSP_cmp(void);
2678 static void DSP_cmpq(void);
2679 static void DSP_div(void);
2680 static void DSP_imacn(void);
2681 static void DSP_imult(void);
2682 static void DSP_imultn(void);
2683 static void DSP_illegal(void);
2684 static void DSP_jr(void);
2685 static void DSP_jump(void);
2686 static void DSP_load(void);
2687 static void DSP_loadb(void);
2688 static void DSP_loadw(void);
2689 static void DSP_load_r14_i(void);
2690 static void DSP_load_r14_r(void);
2691 static void DSP_load_r15_i(void);
2692 static void DSP_load_r15_r(void);
2693 static void DSP_mirror(void);
2694 static void DSP_mmult(void);
2695 static void DSP_move(void);
2696 static void DSP_movefa(void);
2697 static void DSP_movei(void);
2698 static void DSP_movepc(void);
2699 static void DSP_moveq(void);
2700 static void DSP_moveta(void);
2701 static void DSP_mtoi(void);
2702 static void DSP_mult(void);
2703 static void DSP_neg(void);
2704 static void DSP_nop(void);
2705 static void DSP_normi(void);
2706 static void DSP_not(void);
2707 static void DSP_or(void);
2708 static void DSP_resmac(void);
2709 static void DSP_ror(void);
2710 static void DSP_rorq(void);
2711 static void DSP_sat16s(void);
2712 static void DSP_sat32s(void);
2713 static void DSP_sh(void);
2714 static void DSP_sha(void);
2715 static void DSP_sharq(void);
2716 static void DSP_shlq(void);
2717 static void DSP_shrq(void);
2718 static void DSP_store(void);
2719 static void DSP_storeb(void);
2720 static void DSP_storew(void);
2721 static void DSP_store_r14_i(void);
2722 static void DSP_store_r14_r(void);
2723 static void DSP_store_r15_i(void);
2724 static void DSP_store_r15_r(void);
2725 static void DSP_sub(void);
2726 static void DSP_subc(void);
2727 static void DSP_subq(void);
2728 static void DSP_subqmod(void);
2729 static void DSP_subqt(void);
2730 static void DSP_xor(void);
2731
2732 void (* DSPOpcode[64])() =
2733 {
2734         DSP_add,                        DSP_addc,                       DSP_addq,                       DSP_addqt,
2735         DSP_sub,                        DSP_subc,                       DSP_subq,                       DSP_subqt,
2736         DSP_neg,                        DSP_and,                        DSP_or,                         DSP_xor,
2737         DSP_not,                        DSP_btst,                       DSP_bset,                       DSP_bclr,
2738
2739         DSP_mult,                       DSP_imult,                      DSP_imultn,                     DSP_resmac,
2740         DSP_imacn,                      DSP_div,                        DSP_abs,                        DSP_sh,
2741         DSP_shlq,                       DSP_shrq,                       DSP_sha,                        DSP_sharq,
2742         DSP_ror,                        DSP_rorq,                       DSP_cmp,                        DSP_cmpq,
2743
2744         DSP_subqmod,            DSP_sat16s,                     DSP_move,                       DSP_moveq,
2745         DSP_moveta,                     DSP_movefa,                     DSP_movei,                      DSP_loadb,
2746         DSP_loadw,                      DSP_load,                       DSP_sat32s,                     DSP_load_r14_i,
2747         DSP_load_r15_i,         DSP_storeb,                     DSP_storew,                     DSP_store,
2748
2749         DSP_mirror,                     DSP_store_r14_i,        DSP_store_r15_i,        DSP_movepc,
2750         DSP_jump,                       DSP_jr,                         DSP_mmult,                      DSP_mtoi,
2751         DSP_normi,                      DSP_nop,                        DSP_load_r14_r,         DSP_load_r15_r,
2752         DSP_store_r14_r,        DSP_store_r15_r,        DSP_illegal,            DSP_addqmod
2753 };
2754
2755 bool readAffected[64][2] =
2756 {
2757         { true,  true}, { true,  true}, {false,  true}, {false,  true},
2758         { true,  true}, { true,  true}, {false,  true}, {false,  true},
2759         {false,  true}, { true,  true}, { true,  true}, { true,  true},
2760         {false,  true}, {false,  true}, {false,  true}, {false,  true},
2761
2762         { true,  true}, { true,  true}, { true,  true}, {false,  true},
2763         { true,  true}, { true,  true}, {false,  true}, { true,  true},
2764         {false,  true}, {false,  true}, { true,  true}, {false,  true},
2765         { true,  true}, {false,  true}, { true,  true}, {false,  true},
2766
2767         {false,  true}, {false,  true}, { true, false}, {false, false},
2768         { true, false}, {false, false}, {false, false}, { true, false},
2769         { true, false}, { true, false}, {false,  true}, { true, false},
2770         { true, false}, { true,  true}, { true,  true}, { true,  true},
2771
2772         {false,  true}, { true,  true}, { true,  true}, {false,  true},
2773         { true, false}, { true, false}, { true,  true}, { true, false},
2774         { true, false}, {false, false}, { true, false}, { true, false},
2775         { true,  true}, { true,  true}, {false, false}, {false,  true}
2776 };
2777
2778 bool isLoadStore[65] =
2779 {
2780         false, false, false, false, false, false, false, false,
2781         false, false, false, false, false, false, false, false,
2782
2783         false, false, false, false, false, false, false, false,
2784         false, false, false, false, false, false, false, false,
2785
2786         false, false, false, false, false, false, false,  true,
2787          true,  true, false,  true,  true,  true,  true,  true,
2788
2789         false,  true,  true, false, false, false, false, false,
2790         false, false,  true,  true,  true,  true, false, false, false
2791 };
2792
2793 void FlushDSPPipeline(void)
2794 {
2795         plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2796
2797         for(int i=0; i<4; i++)
2798                 pipeline[i].opcode = PIPELINE_STALL;
2799
2800         for(int i=0; i<32; i++)
2801                 scoreboard[i] = 0;
2802 }
2803
2804 //
2805 // New pipelined DSP execution core
2806 //
2807 /*void DSPExecP(int32_t cycles)
2808 {
2809 //      bool inhibitFetch = false;
2810
2811         dsp_releaseTimeSlice_flag = 0;
2812         dsp_in_exec++;
2813
2814         while (cycles > 0 && DSP_RUNNING)
2815         {
2816 WriteLog("DSPExecP: Pipeline status...\n");
2817 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2818 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2819 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2820 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2821 WriteLog("  --> Scoreboard: ");
2822 for(int i=0; i<32; i++)
2823         WriteLog("%s ", scoreboard[i] ? "T" : "F");
2824 WriteLog("\n");
2825                 // Stage 1: Instruction fetch
2826 //              if (!inhibitFetch)
2827 //              {
2828                 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2829                 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2830                 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2831                 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2832                 if (pipeline[plPtrFetch].opcode == 38)
2833                         pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2834                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2835 //              }
2836 //              else
2837 //                      inhibitFetch = false;
2838 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2839
2840 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2841 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2842 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2843 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2844 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2845                 // Stage 2: Read registers
2846 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2847 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2848                 if (scoreboard[pipeline[plPtrRead].operand2])
2849                         && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2850                         // We have a hit in the scoreboard, so we have to stall the pipeline...
2851 {
2852 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2853 //                      dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2854 WriteLog("  --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2855                         pipeline[plPtrFetch] = pipeline[plPtrRead];
2856                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
2857 }
2858                 else
2859                 {
2860                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2861                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2862                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
2863
2864                         if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2865                         // Shouldn't we be more selective with the register scoreboarding?
2866                         // Yes, we should. !!! FIX !!!
2867                         scoreboard[pipeline[plPtrRead].operand2] = true;
2868 //Advance PC here??? Yes.
2869 //                      dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2870 //This is a mangling of the pipeline stages, but what else to do???
2871                         dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2872                 }
2873
2874 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2875 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2876 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2877 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2878 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2879                 // Stage 3: Execute
2880                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2881                 {
2882 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2883                         DSPOpcode[pipeline[plPtrExec].opcode]();
2884                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2885                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2886                 }
2887                 else
2888                         cycles--;
2889
2890 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2891 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2892 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2893 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2894 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2895                 // Stage 4: Write back register
2896                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2897                 {
2898                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2899                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2900
2901                         scoreboard[pipeline[plPtrWrite].operand1]
2902                                 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2903                 }
2904
2905                 // Push instructions through the pipeline...
2906                 plPtrFetch = (++plPtrFetch) & 0x03;
2907                 plPtrRead = (++plPtrRead) & 0x03;
2908                 plPtrExec = (++plPtrExec) & 0x03;
2909                 plPtrWrite = (++plPtrWrite) & 0x03;
2910         }
2911
2912         dsp_in_exec--;
2913 }*/
2914
2915
2916 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2917 //!!! FIX !!!
2918 // Should be fixed now. Another problem is figuring how to do the sequence following
2919 // a branch followed with the JR & JUMP instructions...
2920 //
2921 // There are two conflicting problems:
2922
2923 /*
2924 F1B236: LOAD   (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2925 F1B238: BCLR   #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2926 F1B23A: ADDQ   #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2927 F1B23C: SUBQ   #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2928 F1B23E: MOVEI  #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2929 F1B244: JR     z, F1B254 [NCZ:000] Branch NOT taken.
2930 F1B246: BSET   #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2931 F1B248: MOVEI  #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2932 F1B24E: STORE  R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2933 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2934 DSP: Finished interrupt.
2935 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2936 ; bank 0 (where is was prepared)!
2937 F1B250: JUMP   T, (R03) [NCZ:001, R03=00000000] Branched!
2938 F1B252: NOP    [NCZ:001]
2939 */
2940
2941 // The other is when you see this at the end of an IRQ:
2942
2943 /*
2944 JUMP   T, (R29)         ; R29 = Previous stack + 2
2945 STORE  R28, (R30)       ; R28 = Modified flags register, R30 = $F1A100
2946
2947 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2948 ; 1) The STORE goes through the pipeline and is executed/written back
2949 ; 2) The pipeline is flushed
2950 ; 3) The DSP_PC is set to the new address
2951 ; 4) Execution resumes
2952
2953 JUMP   T, (R25)         ; Oops! Because of pipeline effects R25 has the value from
2954                                         ; bank 0 instead of the current bank 1 and so goes astray!
2955 */
2956
2957 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2958 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2959
2960
2961 /*
2962 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2963 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2964 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2965 If it were done properly, the STORE write back would occur *after* (well, technically,
2966 during) the execution of the the JUMP that follows it.
2967
2968 !!! FIX !!! [DONE]
2969
2970 F1B08A: JR     z, F1B082 [NCZ:001] Branched!
2971 F1B08A: NOP    [NCZ:001]
2972 [STALL...]
2973 F1B080: MOVEI  #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2974 [STALL...]
2975 [STALL...]
2976 F1B086: LOAD   (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2977 [STALL...]
2978 [STALL...]
2979 F1B088: OR     R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2980 F1B08A: JR     z, F1B082 [NCZ:001] Branched!
2981 F1B08A: NOP    [NCZ:001]
2982 [STALL...]
2983 F1B080: MOVEI  #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2984 [STALL...]
2985 [STALL...]
2986 Write to DSP CTRL: 00002301  --> Starting to run at 00F1B088 by M68K...
2987 DSP: CPU -> DSP interrupt
2988 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2989 Write to DSP CTRL: 00000001  --> Starting to run at 00F1B000 by M68K...
2990 [STALL...]
2991 F1B000: MOVEI  #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2992 [STALL...]
2993 [STALL...]
2994 F1B006: JUMP   T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2995 F1B006: NOP    [NCZ:001]
2996 [STALL...]
2997 F1B0D4: MOVEI  #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2998 [STALL...]
2999 [STALL...]
3000 F1B0DA: LOAD   (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3001 F1B0DC: MOVEI  #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3002 [STALL...]
3003 [STALL...]
3004 F1B0E2: LOAD   (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3005 F1B0E4: MOVEI  #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3006 [STALL...]
3007 [STALL...]
3008 F1B0EA: LOAD   (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3009 F1B0EC: MOVEI  #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3010 [STALL...]
3011 [STALL...]
3012 F1B0F2: LOAD   (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3013 F1B0F4: MOVEI  #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3014 [STALL...]
3015 [STALL...]
3016 F1B0FA: ADD    R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3017 [STALL...]
3018 [STALL...]
3019 F1B0FC: LOAD   (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3020 [STALL...]
3021 [STALL...]
3022 F1B0FE: JUMP   T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3023 F1B0FE: NOP    [NCZ:000]
3024 [STALL...]
3025 F1B12E: MOVE   R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3026 [STALL...]
3027 [STALL...]
3028 F1B132: MOVEI  #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3029 [STALL...]
3030 [STALL...]
3031 F1B138: JUMP   T, (R01) [NCZ:000, R01=00F1B102] Branched!
3032 F1B138: NOP    [NCZ:000]
3033 [STALL...]
3034 F1B102: MOVEI  #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3035 [STALL...]
3036 [STALL...]
3037 F1B108: STORE  R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3038 F1B10A: MOVEI  #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3039 F1B110: MOVEQ  #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3040 [STALL...]
3041 [STALL...]
3042 F1B112: STORE  R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3043 F1B114: BCLR   #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3044 [STALL...]
3045 [STALL...]
3046 F1B116: BSET   #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3047 F1B118: LOAD   (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3048 F1B11A: MOVEI  #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3049 [STALL...]
3050 F1B120: ADDQ   #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3051 F1B122: MOVEI  #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3052 [STALL...]
3053 [STALL...]
3054 F1B128: STORE  R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3055 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3056 DSP: Finished interrupt.
3057 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3058 [STALL...]
3059 F1B010: MOVEI  #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3060 [STALL...]
3061 [STALL...]
3062 F1B016: JUMP   T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3063 F1B016: NOP    [NCZ:001]
3064 [STALL...]
3065 F1B1FC: MOVEI  #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3066 */
3067
3068 uint32_t pcQueue1[0x400];
3069 uint32_t pcQPtr1 = 0;
3070 static uint32_t prevR1;
3071 //Let's try a 3 stage pipeline....
3072 //Looks like 3 stage is correct, otherwise bad things happen...
3073 void DSPExecP2(int32_t cycles)
3074 {
3075         dsp_releaseTimeSlice_flag = 0;
3076         dsp_in_exec++;
3077
3078         while (cycles > 0 && DSP_RUNNING)
3079         {
3080 /*extern uint32_t totalFrames;
3081 //F1B2F6: LOAD   (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3082 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3083 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3084 //F1B140:
3085 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3086 {
3087         doDSPDis = true;
3088         WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3089 }
3090 if (dsp_pc == 0xF1B092)
3091         doDSPDis = false;//*/
3092 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3093         doDSPDis = true;//*/
3094 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3095         doDSPDis = true;//*/
3096 /*if (dsp_pc == 0xF1B0A0)
3097         doDSPDis = true;//*/
3098 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3099         doDSPDis = true;//*/
3100 //Two parter... (not sure how to write this)
3101 //if (dsp_pc == 0xF1B0D2)
3102 //      prevR1 = dsp_reg[1];
3103
3104 //F1B0D2: ADDQT  #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3105 //F1B0D2: ADDQT  #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3106
3107
3108 pcQueue1[pcQPtr1++] = dsp_pc;
3109 pcQPtr1 &= 0x3FF;
3110
3111 #ifdef DSP_DEBUG_PL2
3112 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3113 {
3114         WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3115         doDSPDis = true;
3116
3117         char buffer[512];
3118
3119         for(int i=0; i<0x400; i++)
3120         {
3121                 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3122                 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3123         }
3124         WriteLog("\n");
3125 }//*/
3126 #endif
3127
3128                 if (IMASKCleared)                                               // If IMASK was cleared,
3129                 {
3130 #ifdef DSP_DEBUG_IRQ
3131                         WriteLog("DSP: Finished interrupt.\n");
3132 #endif
3133                         DSPHandleIRQs();                                        // See if any other interrupts are pending!
3134                         IMASKCleared = false;
3135                 }
3136
3137 //if (dsp_flags & REGPAGE)
3138 //      WriteLog("  --> REGPAGE has just been set!\n");
3139 #ifdef DSP_DEBUG_PL2
3140 if (doDSPDis)
3141 {
3142 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3143 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]);
3144 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]);
3145 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]);
3146 WriteLog("  --> Scoreboard: ");
3147 for(int i=0; i<32; i++)
3148         WriteLog("%s ", scoreboard[i] ? "T" : "F");
3149 WriteLog("\n");
3150 }
3151 #endif
3152                 // Stage 1a: Instruction fetch
3153                 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3154                 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3155                 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3156                 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3157                 if (pipeline[plPtrRead].opcode == 38)
3158                         pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3159                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3160 #ifdef DSP_DEBUG_PL2
3161 if (doDSPDis)
3162 {
3163 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3164 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3165 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]);
3166 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]);
3167 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]);
3168 }
3169 #endif
3170                 // Stage 1b: Read registers
3171 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3172 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3173 //Ugly, but [DONE]
3174 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3175 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3176                 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3177                         || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3178                         || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3179                         || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3180 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3181 //work--somewhat...
3182                         || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3183                         // We have a hit in the scoreboard, so we have to stall the pipeline...
3184 #ifdef DSP_DEBUG_PL2
3185 {
3186 if (doDSPDis)
3187 {
3188 WriteLog("  --> Stalling pipeline: ");
3189 if (readAffected[pipeline[plPtrRead].opcode][0])
3190         WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3191 if (readAffected[pipeline[plPtrRead].opcode][1])
3192         WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3193 WriteLog("\n");
3194 }
3195 #endif
3196                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
3197 #ifdef DSP_DEBUG_PL2
3198 }
3199 #endif
3200                 else
3201                 {
3202                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3203                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3204                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
3205
3206                         // Shouldn't we be more selective with the register scoreboarding?
3207                         // Yes, we should. !!! FIX !!! Kinda [DONE]
3208 #ifndef NEW_SCOREBOARD
3209                         scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3210 #else
3211 //Hopefully this will fix the dual MOVEQ # problem...
3212                         scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3213 #endif
3214
3215 //Advance PC here??? Yes.
3216                         dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3217                 }
3218
3219 #ifdef DSP_DEBUG_PL2
3220 if (doDSPDis)
3221 {
3222 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3223 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]);
3224 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]);
3225 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]);
3226 }
3227 #endif
3228                 // Stage 2: Execute
3229                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3230                 {
3231 #ifdef DSP_DEBUG_PL2
3232 if (doDSPDis)
3233         WriteLog("\t[inst=%02u][R28=%08X, alt R28=%08X, REGPAGE=%s]\n", pipeline[plPtrExec].opcode, dsp_reg[28], dsp_alternate_reg[28], (dsp_flags & REGPAGE ? "set" : "not set"));
3234
3235 if (doDSPDis)
3236 {
3237 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3238 }
3239 #endif
3240 //CC only!
3241 #ifdef DSP_DEBUG_CC
3242 lastExec = pipeline[plPtrExec].instruction;
3243 //WriteLog("[lastExec = %04X]\n", lastExec);
3244 #endif
3245                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3246                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3247                         DSPOpcode[pipeline[plPtrExec].opcode]();
3248 //WriteLog("    --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3249                 }
3250                 else
3251 {
3252 //Let's not, until we do the stalling correctly...
3253 //But, we gotta while we're doing the comparison core...!
3254 //Or do we?                     cycles--;
3255 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3256 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3257 //to model this clock cycle behavior correctly...
3258 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3259 //don't affect the reads at stage 1...
3260 #ifdef DSP_DEBUG_STALL
3261 if (doDSPDis)
3262         WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3263 #endif
3264 }
3265
3266 #ifdef DSP_DEBUG_PL2
3267 if (doDSPDis)
3268 {
3269 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3270 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]);
3271 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]);
3272 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]);
3273 WriteLog("\n");
3274 }
3275 #endif
3276                 // Stage 3: Write back register/memory address
3277                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3278                 {
3279 /*if (pipeline[plPtrWrite].writebackRegister == 3
3280         && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3281         && !doDSPDis)
3282 {
3283         WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3284         doDSPDis = true;
3285 }//*/
3286                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3287                         {
3288                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3289                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3290                                 else
3291                                 {
3292                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3293                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3294                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3295                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3296                                         else
3297                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3298                                 }
3299                         }
3300
3301 #ifndef NEW_SCOREBOARD
3302                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3303                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3304 #else
3305 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3306                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3307                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3308                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3309 #endif
3310                 }
3311
3312                 // Push instructions through the pipeline...
3313                 plPtrRead = (++plPtrRead) & 0x03;
3314                 plPtrExec = (++plPtrExec) & 0x03;
3315                 plPtrWrite = (++plPtrWrite) & 0x03;
3316         }
3317
3318         dsp_in_exec--;
3319 }
3320
3321
3322
3323 /*
3324 //#define DSP_DEBUG_PL3
3325 //Let's try a 2 stage pipeline....
3326 void DSPExecP3(int32_t cycles)
3327 {
3328         dsp_releaseTimeSlice_flag = 0;
3329         dsp_in_exec++;
3330
3331         while (cycles > 0 && DSP_RUNNING)
3332         {
3333 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3334 //      doDSPDis = true;
3335 #ifdef DSP_DEBUG_PL3
3336 WriteLog("DSPExecP: Pipeline status...\n");
3337 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]);
3338 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]);
3339 WriteLog("  --> Scoreboard: ");
3340 for(int i=0; i<32; i++)
3341         WriteLog("%s ", scoreboard[i] ? "T" : "F");
3342 WriteLog("\n");
3343 #endif
3344                 // Stage 1a: Instruction fetch
3345                 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3346                 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3347                 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3348                 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3349                 if (pipeline[plPtrRead].opcode == 38)
3350                         pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3351                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3352 #ifdef DSP_DEBUG_PL3
3353 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3354 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3355 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]);
3356 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]);
3357 #endif
3358                 // Stage 1b: Read registers
3359                 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3360                         || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3361                         // We have a hit in the scoreboard, so we have to stall the pipeline...
3362 #ifdef DSP_DEBUG_PL3
3363 {
3364 WriteLog("  --> Stalling pipeline: ");
3365 if (readAffected[pipeline[plPtrRead].opcode][0])
3366         WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3367 if (readAffected[pipeline[plPtrRead].opcode][1])
3368         WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3369 WriteLog("\n");
3370 #endif
3371                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
3372 #ifdef DSP_DEBUG_PL3
3373 }
3374 #endif
3375                 else
3376                 {
3377                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3378                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3379                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
3380
3381                         // Shouldn't we be more selective with the register scoreboarding?
3382                         // Yes, we should. !!! FIX !!! [Kinda DONE]
3383                         scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3384
3385 //Advance PC here??? Yes.
3386                         dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3387                 }
3388
3389 #ifdef DSP_DEBUG_PL3
3390 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3391 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]);
3392 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]);
3393 #endif
3394                 // Stage 2a: Execute
3395                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3396                 {
3397 #ifdef DSP_DEBUG_PL3
3398 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3399 #endif
3400                         DSPOpcode[pipeline[plPtrExec].opcode]();
3401                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3402                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3403                 }
3404                 else
3405                         cycles--;
3406
3407 #ifdef DSP_DEBUG_PL3
3408 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3409 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]);
3410 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]);
3411 WriteLog("\n");
3412 #endif
3413                 // Stage 2b: Write back register
3414                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3415                 {
3416                         if (pipeline[plPtrExec].writebackRegister != 0xFF)
3417                                 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3418
3419                         if (affectsScoreboard[pipeline[plPtrExec].opcode])
3420                                 scoreboard[pipeline[plPtrExec].operand2] = false;
3421                 }
3422
3423                 // Push instructions through the pipeline...
3424                 plPtrRead = (++plPtrRead) & 0x03;
3425                 plPtrExec = (++plPtrExec) & 0x03;
3426         }
3427
3428         dsp_in_exec--;
3429 }*/
3430
3431 //
3432 // DSP pipelined opcode handlers
3433 //
3434
3435 #define PRM                             pipeline[plPtrExec].reg1
3436 #define PRN                             pipeline[plPtrExec].reg2
3437 #define PIMM1                   pipeline[plPtrExec].operand1
3438 #define PIMM2                   pipeline[plPtrExec].operand2
3439 #define PRES                    pipeline[plPtrExec].result
3440 #define PWBR                    pipeline[plPtrExec].writebackRegister
3441 #define NO_WRITEBACK    pipeline[plPtrExec].writebackRegister = 0xFF
3442 //#define DSP_PPC                       dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3443 #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))
3444 #define WRITEBACK_ADDR  pipeline[plPtrExec].writebackRegister = 0xFE
3445
3446 static void DSP_abs(void)
3447 {
3448 #ifdef DSP_DIS_ABS
3449         if (doDSPDis)
3450                 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);
3451 #endif
3452         uint32_t _Rn = PRN;
3453
3454         if (_Rn == 0x80000000)
3455                 dsp_flag_n = 1;
3456         else
3457         {
3458                 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3459                 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3460                 CLR_ZN; SET_Z(PRES);
3461         }
3462 #ifdef DSP_DIS_ABS
3463         if (doDSPDis)
3464                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3465 #endif
3466 }
3467
3468 static void DSP_add(void)
3469 {
3470 #ifdef DSP_DIS_ADD
3471         if (doDSPDis)
3472                 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);
3473 #endif
3474         uint32_t res = PRN + PRM;
3475         SET_ZNC_ADD(PRN, PRM, res);
3476         PRES = res;
3477 #ifdef DSP_DIS_ADD
3478         if (doDSPDis)
3479                 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);
3480 #endif
3481 }
3482
3483 static void DSP_addc(void)
3484 {
3485 #ifdef DSP_DIS_ADDC
3486         if (doDSPDis)
3487                 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);
3488 #endif
3489         uint32_t res = PRN + PRM + dsp_flag_c;
3490         uint32_t carry = dsp_flag_c;
3491 //      SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3492         SET_ZNC_ADD(PRN + carry, PRM, res);
3493 //      SET_ZNC_ADD(PRN, PRM + carry, res);
3494         PRES = res;
3495 #ifdef DSP_DIS_ADDC
3496         if (doDSPDis)
3497                 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);
3498 #endif
3499 }
3500
3501 static void DSP_addq(void)
3502 {
3503 #ifdef DSP_DIS_ADDQ
3504         if (doDSPDis)
3505                 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);
3506 #endif
3507         uint32_t r1 = dsp_convert_zero[PIMM1];
3508         uint32_t res = PRN + r1;
3509         CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3510         PRES = res;
3511 #ifdef DSP_DIS_ADDQ
3512         if (doDSPDis)
3513                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3514 #endif
3515 }
3516
3517 static void DSP_addqmod(void)
3518 {
3519 #ifdef DSP_DIS_ADDQMOD
3520         if (doDSPDis)
3521                 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);
3522 #endif
3523         uint32_t r1 = dsp_convert_zero[PIMM1];
3524         uint32_t r2 = PRN;
3525         uint32_t res = r2 + r1;
3526         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3527         PRES = res;
3528         SET_ZNC_ADD(r2, r1, res);
3529 #ifdef DSP_DIS_ADDQMOD
3530         if (doDSPDis)
3531                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3532 #endif
3533 }
3534
3535 static void DSP_addqt(void)
3536 {
3537 #ifdef DSP_DIS_ADDQT
3538         if (doDSPDis)
3539                 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);
3540 #endif
3541         PRES = PRN + dsp_convert_zero[PIMM1];
3542 #ifdef DSP_DIS_ADDQT
3543         if (doDSPDis)
3544                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3545 #endif
3546 }
3547
3548 static void DSP_and(void)
3549 {
3550 #ifdef DSP_DIS_AND
3551         if (doDSPDis)
3552                 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);
3553 #endif
3554         PRES = PRN & PRM;
3555         SET_ZN(PRES);
3556 #ifdef DSP_DIS_AND
3557         if (doDSPDis)
3558                 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);
3559 #endif
3560 }
3561
3562 static void DSP_bclr(void)
3563 {
3564 #ifdef DSP_DIS_BCLR
3565         if (doDSPDis)
3566                 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);
3567 #endif
3568         PRES = PRN & ~(1 << PIMM1);
3569         SET_ZN(PRES);
3570 #ifdef DSP_DIS_BCLR
3571         if (doDSPDis)
3572                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3573 #endif
3574 }
3575
3576 static void DSP_bset(void)
3577 {
3578 #ifdef DSP_DIS_BSET
3579         if (doDSPDis)
3580                 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);
3581 #endif
3582         PRES = PRN | (1 << PIMM1);
3583         SET_ZN(PRES);
3584 #ifdef DSP_DIS_BSET
3585         if (doDSPDis)
3586                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3587 #endif
3588 }
3589
3590 static void DSP_btst(void)
3591 {
3592 #ifdef DSP_DIS_BTST
3593         if (doDSPDis)
3594                 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);
3595 #endif
3596         dsp_flag_z = (~PRN >> PIMM1) & 1;
3597         NO_WRITEBACK;
3598 #ifdef DSP_DIS_BTST
3599         if (doDSPDis)
3600                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3601 #endif
3602 }
3603
3604 static void DSP_cmp(void)
3605 {
3606 #ifdef DSP_DIS_CMP
3607         if (doDSPDis)
3608                 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);
3609 #endif
3610         uint32_t res = PRN - PRM;
3611         SET_ZNC_SUB(PRN, PRM, res);
3612         NO_WRITEBACK;
3613 #ifdef DSP_DIS_CMP
3614         if (doDSPDis)
3615                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3616 #endif
3617 }
3618
3619 static void DSP_cmpq(void)
3620 {
3621         static int32_t sqtable[32] =
3622                 { 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 };
3623 #ifdef DSP_DIS_CMPQ
3624         if (doDSPDis)
3625                 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);
3626 #endif
3627         uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3628         uint32_t res = PRN - r1;
3629         SET_ZNC_SUB(PRN, r1, res);
3630         NO_WRITEBACK;
3631 #ifdef DSP_DIS_CMPQ
3632         if (doDSPDis)
3633                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3634 #endif
3635 }
3636
3637 static void DSP_div(void)
3638 {
3639         uint32_t _Rm = PRM, _Rn = PRN;
3640
3641         if (_Rm)
3642         {
3643                 if (dsp_div_control & 1)
3644                 {
3645                         dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3646                         if (dsp_remain & 0x80000000)
3647                                 dsp_remain -= _Rm;
3648                         PRES = (((uint64_t)_Rn) << 16) / _Rm;
3649                 }
3650                 else
3651                 {
3652                         dsp_remain = _Rn % _Rm;
3653                         if (dsp_remain & 0x80000000)
3654                                 dsp_remain -= _Rm;
3655                         PRES = PRN / _Rm;
3656                 }
3657         }
3658         else
3659                 PRES = 0xFFFFFFFF;
3660 }
3661
3662 static void DSP_imacn(void)
3663 {
3664 #ifdef DSP_DIS_IMACN
3665         if (doDSPDis)
3666                 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);
3667 #endif
3668         int32_t res = (int16_t)PRM * (int16_t)PRN;
3669         dsp_acc += (int64_t)res;
3670 //Should we AND the result to fit into 40 bits here???
3671         NO_WRITEBACK;
3672 #ifdef DSP_DIS_IMACN
3673         if (doDSPDis)
3674                 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));
3675 #endif
3676 }
3677
3678 static void DSP_imult(void)
3679 {
3680 #ifdef DSP_DIS_IMULT
3681         if (doDSPDis)
3682                 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);
3683 #endif
3684         PRES = (int16_t)PRN * (int16_t)PRM;
3685         SET_ZN(PRES);
3686 #ifdef DSP_DIS_IMULT
3687         if (doDSPDis)
3688                 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);
3689 #endif
3690 }
3691
3692 static void DSP_imultn(void)
3693 {
3694 #ifdef DSP_DIS_IMULTN
3695         if (doDSPDis)
3696                 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);
3697 #endif
3698         // This is OK, since this multiply won't overflow 32 bits...
3699         int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3700         dsp_acc = (int64_t)res;
3701         SET_ZN(res);
3702         NO_WRITEBACK;
3703 #ifdef DSP_DIS_IMULTN
3704         if (doDSPDis)
3705                 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));
3706 #endif
3707 }
3708
3709 static void DSP_illegal(void)
3710 {
3711 #ifdef DSP_DIS_ILLEGAL
3712         if (doDSPDis)
3713                 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3714 #endif
3715         NO_WRITEBACK;
3716 }
3717
3718 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3719 // can cause trouble because an interrupt can occur *before* the instruction following the
3720 // jump can execute... !!! FIX !!!
3721 // This can probably be solved by judicious coding in the pipeline execution core...
3722 // And should be fixed now...
3723 static void DSP_jr(void)
3724 {
3725 #ifdef DSP_DIS_JR
3726 const char * condition[32] =
3727 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3728         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3729         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3730         "???", "???", "???", "F" };
3731         if (doDSPDis)
3732 //How come this is always off by 2???
3733                 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);
3734 #endif
3735         // KLUDGE: Used by BRANCH_CONDITION macro
3736         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3737
3738         if (BRANCH_CONDITION(PIMM2))
3739         {
3740 #ifdef DSP_DIS_JR
3741         if (doDSPDis)
3742                 WriteLog("Branched!\n");
3743 #endif
3744                 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1);           // Sign extend PIMM1
3745 //Account for pipeline effects...
3746                 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3747 //WriteLog("  --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3748
3749                 // Now that we've branched, we have to make sure that the following instruction
3750                 // is executed atomically with this one and then flush the pipeline before setting
3751                 // the new PC.
3752
3753                 // Step 1: Handle writebacks at stage 3 of pipeline
3754 /*              if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3755                 {
3756                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3757                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3758
3759                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3760                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3761                 }//*/
3762                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3763                 {
3764                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3765                         {
3766                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3767                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3768                                 else
3769                                 {
3770                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3771                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3772                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3773                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3774                                         else
3775                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3776                                 }
3777                         }
3778
3779 #ifndef NEW_SCOREBOARD
3780                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3781                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3782 #else
3783 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3784                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3785                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3786                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3787 #endif
3788                 }
3789
3790                 // Step 2: Push instruction through pipeline & execute following instruction
3791                 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3792                 //       we effectively handle the final push of the instruction through the
3793                 //       pipeline when the new PC takes effect (since when we return, the
3794                 //       pipeline code will be executing the writeback stage. If we reverse
3795                 //       the execution order of the pipeline stages, this will no longer be
3796                 //       the case!)...
3797                 pipeline[plPtrExec] = pipeline[plPtrRead];
3798 //This is BAD. We need to get that next opcode and execute it!
3799 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3800 //      remove this crap.
3801                 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3802                 {
3803                 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3804                 pipeline[plPtrExec].opcode = instruction >> 10;
3805                 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3806                 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3807                         pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3808                         pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3809                         pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2;   // Set it to RN
3810                 }//*/
3811         dsp_pc += 2;    // For DSP_DIS_* accuracy
3812                 DSPOpcode[pipeline[plPtrExec].opcode]();
3813                 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3814                 pipeline[plPtrWrite] = pipeline[plPtrExec];
3815
3816                 // Step 3: Flush pipeline & set new PC
3817                 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3818                 dsp_pc = newPC;
3819         }
3820         else
3821 #ifdef DSP_DIS_JR
3822         {
3823                 if (doDSPDis)
3824                         WriteLog("Branch NOT taken.\n");
3825 #endif
3826                 NO_WRITEBACK;
3827 #ifdef DSP_DIS_JR
3828         }
3829 #endif
3830 //      WriteLog("  --> DSP_PC: %08X\n", dsp_pc);
3831 }
3832
3833 static void DSP_jump(void)
3834 {
3835 #ifdef DSP_DIS_JUMP
3836 const char * condition[32] =
3837 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3838         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3839         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3840         "???", "???", "???", "F" };
3841         if (doDSPDis)
3842                 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);
3843 #endif
3844         // KLUDGE: Used by BRANCH_CONDITION macro
3845         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3846
3847         if (BRANCH_CONDITION(PIMM2))
3848         {
3849 #ifdef DSP_DIS_JUMP
3850         if (doDSPDis)
3851                 WriteLog("Branched!\n");
3852 #endif
3853                 uint32_t PCSave = PRM;
3854                 // Now that we've branched, we have to make sure that the following instruction
3855                 // is executed atomically with this one and then flush the pipeline before setting
3856                 // the new PC.
3857
3858                 // Step 1: Handle writebacks at stage 3 of pipeline
3859 /*              if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3860                 {
3861                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3862                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3863
3864                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3865                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3866                 }//*/
3867                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3868                 {
3869                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3870                         {
3871                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3872                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3873                                 else
3874                                 {
3875                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3876                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3877                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3878                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3879                                         else
3880                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3881                                 }
3882                         }
3883
3884 #ifndef NEW_SCOREBOARD
3885                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3886                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3887 #else
3888 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3889                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3890                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3891                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3892 #endif
3893                 }
3894
3895                 // Step 2: Push instruction through pipeline & execute following instruction
3896                 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3897                 //       we effectively handle the final push of the instruction through the
3898                 //       pipeline when the new PC takes effect (since when we return, the
3899                 //       pipeline code will be executing the writeback stage. If we reverse
3900                 //       the execution order of the pipeline stages, this will no longer be
3901                 //       the case!)...
3902                 pipeline[plPtrExec] = pipeline[plPtrRead];
3903 //This is BAD. We need to get that next opcode and execute it!
3904 //Also, same problem in JR!
3905 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3906 //      remove this crap.
3907                 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3908                 {
3909                 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3910                 pipeline[plPtrExec].opcode = instruction >> 10;
3911                 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3912                 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3913                         pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3914                         pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3915                         pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2;   // Set it to RN
3916                 }//*/
3917         dsp_pc += 2;    // For DSP_DIS_* accuracy
3918                 DSPOpcode[pipeline[plPtrExec].opcode]();
3919                 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3920                 pipeline[plPtrWrite] = pipeline[plPtrExec];
3921
3922                 // Step 3: Flush pipeline & set new PC
3923                 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3924                 dsp_pc = PCSave;
3925         }
3926         else
3927 #ifdef DSP_DIS_JUMP
3928         {
3929                 if (doDSPDis)
3930                         WriteLog("Branch NOT taken.\n");
3931 #endif
3932                 NO_WRITEBACK;
3933 #ifdef DSP_DIS_JUMP
3934         }
3935 #endif
3936 }
3937
3938 static void DSP_load(void)
3939 {
3940 #ifdef DSP_DIS_LOAD
3941         if (doDSPDis)
3942                 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);
3943 #endif
3944 #ifdef DSP_CORRECT_ALIGNMENT
3945         PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3946 #else
3947         PRES = DSPReadLong(PRM, DSP);
3948 #endif
3949 #ifdef DSP_DIS_LOAD
3950         if (doDSPDis)
3951                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3952 #endif
3953 }
3954
3955 static void DSP_loadb(void)
3956 {
3957 #ifdef DSP_DIS_LOADB
3958         if (doDSPDis)
3959                 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);
3960 #endif
3961         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3962                 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3963         else
3964                 PRES = JaguarReadByte(PRM, DSP);
3965 #ifdef DSP_DIS_LOADB
3966         if (doDSPDis)
3967                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3968 #endif
3969 }
3970
3971 static void DSP_loadw(void)
3972 {
3973 #ifdef DSP_DIS_LOADW
3974         if (doDSPDis)
3975                 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);
3976 #endif
3977 #ifdef DSP_CORRECT_ALIGNMENT
3978         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3979                 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
3980         else
3981                 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
3982 #else
3983         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3984                 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3985         else
3986                 PRES = JaguarReadWord(PRM, DSP);
3987 #endif
3988 #ifdef DSP_DIS_LOADW
3989         if (doDSPDis)
3990                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3991 #endif
3992 }
3993
3994 static void DSP_load_r14_i(void)
3995 {
3996 #ifdef DSP_DIS_LOAD14I
3997         if (doDSPDis)
3998                 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);
3999 #endif
4000 #ifdef DSP_CORRECT_ALIGNMENT
4001         PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4002 #else
4003         PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4004 #endif
4005 #ifdef DSP_DIS_LOAD14I
4006         if (doDSPDis)
4007                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4008 #endif
4009 }
4010
4011 static void DSP_load_r14_r(void)
4012 {
4013 #ifdef DSP_DIS_LOAD14R
4014         if (doDSPDis)
4015                 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);
4016 #endif
4017 #ifdef DSP_CORRECT_ALIGNMENT
4018         PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4019 #else
4020         PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4021 #endif
4022 #ifdef DSP_DIS_LOAD14R
4023         if (doDSPDis)
4024                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4025 #endif
4026 }
4027
4028 static void DSP_load_r15_i(void)
4029 {
4030 #ifdef DSP_DIS_LOAD15I
4031         if (doDSPDis)
4032                 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);
4033 #endif
4034 #ifdef DSP_CORRECT_ALIGNMENT
4035         PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4036 #else
4037         PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4038 #endif
4039 #ifdef DSP_DIS_LOAD15I
4040         if (doDSPDis)
4041                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4042 #endif
4043 }
4044
4045 static void DSP_load_r15_r(void)
4046 {
4047 #ifdef DSP_DIS_LOAD15R
4048         if (doDSPDis)
4049                 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);
4050 #endif
4051 #ifdef DSP_CORRECT_ALIGNMENT
4052         PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4053 #else
4054         PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4055 #endif
4056 #ifdef DSP_DIS_LOAD15R
4057         if (doDSPDis)
4058                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4059 #endif
4060 }
4061
4062 static void DSP_mirror(void)
4063 {
4064         uint32_t r1 = PRN;
4065         PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4066         SET_ZN(PRES);
4067 }
4068
4069 static void DSP_mmult(void)
4070 {
4071         int count       = dsp_matrix_control&0x0f;
4072         uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4073         int64_t accum = 0;
4074         uint32_t res;
4075
4076         if (!(dsp_matrix_control & 0x10))
4077         {
4078                 for (int i = 0; i < count; i++)
4079                 {
4080                         int16_t a;
4081                         if (i&0x01)
4082                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4083                         else
4084                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4085                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4086                         accum += a*b;
4087                         addr += 4;
4088                 }
4089         }
4090         else
4091         {
4092                 for (int i = 0; i < count; i++)
4093                 {
4094                         int16_t a;
4095                         if (i&0x01)
4096                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4097                         else
4098                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4099                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4100                         accum += a*b;
4101                         addr += 4 * count;
4102                 }
4103         }
4104
4105         PRES = res = (int32_t)accum;
4106         // carry flag to do
4107 //NOTE: The flags are set based upon the last add/multiply done...
4108         SET_ZN(PRES);
4109 }
4110
4111 static void DSP_move(void)
4112 {
4113 #ifdef DSP_DIS_MOVE
4114         if (doDSPDis)
4115                 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);
4116 #endif
4117         PRES = PRM;
4118 #ifdef DSP_DIS_MOVE
4119         if (doDSPDis)
4120                 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);
4121 #endif
4122 }
4123
4124 static void DSP_movefa(void)
4125 {
4126 #ifdef DSP_DIS_MOVEFA
4127         if (doDSPDis)
4128 //              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);
4129                 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);
4130 #endif
4131 //      PRES = ALTERNATE_RM;
4132         PRES = dsp_alternate_reg[PIMM1];
4133 #ifdef DSP_DIS_MOVEFA
4134         if (doDSPDis)
4135 //              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);
4136                 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);
4137 #endif
4138 }
4139
4140 static void DSP_movei(void)
4141 {
4142 #ifdef DSP_DIS_MOVEI
4143         if (doDSPDis)
4144                 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);
4145 #endif
4146 //      // This instruction is followed by 32-bit value in LSW / MSW format...
4147 //      PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4148 //      dsp_pc += 4;
4149 #ifdef DSP_DIS_MOVEI
4150         if (doDSPDis)
4151                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4152 #endif
4153 }
4154
4155 static void DSP_movepc(void)
4156 {
4157 #ifdef DSP_DIS_MOVEPC
4158         if (doDSPDis)
4159                 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);
4160 #endif
4161 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4162 //      PRES = dsp_pc - 2;
4163 //Account for pipeline effects...
4164         PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4165 #ifdef DSP_DIS_MOVEPC
4166         if (doDSPDis)
4167                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4168 #endif
4169 }
4170
4171 static void DSP_moveq(void)
4172 {
4173 #ifdef DSP_DIS_MOVEQ
4174         if (doDSPDis)
4175                 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);
4176 #endif
4177         PRES = PIMM1;
4178 #ifdef DSP_DIS_MOVEQ
4179         if (doDSPDis)
4180                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4181 #endif
4182 }
4183
4184 static void DSP_moveta(void)
4185 {
4186 #ifdef DSP_DIS_MOVETA
4187         if (doDSPDis)
4188 //              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);
4189                 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]);
4190 #endif
4191 //      ALTERNATE_RN = PRM;
4192         dsp_alternate_reg[PIMM2] = PRM;
4193         NO_WRITEBACK;
4194 #ifdef DSP_DIS_MOVETA
4195         if (doDSPDis)
4196 //              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);
4197                 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]);
4198 #endif
4199 }
4200
4201 static void DSP_mtoi(void)
4202 {
4203         PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4204         SET_ZN(PRES);
4205 }
4206
4207 static void DSP_mult(void)
4208 {
4209 #ifdef DSP_DIS_MULT
4210         if (doDSPDis)
4211                 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);
4212 #endif
4213         PRES = (uint16_t)PRM * (uint16_t)PRN;
4214         SET_ZN(PRES);
4215 #ifdef DSP_DIS_MULT
4216         if (doDSPDis)
4217                 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);
4218 #endif
4219 }
4220
4221 static void DSP_neg(void)
4222 {
4223 #ifdef DSP_DIS_NEG
4224         if (doDSPDis)
4225                 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);
4226 #endif
4227         uint32_t res = -PRN;
4228         SET_ZNC_SUB(0, PRN, res);
4229         PRES = res;
4230 #ifdef DSP_DIS_NEG
4231         if (doDSPDis)
4232                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4233 #endif
4234 }
4235
4236 static void DSP_nop(void)
4237 {
4238 #ifdef DSP_DIS_NOP
4239         if (doDSPDis)
4240                 WriteLog("%06X: NOP    [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4241 #endif
4242         NO_WRITEBACK;
4243 }
4244
4245 static void DSP_normi(void)
4246 {
4247         uint32_t _Rm = PRM;
4248         uint32_t res = 0;
4249
4250         if (_Rm)
4251         {
4252                 while ((_Rm & 0xffc00000) == 0)
4253                 {
4254                         _Rm <<= 1;
4255                         res--;
4256                 }
4257                 while ((_Rm & 0xff800000) != 0)
4258                 {
4259                         _Rm >>= 1;
4260                         res++;
4261                 }
4262         }
4263         PRES = res;
4264         SET_ZN(PRES);
4265 }
4266
4267 static void DSP_not(void)
4268 {
4269 #ifdef DSP_DIS_NOT
4270         if (doDSPDis)
4271                 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);
4272 #endif
4273         PRES = ~PRN;
4274         SET_ZN(PRES);
4275 #ifdef DSP_DIS_NOT
4276         if (doDSPDis)
4277                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4278 #endif
4279 }
4280
4281 static void DSP_or(void)
4282 {
4283 #ifdef DSP_DIS_OR
4284         if (doDSPDis)
4285                 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);
4286 #endif
4287         PRES = PRN | PRM;
4288         SET_ZN(PRES);
4289 #ifdef DSP_DIS_OR
4290         if (doDSPDis)
4291                 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);
4292 #endif
4293 }
4294
4295 static void DSP_resmac(void)
4296 {
4297 #ifdef DSP_DIS_RESMAC
4298         if (doDSPDis)
4299                 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));
4300 #endif
4301         PRES = (uint32_t)dsp_acc;
4302 #ifdef DSP_DIS_RESMAC
4303         if (doDSPDis)
4304                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4305 #endif
4306 }
4307
4308 static void DSP_ror(void)
4309 {
4310 #ifdef DSP_DIS_ROR
4311         if (doDSPDis)
4312                 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);
4313 #endif
4314         uint32_t r1 = PRM & 0x1F;
4315         uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4316         SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4317         PRES = res;
4318 #ifdef DSP_DIS_ROR
4319         if (doDSPDis)
4320                 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);
4321 #endif
4322 }
4323
4324 static void DSP_rorq(void)
4325 {
4326 #ifdef DSP_DIS_RORQ
4327         if (doDSPDis)
4328                 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);
4329 #endif
4330         uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4331         uint32_t r2 = PRN;
4332         uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4333         PRES = res;
4334         SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4335 #ifdef DSP_DIS_RORQ
4336         if (doDSPDis)
4337                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4338 #endif
4339 }
4340
4341 static void DSP_sat16s(void)
4342 {
4343         int32_t r2 = PRN;
4344         uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4345         PRES = res;
4346         SET_ZN(res);
4347 }
4348
4349 static void DSP_sat32s(void)
4350 {
4351         int32_t r2 = (uint32_t)PRN;
4352         int32_t temp = dsp_acc >> 32;
4353         uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4354         PRES = res;
4355         SET_ZN(res);
4356 }
4357
4358 static void DSP_sh(void)
4359 {
4360         int32_t sRm = (int32_t)PRM;
4361         uint32_t _Rn = PRN;
4362
4363         if (sRm < 0)
4364         {
4365                 uint32_t shift = -sRm;
4366
4367                 if (shift >= 32)
4368                         shift = 32;
4369
4370                 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4371
4372                 while (shift)
4373                 {
4374                         _Rn <<= 1;
4375                         shift--;
4376                 }
4377         }
4378         else
4379         {
4380                 uint32_t shift = sRm;
4381
4382                 if (shift >= 32)
4383                         shift = 32;
4384
4385                 dsp_flag_c = _Rn & 0x1;
4386
4387                 while (shift)
4388                 {
4389                         _Rn >>= 1;
4390                         shift--;
4391                 }
4392         }
4393
4394         PRES = _Rn;
4395         SET_ZN(PRES);
4396 }
4397
4398 static void DSP_sha(void)
4399 {
4400         int32_t sRm = (int32_t)PRM;
4401         uint32_t _Rn = PRN;
4402
4403         if (sRm < 0)
4404         {
4405                 uint32_t shift = -sRm;
4406
4407                 if (shift >= 32)
4408                         shift = 32;
4409
4410                 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4411
4412                 while (shift)
4413                 {
4414                         _Rn <<= 1;
4415                         shift--;
4416                 }
4417         }
4418         else
4419         {
4420                 uint32_t shift = sRm;
4421
4422                 if (shift >= 32)
4423                         shift = 32;
4424
4425                 dsp_flag_c = _Rn & 0x1;
4426
4427                 while (shift)
4428                 {
4429                         _Rn = ((int32_t)_Rn) >> 1;
4430                         shift--;
4431                 }
4432         }
4433
4434         PRES = _Rn;
4435         SET_ZN(PRES);
4436 }
4437
4438 static void DSP_sharq(void)
4439 {
4440 #ifdef DSP_DIS_SHARQ
4441         if (doDSPDis)
4442                 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);
4443 #endif
4444         uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4445         SET_ZN(res); dsp_flag_c = PRN & 0x01;
4446         PRES = res;
4447 #ifdef DSP_DIS_SHARQ
4448         if (doDSPDis)
4449                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4450 #endif
4451 }
4452
4453 static void DSP_shlq(void)
4454 {
4455 #ifdef DSP_DIS_SHLQ
4456         if (doDSPDis)
4457                 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);
4458 #endif
4459         int32_t r1 = 32 - PIMM1;
4460         uint32_t res = PRN << r1;
4461         SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4462         PRES = res;
4463 #ifdef DSP_DIS_SHLQ
4464         if (doDSPDis)
4465                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4466 #endif
4467 }
4468
4469 static void DSP_shrq(void)
4470 {
4471 #ifdef DSP_DIS_SHRQ
4472         if (doDSPDis)
4473                 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);
4474 #endif
4475         int32_t r1 = dsp_convert_zero[PIMM1];
4476         uint32_t res = PRN >> r1;
4477         SET_ZN(res); dsp_flag_c = PRN & 1;
4478         PRES = res;
4479 #ifdef DSP_DIS_SHRQ
4480         if (doDSPDis)
4481                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4482 #endif
4483 }
4484
4485 static void DSP_store(void)
4486 {
4487 #ifdef DSP_DIS_STORE
4488         if (doDSPDis)
4489                 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);
4490 #endif
4491 //      DSPWriteLong(PRM, PRN, DSP);
4492 //      NO_WRITEBACK;
4493 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4494         pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4495 #else
4496         pipeline[plPtrExec].address = PRM;
4497 #endif
4498         pipeline[plPtrExec].value = PRN;
4499         pipeline[plPtrExec].type = TYPE_DWORD;
4500         WRITEBACK_ADDR;
4501 }
4502
4503 static void DSP_storeb(void)
4504 {
4505 #ifdef DSP_DIS_STOREB
4506         if (doDSPDis)
4507                 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);
4508 #endif
4509 //      if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4510 //              DSPWriteLong(PRM, PRN & 0xFF, DSP);
4511 //      else
4512 //              JaguarWriteByte(PRM, PRN, DSP);
4513 //
4514 //      NO_WRITEBACK;
4515         pipeline[plPtrExec].address = PRM;
4516
4517         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4518         {
4519                 pipeline[plPtrExec].value = PRN & 0xFF;
4520                 pipeline[plPtrExec].type = TYPE_DWORD;
4521         }
4522         else
4523         {
4524                 pipeline[plPtrExec].value = PRN;
4525                 pipeline[plPtrExec].type = TYPE_BYTE;
4526         }
4527
4528         WRITEBACK_ADDR;
4529 }
4530
4531 static void DSP_storew(void)
4532 {
4533 #ifdef DSP_DIS_STOREW
4534         if (doDSPDis)
4535                 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);
4536 #endif
4537 //      if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4538 //              DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4539 //      else
4540 //              JaguarWriteWord(PRM, PRN, DSP);
4541 //
4542 //      NO_WRITEBACK;
4543 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4544         pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4545 #else
4546         pipeline[plPtrExec].address = PRM;
4547 #endif
4548
4549         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4550         {
4551                 pipeline[plPtrExec].value = PRN & 0xFFFF;
4552                 pipeline[plPtrExec].type = TYPE_DWORD;
4553         }
4554         else
4555         {
4556                 pipeline[plPtrExec].value = PRN;
4557                 pipeline[plPtrExec].type = TYPE_WORD;
4558         }
4559         WRITEBACK_ADDR;
4560 }
4561
4562 static void DSP_store_r14_i(void)
4563 {
4564 #ifdef DSP_DIS_STORE14I
4565         if (doDSPDis)
4566                 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));
4567 #endif
4568 //      DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4569 //      NO_WRITEBACK;
4570 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4571         pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4572 #else
4573         pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4574 #endif
4575         pipeline[plPtrExec].value = PRN;
4576         pipeline[plPtrExec].type = TYPE_DWORD;
4577         WRITEBACK_ADDR;
4578 }
4579
4580 static void DSP_store_r14_r(void)
4581 {
4582 //      DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4583 //      NO_WRITEBACK;
4584 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4585         pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4586 #else
4587         pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4588 #endif
4589         pipeline[plPtrExec].value = PRN;
4590         pipeline[plPtrExec].type = TYPE_DWORD;
4591         WRITEBACK_ADDR;
4592 }
4593
4594 static void DSP_store_r15_i(void)
4595 {
4596 #ifdef DSP_DIS_STORE15I
4597         if (doDSPDis)
4598                 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));
4599 #endif
4600 //      DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4601 //      NO_WRITEBACK;
4602 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4603         pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4604 #else
4605         pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4606 #endif
4607         pipeline[plPtrExec].value = PRN;
4608         pipeline[plPtrExec].type = TYPE_DWORD;
4609         WRITEBACK_ADDR;
4610 }
4611
4612 static void DSP_store_r15_r(void)
4613 {
4614 //      DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4615 //      NO_WRITEBACK;
4616 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4617         pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4618 #else
4619         pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4620 #endif
4621         pipeline[plPtrExec].value = PRN;
4622         pipeline[plPtrExec].type = TYPE_DWORD;
4623         WRITEBACK_ADDR;
4624 }
4625
4626 static void DSP_sub(void)
4627 {
4628 #ifdef DSP_DIS_SUB
4629         if (doDSPDis)
4630                 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);
4631 #endif
4632         uint32_t res = PRN - PRM;
4633         SET_ZNC_SUB(PRN, PRM, res);
4634         PRES = res;
4635 #ifdef DSP_DIS_SUB
4636         if (doDSPDis)
4637                 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);
4638 #endif
4639 }
4640
4641 static void DSP_subc(void)
4642 {
4643 #ifdef DSP_DIS_SUBC
4644         if (doDSPDis)
4645                 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);
4646 #endif
4647         uint32_t res = PRN - PRM - dsp_flag_c;
4648         uint32_t borrow = dsp_flag_c;
4649         SET_ZNC_SUB(PRN - borrow, PRM, res);
4650         PRES = res;
4651 #ifdef DSP_DIS_SUBC
4652         if (doDSPDis)
4653                 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);
4654 #endif
4655 }
4656
4657 static void DSP_subq(void)
4658 {
4659 #ifdef DSP_DIS_SUBQ
4660         if (doDSPDis)
4661                 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);
4662 #endif
4663         uint32_t r1 = dsp_convert_zero[PIMM1];
4664         uint32_t res = PRN - r1;
4665         SET_ZNC_SUB(PRN, r1, res);
4666         PRES = res;
4667 #ifdef DSP_DIS_SUBQ
4668         if (doDSPDis)
4669                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4670 #endif
4671 }
4672
4673 static void DSP_subqmod(void)
4674 {
4675         uint32_t r1 = dsp_convert_zero[PIMM1];
4676         uint32_t r2 = PRN;
4677         uint32_t res = r2 - r1;
4678         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4679         PRES = res;
4680         SET_ZNC_SUB(r2, r1, res);
4681 }
4682
4683 static void DSP_subqt(void)
4684 {
4685 #ifdef DSP_DIS_SUBQT
4686         if (doDSPDis)
4687                 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);
4688 #endif
4689         PRES = PRN - dsp_convert_zero[PIMM1];
4690 #ifdef DSP_DIS_SUBQT
4691         if (doDSPDis)
4692                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4693 #endif
4694 }
4695
4696 static void DSP_xor(void)
4697 {
4698 #ifdef DSP_DIS_XOR
4699         if (doDSPDis)
4700                 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);
4701 #endif
4702         PRES = PRN ^ PRM;
4703         SET_ZN(PRES);
4704 #ifdef DSP_DIS_XOR
4705         if (doDSPDis)
4706                 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);
4707 #endif
4708 }