]> Shamusworld >> Repos - virtualjaguar/blob - src/dsp.cpp
Various fixes for GPU/DSP DIV instruction, fixes for joypad handling.
[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 #if 0
2407         uint32_t _Rm=RM;
2408         uint32_t _Rn=RN;
2409
2410         if (_Rm)
2411         {
2412                 if (dsp_div_control & 1)
2413                 {
2414                         dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2415                         if (dsp_remain&0x80000000)
2416                                 dsp_remain-=_Rm;
2417                         RN = (((uint64_t)_Rn) << 16) / _Rm;
2418                 }
2419                 else
2420                 {
2421                         dsp_remain = _Rn % _Rm;
2422                         if (dsp_remain&0x80000000)
2423                                 dsp_remain-=_Rm;
2424                         RN/=_Rm;
2425                 }
2426         }
2427         else
2428                 RN=0xffffffff;
2429 #else
2430         if (RM)
2431         {
2432                 if (dsp_div_control & 0x01)             // 16.16 division
2433                 {
2434                         dsp_remain = ((uint64_t)RN << 16) % RM;
2435                         RN = ((uint64_t)RN << 16) / RM;
2436                 }
2437                 else
2438                 {
2439                         // We calculate the remainder first because we destroy RN after
2440                         // this by assigning it to itself.
2441                         dsp_remain = RN % RM;
2442                         RN = RN / RM;
2443                 }
2444
2445 // What we really should do here is figure out why this condition
2446 // happens in the real divide unit and emulate *that* behavior.
2447 #if 0
2448                 if ((gpu_remain - RM) & 0x80000000)     // If the result would have been negative...
2449                         gpu_remain -= RM;                       // Then make it negative!
2450 #endif
2451         }
2452         else
2453                 RN = 0xFFFFFFFF;
2454 #endif
2455 }
2456
2457 static void dsp_opcode_imultn(void)
2458 {
2459 #ifdef DSP_DIS_IMULTN
2460         if (doDSPDis)
2461                 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);
2462 #endif
2463         // This is OK, since this multiply won't overflow 32 bits...
2464         int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2465         dsp_acc = (int64_t)res;
2466         SET_ZN(res);
2467 #ifdef DSP_DIS_IMULTN
2468         if (doDSPDis)
2469                 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));
2470 #endif
2471 }
2472
2473 static void dsp_opcode_neg(void)
2474 {
2475 #ifdef DSP_DIS_NEG
2476         if (doDSPDis)
2477                 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);
2478 #endif
2479         uint32_t res = -RN;
2480         SET_ZNC_SUB(0, RN, res);
2481         RN = res;
2482 #ifdef DSP_DIS_NEG
2483         if (doDSPDis)
2484                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2485 #endif
2486 }
2487
2488 static void dsp_opcode_shlq(void)
2489 {
2490 #ifdef DSP_DIS_SHLQ
2491         if (doDSPDis)
2492                 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);
2493 #endif
2494         // NB: This instruction is the *only* one that does (32 - immediate data).
2495         int32_t r1 = 32 - IMM_1;
2496         uint32_t res = RN << r1;
2497         SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2498         RN = res;
2499 #ifdef DSP_DIS_SHLQ
2500         if (doDSPDis)
2501                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2502 #endif
2503 }
2504
2505 static void dsp_opcode_shrq(void)
2506 {
2507 #ifdef DSP_DIS_SHRQ
2508         if (doDSPDis)
2509                 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);
2510 #endif
2511         int32_t r1 = dsp_convert_zero[IMM_1];
2512         uint32_t res = RN >> r1;
2513         SET_ZN(res); dsp_flag_c = RN & 1;
2514         RN = res;
2515 #ifdef DSP_DIS_SHRQ
2516         if (doDSPDis)
2517                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2518 #endif
2519 }
2520
2521 static void dsp_opcode_ror(void)
2522 {
2523 #ifdef DSP_DIS_ROR
2524         if (doDSPDis)
2525                 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);
2526 #endif
2527         uint32_t r1 = RM & 0x1F;
2528         uint32_t res = (RN >> r1) | (RN << (32 - r1));
2529         SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2530         RN = res;
2531 #ifdef DSP_DIS_ROR
2532         if (doDSPDis)
2533                 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);
2534 #endif
2535 }
2536
2537 static void dsp_opcode_rorq(void)
2538 {
2539 #ifdef DSP_DIS_RORQ
2540         if (doDSPDis)
2541                 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);
2542 #endif
2543         uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2544         uint32_t r2 = RN;
2545         uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2546         RN = res;
2547         SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2548 #ifdef DSP_DIS_RORQ
2549         if (doDSPDis)
2550                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2551 #endif
2552 }
2553
2554 static void dsp_opcode_sha(void)
2555 {
2556         int32_t sRm=(int32_t)RM;
2557         uint32_t _Rn=RN;
2558
2559         if (sRm<0)
2560         {
2561                 uint32_t shift=-sRm;
2562                 if (shift>=32) shift=32;
2563                 dsp_flag_c=(_Rn&0x80000000)>>31;
2564                 while (shift)
2565                 {
2566                         _Rn<<=1;
2567                         shift--;
2568                 }
2569         }
2570         else
2571         {
2572                 uint32_t shift=sRm;
2573                 if (shift>=32) shift=32;
2574                 dsp_flag_c=_Rn&0x1;
2575                 while (shift)
2576                 {
2577                         _Rn=((int32_t)_Rn)>>1;
2578                         shift--;
2579                 }
2580         }
2581         RN = _Rn;
2582         SET_ZN(RN);
2583 }
2584
2585 static void dsp_opcode_sharq(void)
2586 {
2587 #ifdef DSP_DIS_SHARQ
2588         if (doDSPDis)
2589                 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);
2590 #endif
2591         uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2592         SET_ZN(res); dsp_flag_c = RN & 0x01;
2593         RN = res;
2594 #ifdef DSP_DIS_SHARQ
2595         if (doDSPDis)
2596                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2597 #endif
2598 }
2599
2600 static void dsp_opcode_sh(void)
2601 {
2602         int32_t sRm=(int32_t)RM;
2603         uint32_t _Rn=RN;
2604
2605         if (sRm<0)
2606         {
2607                 uint32_t shift=(-sRm);
2608                 if (shift>=32) shift=32;
2609                 dsp_flag_c=(_Rn&0x80000000)>>31;
2610                 while (shift)
2611                 {
2612                         _Rn<<=1;
2613                         shift--;
2614                 }
2615         }
2616         else
2617         {
2618                 uint32_t shift=sRm;
2619                 if (shift>=32) shift=32;
2620                 dsp_flag_c=_Rn&0x1;
2621                 while (shift)
2622                 {
2623                         _Rn>>=1;
2624                         shift--;
2625                 }
2626         }
2627         RN = _Rn;
2628         SET_ZN(RN);
2629 }
2630
2631 void dsp_opcode_addqmod(void)
2632 {
2633 #ifdef DSP_DIS_ADDQMOD
2634         if (doDSPDis)
2635                 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);
2636 #endif
2637         uint32_t r1 = dsp_convert_zero[IMM_1];
2638         uint32_t r2 = RN;
2639         uint32_t res = r2 + r1;
2640         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2641         RN = res;
2642         SET_ZNC_ADD(r2, r1, res);
2643 #ifdef DSP_DIS_ADDQMOD
2644         if (doDSPDis)
2645                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2646 #endif
2647 }
2648
2649 void dsp_opcode_subqmod(void)
2650 {
2651         uint32_t r1 = dsp_convert_zero[IMM_1];
2652         uint32_t r2 = RN;
2653         uint32_t res = r2 - r1;
2654         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2655         RN = res;
2656
2657         SET_ZNC_SUB(r2, r1, res);
2658 }
2659
2660 void dsp_opcode_mirror(void)
2661 {
2662         uint32_t r1 = RN;
2663         RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2664         SET_ZN(RN);
2665 }
2666
2667 void dsp_opcode_sat32s(void)
2668 {
2669         int32_t r2 = (uint32_t)RN;
2670         int32_t temp = dsp_acc >> 32;
2671         uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2672         RN = res;
2673         SET_ZN(res);
2674 }
2675
2676 void dsp_opcode_sat16s(void)
2677 {
2678         int32_t r2 = RN;
2679         uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2680         RN = res;
2681         SET_ZN(res);
2682 }
2683
2684 void dsp_opcode_illegal(void)
2685 {
2686         // Don't know what it does, but it does *something*...
2687         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);
2688 }
2689
2690 //
2691 // New pipelined DSP core
2692 //
2693
2694 static void DSP_abs(void);
2695 static void DSP_add(void);
2696 static void DSP_addc(void);
2697 static void DSP_addq(void);
2698 static void DSP_addqmod(void);
2699 static void DSP_addqt(void);
2700 static void DSP_and(void);
2701 static void DSP_bclr(void);
2702 static void DSP_bset(void);
2703 static void DSP_btst(void);
2704 static void DSP_cmp(void);
2705 static void DSP_cmpq(void);
2706 static void DSP_div(void);
2707 static void DSP_imacn(void);
2708 static void DSP_imult(void);
2709 static void DSP_imultn(void);
2710 static void DSP_illegal(void);
2711 static void DSP_jr(void);
2712 static void DSP_jump(void);
2713 static void DSP_load(void);
2714 static void DSP_loadb(void);
2715 static void DSP_loadw(void);
2716 static void DSP_load_r14_i(void);
2717 static void DSP_load_r14_r(void);
2718 static void DSP_load_r15_i(void);
2719 static void DSP_load_r15_r(void);
2720 static void DSP_mirror(void);
2721 static void DSP_mmult(void);
2722 static void DSP_move(void);
2723 static void DSP_movefa(void);
2724 static void DSP_movei(void);
2725 static void DSP_movepc(void);
2726 static void DSP_moveq(void);
2727 static void DSP_moveta(void);
2728 static void DSP_mtoi(void);
2729 static void DSP_mult(void);
2730 static void DSP_neg(void);
2731 static void DSP_nop(void);
2732 static void DSP_normi(void);
2733 static void DSP_not(void);
2734 static void DSP_or(void);
2735 static void DSP_resmac(void);
2736 static void DSP_ror(void);
2737 static void DSP_rorq(void);
2738 static void DSP_sat16s(void);
2739 static void DSP_sat32s(void);
2740 static void DSP_sh(void);
2741 static void DSP_sha(void);
2742 static void DSP_sharq(void);
2743 static void DSP_shlq(void);
2744 static void DSP_shrq(void);
2745 static void DSP_store(void);
2746 static void DSP_storeb(void);
2747 static void DSP_storew(void);
2748 static void DSP_store_r14_i(void);
2749 static void DSP_store_r14_r(void);
2750 static void DSP_store_r15_i(void);
2751 static void DSP_store_r15_r(void);
2752 static void DSP_sub(void);
2753 static void DSP_subc(void);
2754 static void DSP_subq(void);
2755 static void DSP_subqmod(void);
2756 static void DSP_subqt(void);
2757 static void DSP_xor(void);
2758
2759 void (* DSPOpcode[64])() =
2760 {
2761         DSP_add,                        DSP_addc,                       DSP_addq,                       DSP_addqt,
2762         DSP_sub,                        DSP_subc,                       DSP_subq,                       DSP_subqt,
2763         DSP_neg,                        DSP_and,                        DSP_or,                         DSP_xor,
2764         DSP_not,                        DSP_btst,                       DSP_bset,                       DSP_bclr,
2765
2766         DSP_mult,                       DSP_imult,                      DSP_imultn,                     DSP_resmac,
2767         DSP_imacn,                      DSP_div,                        DSP_abs,                        DSP_sh,
2768         DSP_shlq,                       DSP_shrq,                       DSP_sha,                        DSP_sharq,
2769         DSP_ror,                        DSP_rorq,                       DSP_cmp,                        DSP_cmpq,
2770
2771         DSP_subqmod,            DSP_sat16s,                     DSP_move,                       DSP_moveq,
2772         DSP_moveta,                     DSP_movefa,                     DSP_movei,                      DSP_loadb,
2773         DSP_loadw,                      DSP_load,                       DSP_sat32s,                     DSP_load_r14_i,
2774         DSP_load_r15_i,         DSP_storeb,                     DSP_storew,                     DSP_store,
2775
2776         DSP_mirror,                     DSP_store_r14_i,        DSP_store_r15_i,        DSP_movepc,
2777         DSP_jump,                       DSP_jr,                         DSP_mmult,                      DSP_mtoi,
2778         DSP_normi,                      DSP_nop,                        DSP_load_r14_r,         DSP_load_r15_r,
2779         DSP_store_r14_r,        DSP_store_r15_r,        DSP_illegal,            DSP_addqmod
2780 };
2781
2782 bool readAffected[64][2] =
2783 {
2784         { true,  true}, { true,  true}, {false,  true}, {false,  true},
2785         { true,  true}, { true,  true}, {false,  true}, {false,  true},
2786         {false,  true}, { true,  true}, { true,  true}, { true,  true},
2787         {false,  true}, {false,  true}, {false,  true}, {false,  true},
2788
2789         { true,  true}, { true,  true}, { true,  true}, {false,  true},
2790         { true,  true}, { true,  true}, {false,  true}, { true,  true},
2791         {false,  true}, {false,  true}, { true,  true}, {false,  true},
2792         { true,  true}, {false,  true}, { true,  true}, {false,  true},
2793
2794         {false,  true}, {false,  true}, { true, false}, {false, false},
2795         { true, false}, {false, false}, {false, false}, { true, false},
2796         { true, false}, { true, false}, {false,  true}, { true, false},
2797         { true, false}, { true,  true}, { true,  true}, { true,  true},
2798
2799         {false,  true}, { true,  true}, { true,  true}, {false,  true},
2800         { true, false}, { true, false}, { true,  true}, { true, false},
2801         { true, false}, {false, false}, { true, false}, { true, false},
2802         { true,  true}, { true,  true}, {false, false}, {false,  true}
2803 };
2804
2805 bool isLoadStore[65] =
2806 {
2807         false, false, false, false, false, false, false, false,
2808         false, false, false, false, false, false, false, false,
2809
2810         false, false, false, false, false, false, false, false,
2811         false, false, false, false, false, false, false, false,
2812
2813         false, false, false, false, false, false, false,  true,
2814          true,  true, false,  true,  true,  true,  true,  true,
2815
2816         false,  true,  true, false, false, false, false, false,
2817         false, false,  true,  true,  true,  true, false, false, false
2818 };
2819
2820 void FlushDSPPipeline(void)
2821 {
2822         plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2823
2824         for(int i=0; i<4; i++)
2825                 pipeline[i].opcode = PIPELINE_STALL;
2826
2827         for(int i=0; i<32; i++)
2828                 scoreboard[i] = 0;
2829 }
2830
2831 //
2832 // New pipelined DSP execution core
2833 //
2834 /*void DSPExecP(int32_t cycles)
2835 {
2836 //      bool inhibitFetch = false;
2837
2838         dsp_releaseTimeSlice_flag = 0;
2839         dsp_in_exec++;
2840
2841         while (cycles > 0 && DSP_RUNNING)
2842         {
2843 WriteLog("DSPExecP: Pipeline status...\n");
2844 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);
2845 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);
2846 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);
2847 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);
2848 WriteLog("  --> Scoreboard: ");
2849 for(int i=0; i<32; i++)
2850         WriteLog("%s ", scoreboard[i] ? "T" : "F");
2851 WriteLog("\n");
2852                 // Stage 1: Instruction fetch
2853 //              if (!inhibitFetch)
2854 //              {
2855                 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2856                 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2857                 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2858                 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2859                 if (pipeline[plPtrFetch].opcode == 38)
2860                         pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2861                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2862 //              }
2863 //              else
2864 //                      inhibitFetch = false;
2865 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2866
2867 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2868 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);
2869 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);
2870 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);
2871 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);
2872                 // Stage 2: Read registers
2873 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2874 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2875                 if (scoreboard[pipeline[plPtrRead].operand2])
2876                         && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2877                         // We have a hit in the scoreboard, so we have to stall the pipeline...
2878 {
2879 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2880 //                      dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2881 WriteLog("  --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2882                         pipeline[plPtrFetch] = pipeline[plPtrRead];
2883                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
2884 }
2885                 else
2886                 {
2887                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2888                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2889                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
2890
2891                         if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2892                         // Shouldn't we be more selective with the register scoreboarding?
2893                         // Yes, we should. !!! FIX !!!
2894                         scoreboard[pipeline[plPtrRead].operand2] = true;
2895 //Advance PC here??? Yes.
2896 //                      dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2897 //This is a mangling of the pipeline stages, but what else to do???
2898                         dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2899                 }
2900
2901 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2902 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);
2903 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);
2904 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);
2905 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);
2906                 // Stage 3: Execute
2907                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2908                 {
2909 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2910                         DSPOpcode[pipeline[plPtrExec].opcode]();
2911                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2912                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2913                 }
2914                 else
2915                         cycles--;
2916
2917 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2918 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);
2919 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);
2920 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);
2921 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);
2922                 // Stage 4: Write back register
2923                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2924                 {
2925                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2926                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2927
2928                         scoreboard[pipeline[plPtrWrite].operand1]
2929                                 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2930                 }
2931
2932                 // Push instructions through the pipeline...
2933                 plPtrFetch = (++plPtrFetch) & 0x03;
2934                 plPtrRead = (++plPtrRead) & 0x03;
2935                 plPtrExec = (++plPtrExec) & 0x03;
2936                 plPtrWrite = (++plPtrWrite) & 0x03;
2937         }
2938
2939         dsp_in_exec--;
2940 }*/
2941
2942
2943 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2944 //!!! FIX !!!
2945 // Should be fixed now. Another problem is figuring how to do the sequence following
2946 // a branch followed with the JR & JUMP instructions...
2947 //
2948 // There are two conflicting problems:
2949
2950 /*
2951 F1B236: LOAD   (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2952 F1B238: BCLR   #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2953 F1B23A: ADDQ   #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2954 F1B23C: SUBQ   #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2955 F1B23E: MOVEI  #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2956 F1B244: JR     z, F1B254 [NCZ:000] Branch NOT taken.
2957 F1B246: BSET   #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2958 F1B248: MOVEI  #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2959 F1B24E: STORE  R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2960 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2961 DSP: Finished interrupt.
2962 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2963 ; bank 0 (where is was prepared)!
2964 F1B250: JUMP   T, (R03) [NCZ:001, R03=00000000] Branched!
2965 F1B252: NOP    [NCZ:001]
2966 */
2967
2968 // The other is when you see this at the end of an IRQ:
2969
2970 /*
2971 JUMP   T, (R29)         ; R29 = Previous stack + 2
2972 STORE  R28, (R30)       ; R28 = Modified flags register, R30 = $F1A100
2973
2974 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2975 ; 1) The STORE goes through the pipeline and is executed/written back
2976 ; 2) The pipeline is flushed
2977 ; 3) The DSP_PC is set to the new address
2978 ; 4) Execution resumes
2979
2980 JUMP   T, (R25)         ; Oops! Because of pipeline effects R25 has the value from
2981                                         ; bank 0 instead of the current bank 1 and so goes astray!
2982 */
2983
2984 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2985 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2986
2987
2988 /*
2989 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2990 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2991 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2992 If it were done properly, the STORE write back would occur *after* (well, technically,
2993 during) the execution of the the JUMP that follows it.
2994
2995 !!! FIX !!! [DONE]
2996
2997 F1B08A: JR     z, F1B082 [NCZ:001] Branched!
2998 F1B08A: NOP    [NCZ:001]
2999 [STALL...]
3000 F1B080: MOVEI  #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3001 [STALL...]
3002 [STALL...]
3003 F1B086: LOAD   (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3004 [STALL...]
3005 [STALL...]
3006 F1B088: OR     R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3007 F1B08A: JR     z, F1B082 [NCZ:001] Branched!
3008 F1B08A: NOP    [NCZ:001]
3009 [STALL...]
3010 F1B080: MOVEI  #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3011 [STALL...]
3012 [STALL...]
3013 Write to DSP CTRL: 00002301  --> Starting to run at 00F1B088 by M68K...
3014 DSP: CPU -> DSP interrupt
3015 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3016 Write to DSP CTRL: 00000001  --> Starting to run at 00F1B000 by M68K...
3017 [STALL...]
3018 F1B000: MOVEI  #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3019 [STALL...]
3020 [STALL...]
3021 F1B006: JUMP   T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3022 F1B006: NOP    [NCZ:001]
3023 [STALL...]
3024 F1B0D4: MOVEI  #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3025 [STALL...]
3026 [STALL...]
3027 F1B0DA: LOAD   (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3028 F1B0DC: MOVEI  #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3029 [STALL...]
3030 [STALL...]
3031 F1B0E2: LOAD   (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3032 F1B0E4: MOVEI  #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3033 [STALL...]
3034 [STALL...]
3035 F1B0EA: LOAD   (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3036 F1B0EC: MOVEI  #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3037 [STALL...]
3038 [STALL...]
3039 F1B0F2: LOAD   (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3040 F1B0F4: MOVEI  #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3041 [STALL...]
3042 [STALL...]
3043 F1B0FA: ADD    R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3044 [STALL...]
3045 [STALL...]
3046 F1B0FC: LOAD   (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3047 [STALL...]
3048 [STALL...]
3049 F1B0FE: JUMP   T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3050 F1B0FE: NOP    [NCZ:000]
3051 [STALL...]
3052 F1B12E: MOVE   R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3053 [STALL...]
3054 [STALL...]
3055 F1B132: MOVEI  #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3056 [STALL...]
3057 [STALL...]
3058 F1B138: JUMP   T, (R01) [NCZ:000, R01=00F1B102] Branched!
3059 F1B138: NOP    [NCZ:000]
3060 [STALL...]
3061 F1B102: MOVEI  #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3062 [STALL...]
3063 [STALL...]
3064 F1B108: STORE  R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3065 F1B10A: MOVEI  #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3066 F1B110: MOVEQ  #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3067 [STALL...]
3068 [STALL...]
3069 F1B112: STORE  R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3070 F1B114: BCLR   #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3071 [STALL...]
3072 [STALL...]
3073 F1B116: BSET   #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3074 F1B118: LOAD   (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3075 F1B11A: MOVEI  #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3076 [STALL...]
3077 F1B120: ADDQ   #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3078 F1B122: MOVEI  #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3079 [STALL...]
3080 [STALL...]
3081 F1B128: STORE  R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3082 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3083 DSP: Finished interrupt.
3084 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3085 [STALL...]
3086 F1B010: MOVEI  #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3087 [STALL...]
3088 [STALL...]
3089 F1B016: JUMP   T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3090 F1B016: NOP    [NCZ:001]
3091 [STALL...]
3092 F1B1FC: MOVEI  #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3093 */
3094
3095 uint32_t pcQueue1[0x400];
3096 uint32_t pcQPtr1 = 0;
3097 static uint32_t prevR1;
3098 //Let's try a 3 stage pipeline....
3099 //Looks like 3 stage is correct, otherwise bad things happen...
3100 void DSPExecP2(int32_t cycles)
3101 {
3102         dsp_releaseTimeSlice_flag = 0;
3103         dsp_in_exec++;
3104
3105         while (cycles > 0 && DSP_RUNNING)
3106         {
3107 /*extern uint32_t totalFrames;
3108 //F1B2F6: LOAD   (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3109 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3110 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3111 //F1B140:
3112 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3113 {
3114         doDSPDis = true;
3115         WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3116 }
3117 if (dsp_pc == 0xF1B092)
3118         doDSPDis = false;//*/
3119 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3120         doDSPDis = true;//*/
3121 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3122         doDSPDis = true;//*/
3123 /*if (dsp_pc == 0xF1B0A0)
3124         doDSPDis = true;//*/
3125 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3126         doDSPDis = true;//*/
3127 //Two parter... (not sure how to write this)
3128 //if (dsp_pc == 0xF1B0D2)
3129 //      prevR1 = dsp_reg[1];
3130
3131 //F1B0D2: ADDQT  #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3132 //F1B0D2: ADDQT  #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3133
3134
3135 pcQueue1[pcQPtr1++] = dsp_pc;
3136 pcQPtr1 &= 0x3FF;
3137
3138 #ifdef DSP_DEBUG_PL2
3139 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3140 {
3141         WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3142         doDSPDis = true;
3143
3144         char buffer[512];
3145
3146         for(int i=0; i<0x400; i++)
3147         {
3148                 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3149                 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3150         }
3151         WriteLog("\n");
3152 }//*/
3153 #endif
3154
3155                 if (IMASKCleared)                                               // If IMASK was cleared,
3156                 {
3157 #ifdef DSP_DEBUG_IRQ
3158                         WriteLog("DSP: Finished interrupt.\n");
3159 #endif
3160                         DSPHandleIRQs();                                        // See if any other interrupts are pending!
3161                         IMASKCleared = false;
3162                 }
3163
3164 //if (dsp_flags & REGPAGE)
3165 //      WriteLog("  --> REGPAGE has just been set!\n");
3166 #ifdef DSP_DEBUG_PL2
3167 if (doDSPDis)
3168 {
3169 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3170 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]);
3171 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]);
3172 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]);
3173 WriteLog("  --> Scoreboard: ");
3174 for(int i=0; i<32; i++)
3175         WriteLog("%s ", scoreboard[i] ? "T" : "F");
3176 WriteLog("\n");
3177 }
3178 #endif
3179                 // Stage 1a: Instruction fetch
3180                 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3181                 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3182                 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3183                 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3184                 if (pipeline[plPtrRead].opcode == 38)
3185                         pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3186                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3187 #ifdef DSP_DEBUG_PL2
3188 if (doDSPDis)
3189 {
3190 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3191 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3192 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]);
3193 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]);
3194 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]);
3195 }
3196 #endif
3197                 // Stage 1b: Read registers
3198 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3199 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3200 //Ugly, but [DONE]
3201 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3202 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3203                 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3204                         || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3205                         || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3206                         || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3207 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3208 //work--somewhat...
3209                         || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3210                         // We have a hit in the scoreboard, so we have to stall the pipeline...
3211 #ifdef DSP_DEBUG_PL2
3212 {
3213 if (doDSPDis)
3214 {
3215 WriteLog("  --> Stalling pipeline: ");
3216 if (readAffected[pipeline[plPtrRead].opcode][0])
3217         WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3218 if (readAffected[pipeline[plPtrRead].opcode][1])
3219         WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3220 WriteLog("\n");
3221 }
3222 #endif
3223                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
3224 #ifdef DSP_DEBUG_PL2
3225 }
3226 #endif
3227                 else
3228                 {
3229                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3230                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3231                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
3232
3233                         // Shouldn't we be more selective with the register scoreboarding?
3234                         // Yes, we should. !!! FIX !!! Kinda [DONE]
3235 #ifndef NEW_SCOREBOARD
3236                         scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3237 #else
3238 //Hopefully this will fix the dual MOVEQ # problem...
3239                         scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3240 #endif
3241
3242 //Advance PC here??? Yes.
3243                         dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3244                 }
3245
3246 #ifdef DSP_DEBUG_PL2
3247 if (doDSPDis)
3248 {
3249 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3250 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]);
3251 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]);
3252 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]);
3253 }
3254 #endif
3255                 // Stage 2: Execute
3256                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3257                 {
3258 #ifdef DSP_DEBUG_PL2
3259 if (doDSPDis)
3260         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"));
3261
3262 if (doDSPDis)
3263 {
3264 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3265 }
3266 #endif
3267 //CC only!
3268 #ifdef DSP_DEBUG_CC
3269 lastExec = pipeline[plPtrExec].instruction;
3270 //WriteLog("[lastExec = %04X]\n", lastExec);
3271 #endif
3272                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3273                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3274                         DSPOpcode[pipeline[plPtrExec].opcode]();
3275 //WriteLog("    --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3276                 }
3277                 else
3278 {
3279 //Let's not, until we do the stalling correctly...
3280 //But, we gotta while we're doing the comparison core...!
3281 //Or do we?                     cycles--;
3282 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3283 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3284 //to model this clock cycle behavior correctly...
3285 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3286 //don't affect the reads at stage 1...
3287 #ifdef DSP_DEBUG_STALL
3288 if (doDSPDis)
3289         WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3290 #endif
3291 }
3292
3293 #ifdef DSP_DEBUG_PL2
3294 if (doDSPDis)
3295 {
3296 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3297 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]);
3298 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]);
3299 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]);
3300 WriteLog("\n");
3301 }
3302 #endif
3303                 // Stage 3: Write back register/memory address
3304                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3305                 {
3306 /*if (pipeline[plPtrWrite].writebackRegister == 3
3307         && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3308         && !doDSPDis)
3309 {
3310         WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3311         doDSPDis = true;
3312 }//*/
3313                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3314                         {
3315                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3316                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3317                                 else
3318                                 {
3319                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3320                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3321                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3322                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3323                                         else
3324                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3325                                 }
3326                         }
3327
3328 #ifndef NEW_SCOREBOARD
3329                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3330                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3331 #else
3332 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3333                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3334                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3335                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3336 #endif
3337                 }
3338
3339                 // Push instructions through the pipeline...
3340                 plPtrRead = (++plPtrRead) & 0x03;
3341                 plPtrExec = (++plPtrExec) & 0x03;
3342                 plPtrWrite = (++plPtrWrite) & 0x03;
3343         }
3344
3345         dsp_in_exec--;
3346 }
3347
3348
3349
3350 /*
3351 //#define DSP_DEBUG_PL3
3352 //Let's try a 2 stage pipeline....
3353 void DSPExecP3(int32_t cycles)
3354 {
3355         dsp_releaseTimeSlice_flag = 0;
3356         dsp_in_exec++;
3357
3358         while (cycles > 0 && DSP_RUNNING)
3359         {
3360 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3361 //      doDSPDis = true;
3362 #ifdef DSP_DEBUG_PL3
3363 WriteLog("DSPExecP: Pipeline status...\n");
3364 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]);
3365 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]);
3366 WriteLog("  --> Scoreboard: ");
3367 for(int i=0; i<32; i++)
3368         WriteLog("%s ", scoreboard[i] ? "T" : "F");
3369 WriteLog("\n");
3370 #endif
3371                 // Stage 1a: Instruction fetch
3372                 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3373                 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3374                 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3375                 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3376                 if (pipeline[plPtrRead].opcode == 38)
3377                         pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3378                                 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3379 #ifdef DSP_DEBUG_PL3
3380 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3381 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3382 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]);
3383 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]);
3384 #endif
3385                 // Stage 1b: Read registers
3386                 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3387                         || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3388                         // We have a hit in the scoreboard, so we have to stall the pipeline...
3389 #ifdef DSP_DEBUG_PL3
3390 {
3391 WriteLog("  --> Stalling pipeline: ");
3392 if (readAffected[pipeline[plPtrRead].opcode][0])
3393         WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3394 if (readAffected[pipeline[plPtrRead].opcode][1])
3395         WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3396 WriteLog("\n");
3397 #endif
3398                         pipeline[plPtrRead].opcode = PIPELINE_STALL;
3399 #ifdef DSP_DEBUG_PL3
3400 }
3401 #endif
3402                 else
3403                 {
3404                         pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3405                         pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3406                         pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2;   // Set it to RN
3407
3408                         // Shouldn't we be more selective with the register scoreboarding?
3409                         // Yes, we should. !!! FIX !!! [Kinda DONE]
3410                         scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3411
3412 //Advance PC here??? Yes.
3413                         dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3414                 }
3415
3416 #ifdef DSP_DEBUG_PL3
3417 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3418 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]);
3419 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]);
3420 #endif
3421                 // Stage 2a: Execute
3422                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3423                 {
3424 #ifdef DSP_DEBUG_PL3
3425 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3426 #endif
3427                         DSPOpcode[pipeline[plPtrExec].opcode]();
3428                         dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3429                         cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3430                 }
3431                 else
3432                         cycles--;
3433
3434 #ifdef DSP_DEBUG_PL3
3435 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3436 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]);
3437 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]);
3438 WriteLog("\n");
3439 #endif
3440                 // Stage 2b: Write back register
3441                 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3442                 {
3443                         if (pipeline[plPtrExec].writebackRegister != 0xFF)
3444                                 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3445
3446                         if (affectsScoreboard[pipeline[plPtrExec].opcode])
3447                                 scoreboard[pipeline[plPtrExec].operand2] = false;
3448                 }
3449
3450                 // Push instructions through the pipeline...
3451                 plPtrRead = (++plPtrRead) & 0x03;
3452                 plPtrExec = (++plPtrExec) & 0x03;
3453         }
3454
3455         dsp_in_exec--;
3456 }*/
3457
3458 //
3459 // DSP pipelined opcode handlers
3460 //
3461
3462 #define PRM                             pipeline[plPtrExec].reg1
3463 #define PRN                             pipeline[plPtrExec].reg2
3464 #define PIMM1                   pipeline[plPtrExec].operand1
3465 #define PIMM2                   pipeline[plPtrExec].operand2
3466 #define PRES                    pipeline[plPtrExec].result
3467 #define PWBR                    pipeline[plPtrExec].writebackRegister
3468 #define NO_WRITEBACK    pipeline[plPtrExec].writebackRegister = 0xFF
3469 //#define DSP_PPC                       dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3470 #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))
3471 #define WRITEBACK_ADDR  pipeline[plPtrExec].writebackRegister = 0xFE
3472
3473 static void DSP_abs(void)
3474 {
3475 #ifdef DSP_DIS_ABS
3476         if (doDSPDis)
3477                 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);
3478 #endif
3479         uint32_t _Rn = PRN;
3480
3481         if (_Rn == 0x80000000)
3482                 dsp_flag_n = 1;
3483         else
3484         {
3485                 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3486                 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3487                 CLR_ZN; SET_Z(PRES);
3488         }
3489 #ifdef DSP_DIS_ABS
3490         if (doDSPDis)
3491                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3492 #endif
3493 }
3494
3495 static void DSP_add(void)
3496 {
3497 #ifdef DSP_DIS_ADD
3498         if (doDSPDis)
3499                 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);
3500 #endif
3501         uint32_t res = PRN + PRM;
3502         SET_ZNC_ADD(PRN, PRM, res);
3503         PRES = res;
3504 #ifdef DSP_DIS_ADD
3505         if (doDSPDis)
3506                 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);
3507 #endif
3508 }
3509
3510 static void DSP_addc(void)
3511 {
3512 #ifdef DSP_DIS_ADDC
3513         if (doDSPDis)
3514                 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);
3515 #endif
3516         uint32_t res = PRN + PRM + dsp_flag_c;
3517         uint32_t carry = dsp_flag_c;
3518 //      SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3519         SET_ZNC_ADD(PRN + carry, PRM, res);
3520 //      SET_ZNC_ADD(PRN, PRM + carry, res);
3521         PRES = res;
3522 #ifdef DSP_DIS_ADDC
3523         if (doDSPDis)
3524                 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);
3525 #endif
3526 }
3527
3528 static void DSP_addq(void)
3529 {
3530 #ifdef DSP_DIS_ADDQ
3531         if (doDSPDis)
3532                 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);
3533 #endif
3534         uint32_t r1 = dsp_convert_zero[PIMM1];
3535         uint32_t res = PRN + r1;
3536         CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3537         PRES = res;
3538 #ifdef DSP_DIS_ADDQ
3539         if (doDSPDis)
3540                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3541 #endif
3542 }
3543
3544 static void DSP_addqmod(void)
3545 {
3546 #ifdef DSP_DIS_ADDQMOD
3547         if (doDSPDis)
3548                 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);
3549 #endif
3550         uint32_t r1 = dsp_convert_zero[PIMM1];
3551         uint32_t r2 = PRN;
3552         uint32_t res = r2 + r1;
3553         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3554         PRES = res;
3555         SET_ZNC_ADD(r2, r1, res);
3556 #ifdef DSP_DIS_ADDQMOD
3557         if (doDSPDis)
3558                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3559 #endif
3560 }
3561
3562 static void DSP_addqt(void)
3563 {
3564 #ifdef DSP_DIS_ADDQT
3565         if (doDSPDis)
3566                 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);
3567 #endif
3568         PRES = PRN + dsp_convert_zero[PIMM1];
3569 #ifdef DSP_DIS_ADDQT
3570         if (doDSPDis)
3571                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3572 #endif
3573 }
3574
3575 static void DSP_and(void)
3576 {
3577 #ifdef DSP_DIS_AND
3578         if (doDSPDis)
3579                 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);
3580 #endif
3581         PRES = PRN & PRM;
3582         SET_ZN(PRES);
3583 #ifdef DSP_DIS_AND
3584         if (doDSPDis)
3585                 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);
3586 #endif
3587 }
3588
3589 static void DSP_bclr(void)
3590 {
3591 #ifdef DSP_DIS_BCLR
3592         if (doDSPDis)
3593                 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);
3594 #endif
3595         PRES = PRN & ~(1 << PIMM1);
3596         SET_ZN(PRES);
3597 #ifdef DSP_DIS_BCLR
3598         if (doDSPDis)
3599                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3600 #endif
3601 }
3602
3603 static void DSP_bset(void)
3604 {
3605 #ifdef DSP_DIS_BSET
3606         if (doDSPDis)
3607                 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);
3608 #endif
3609         PRES = PRN | (1 << PIMM1);
3610         SET_ZN(PRES);
3611 #ifdef DSP_DIS_BSET
3612         if (doDSPDis)
3613                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3614 #endif
3615 }
3616
3617 static void DSP_btst(void)
3618 {
3619 #ifdef DSP_DIS_BTST
3620         if (doDSPDis)
3621                 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);
3622 #endif
3623         dsp_flag_z = (~PRN >> PIMM1) & 1;
3624         NO_WRITEBACK;
3625 #ifdef DSP_DIS_BTST
3626         if (doDSPDis)
3627                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3628 #endif
3629 }
3630
3631 static void DSP_cmp(void)
3632 {
3633 #ifdef DSP_DIS_CMP
3634         if (doDSPDis)
3635                 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);
3636 #endif
3637         uint32_t res = PRN - PRM;
3638         SET_ZNC_SUB(PRN, PRM, res);
3639         NO_WRITEBACK;
3640 #ifdef DSP_DIS_CMP
3641         if (doDSPDis)
3642                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3643 #endif
3644 }
3645
3646 static void DSP_cmpq(void)
3647 {
3648         static int32_t sqtable[32] =
3649                 { 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 };
3650 #ifdef DSP_DIS_CMPQ
3651         if (doDSPDis)
3652                 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);
3653 #endif
3654         uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3655         uint32_t res = PRN - r1;
3656         SET_ZNC_SUB(PRN, r1, res);
3657         NO_WRITEBACK;
3658 #ifdef DSP_DIS_CMPQ
3659         if (doDSPDis)
3660                 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3661 #endif
3662 }
3663
3664 static void DSP_div(void)
3665 {
3666         uint32_t _Rm = PRM, _Rn = PRN;
3667
3668         if (_Rm)
3669         {
3670                 if (dsp_div_control & 1)
3671                 {
3672                         dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3673                         if (dsp_remain & 0x80000000)
3674                                 dsp_remain -= _Rm;
3675                         PRES = (((uint64_t)_Rn) << 16) / _Rm;
3676                 }
3677                 else
3678                 {
3679                         dsp_remain = _Rn % _Rm;
3680                         if (dsp_remain & 0x80000000)
3681                                 dsp_remain -= _Rm;
3682                         PRES = PRN / _Rm;
3683                 }
3684         }
3685         else
3686                 PRES = 0xFFFFFFFF;
3687 }
3688
3689 static void DSP_imacn(void)
3690 {
3691 #ifdef DSP_DIS_IMACN
3692         if (doDSPDis)
3693                 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);
3694 #endif
3695         int32_t res = (int16_t)PRM * (int16_t)PRN;
3696         dsp_acc += (int64_t)res;
3697 //Should we AND the result to fit into 40 bits here???
3698         NO_WRITEBACK;
3699 #ifdef DSP_DIS_IMACN
3700         if (doDSPDis)
3701                 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));
3702 #endif
3703 }
3704
3705 static void DSP_imult(void)
3706 {
3707 #ifdef DSP_DIS_IMULT
3708         if (doDSPDis)
3709                 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);
3710 #endif
3711         PRES = (int16_t)PRN * (int16_t)PRM;
3712         SET_ZN(PRES);
3713 #ifdef DSP_DIS_IMULT
3714         if (doDSPDis)
3715                 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);
3716 #endif
3717 }
3718
3719 static void DSP_imultn(void)
3720 {
3721 #ifdef DSP_DIS_IMULTN
3722         if (doDSPDis)
3723                 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);
3724 #endif
3725         // This is OK, since this multiply won't overflow 32 bits...
3726         int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3727         dsp_acc = (int64_t)res;
3728         SET_ZN(res);
3729         NO_WRITEBACK;
3730 #ifdef DSP_DIS_IMULTN
3731         if (doDSPDis)
3732                 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));
3733 #endif
3734 }
3735
3736 static void DSP_illegal(void)
3737 {
3738 #ifdef DSP_DIS_ILLEGAL
3739         if (doDSPDis)
3740                 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3741 #endif
3742         NO_WRITEBACK;
3743 }
3744
3745 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3746 // can cause trouble because an interrupt can occur *before* the instruction following the
3747 // jump can execute... !!! FIX !!!
3748 // This can probably be solved by judicious coding in the pipeline execution core...
3749 // And should be fixed now...
3750 static void DSP_jr(void)
3751 {
3752 #ifdef DSP_DIS_JR
3753 const char * condition[32] =
3754 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3755         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3756         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3757         "???", "???", "???", "F" };
3758         if (doDSPDis)
3759 //How come this is always off by 2???
3760                 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);
3761 #endif
3762         // KLUDGE: Used by BRANCH_CONDITION macro
3763         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3764
3765         if (BRANCH_CONDITION(PIMM2))
3766         {
3767 #ifdef DSP_DIS_JR
3768         if (doDSPDis)
3769                 WriteLog("Branched!\n");
3770 #endif
3771                 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1);           // Sign extend PIMM1
3772 //Account for pipeline effects...
3773                 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3774 //WriteLog("  --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3775
3776                 // Now that we've branched, we have to make sure that the following instruction
3777                 // is executed atomically with this one and then flush the pipeline before setting
3778                 // the new PC.
3779
3780                 // Step 1: Handle writebacks at stage 3 of pipeline
3781 /*              if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3782                 {
3783                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3784                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3785
3786                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3787                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3788                 }//*/
3789                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3790                 {
3791                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3792                         {
3793                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3794                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3795                                 else
3796                                 {
3797                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3798                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3799                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3800                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3801                                         else
3802                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3803                                 }
3804                         }
3805
3806 #ifndef NEW_SCOREBOARD
3807                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3808                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3809 #else
3810 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3811                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3812                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3813                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3814 #endif
3815                 }
3816
3817                 // Step 2: Push instruction through pipeline & execute following instruction
3818                 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3819                 //       we effectively handle the final push of the instruction through the
3820                 //       pipeline when the new PC takes effect (since when we return, the
3821                 //       pipeline code will be executing the writeback stage. If we reverse
3822                 //       the execution order of the pipeline stages, this will no longer be
3823                 //       the case!)...
3824                 pipeline[plPtrExec] = pipeline[plPtrRead];
3825 //This is BAD. We need to get that next opcode and execute it!
3826 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3827 //      remove this crap.
3828                 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3829                 {
3830                 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3831                 pipeline[plPtrExec].opcode = instruction >> 10;
3832                 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3833                 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3834                         pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3835                         pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3836                         pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2;   // Set it to RN
3837                 }//*/
3838         dsp_pc += 2;    // For DSP_DIS_* accuracy
3839                 DSPOpcode[pipeline[plPtrExec].opcode]();
3840                 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3841                 pipeline[plPtrWrite] = pipeline[plPtrExec];
3842
3843                 // Step 3: Flush pipeline & set new PC
3844                 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3845                 dsp_pc = newPC;
3846         }
3847         else
3848 #ifdef DSP_DIS_JR
3849         {
3850                 if (doDSPDis)
3851                         WriteLog("Branch NOT taken.\n");
3852 #endif
3853                 NO_WRITEBACK;
3854 #ifdef DSP_DIS_JR
3855         }
3856 #endif
3857 //      WriteLog("  --> DSP_PC: %08X\n", dsp_pc);
3858 }
3859
3860 static void DSP_jump(void)
3861 {
3862 #ifdef DSP_DIS_JUMP
3863 const char * condition[32] =
3864 {       "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3865         "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3866         "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3867         "???", "???", "???", "F" };
3868         if (doDSPDis)
3869                 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);
3870 #endif
3871         // KLUDGE: Used by BRANCH_CONDITION macro
3872         uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3873
3874         if (BRANCH_CONDITION(PIMM2))
3875         {
3876 #ifdef DSP_DIS_JUMP
3877         if (doDSPDis)
3878                 WriteLog("Branched!\n");
3879 #endif
3880                 uint32_t PCSave = PRM;
3881                 // Now that we've branched, we have to make sure that the following instruction
3882                 // is executed atomically with this one and then flush the pipeline before setting
3883                 // the new PC.
3884
3885                 // Step 1: Handle writebacks at stage 3 of pipeline
3886 /*              if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3887                 {
3888                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3889                                 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3890
3891                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3892                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3893                 }//*/
3894                 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3895                 {
3896                         if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3897                         {
3898                                 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3899                                         dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3900                                 else
3901                                 {
3902                                         if (pipeline[plPtrWrite].type == TYPE_BYTE)
3903                                                 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3904                                         else if (pipeline[plPtrWrite].type == TYPE_WORD)
3905                                                 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3906                                         else
3907                                                 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3908                                 }
3909                         }
3910
3911 #ifndef NEW_SCOREBOARD
3912                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3913                                 scoreboard[pipeline[plPtrWrite].operand2] = false;
3914 #else
3915 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3916                         if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3917                                 if (scoreboard[pipeline[plPtrWrite].operand2])
3918                                         scoreboard[pipeline[plPtrWrite].operand2]--;
3919 #endif
3920                 }
3921
3922                 // Step 2: Push instruction through pipeline & execute following instruction
3923                 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3924                 //       we effectively handle the final push of the instruction through the
3925                 //       pipeline when the new PC takes effect (since when we return, the
3926                 //       pipeline code will be executing the writeback stage. If we reverse
3927                 //       the execution order of the pipeline stages, this will no longer be
3928                 //       the case!)...
3929                 pipeline[plPtrExec] = pipeline[plPtrRead];
3930 //This is BAD. We need to get that next opcode and execute it!
3931 //Also, same problem in JR!
3932 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3933 //      remove this crap.
3934                 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3935                 {
3936                 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3937                 pipeline[plPtrExec].opcode = instruction >> 10;
3938                 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3939                 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3940                         pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3941                         pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3942                         pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2;   // Set it to RN
3943                 }//*/
3944         dsp_pc += 2;    // For DSP_DIS_* accuracy
3945                 DSPOpcode[pipeline[plPtrExec].opcode]();
3946                 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3947                 pipeline[plPtrWrite] = pipeline[plPtrExec];
3948
3949                 // Step 3: Flush pipeline & set new PC
3950                 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3951                 dsp_pc = PCSave;
3952         }
3953         else
3954 #ifdef DSP_DIS_JUMP
3955         {
3956                 if (doDSPDis)
3957                         WriteLog("Branch NOT taken.\n");
3958 #endif
3959                 NO_WRITEBACK;
3960 #ifdef DSP_DIS_JUMP
3961         }
3962 #endif
3963 }
3964
3965 static void DSP_load(void)
3966 {
3967 #ifdef DSP_DIS_LOAD
3968         if (doDSPDis)
3969                 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);
3970 #endif
3971 #ifdef DSP_CORRECT_ALIGNMENT
3972         PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3973 #else
3974         PRES = DSPReadLong(PRM, DSP);
3975 #endif
3976 #ifdef DSP_DIS_LOAD
3977         if (doDSPDis)
3978                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3979 #endif
3980 }
3981
3982 static void DSP_loadb(void)
3983 {
3984 #ifdef DSP_DIS_LOADB
3985         if (doDSPDis)
3986                 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);
3987 #endif
3988         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3989                 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3990         else
3991                 PRES = JaguarReadByte(PRM, DSP);
3992 #ifdef DSP_DIS_LOADB
3993         if (doDSPDis)
3994                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3995 #endif
3996 }
3997
3998 static void DSP_loadw(void)
3999 {
4000 #ifdef DSP_DIS_LOADW
4001         if (doDSPDis)
4002                 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);
4003 #endif
4004 #ifdef DSP_CORRECT_ALIGNMENT
4005         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4006                 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4007         else
4008                 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4009 #else
4010         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4011                 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4012         else
4013                 PRES = JaguarReadWord(PRM, DSP);
4014 #endif
4015 #ifdef DSP_DIS_LOADW
4016         if (doDSPDis)
4017                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4018 #endif
4019 }
4020
4021 static void DSP_load_r14_i(void)
4022 {
4023 #ifdef DSP_DIS_LOAD14I
4024         if (doDSPDis)
4025                 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);
4026 #endif
4027 #ifdef DSP_CORRECT_ALIGNMENT
4028         PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4029 #else
4030         PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4031 #endif
4032 #ifdef DSP_DIS_LOAD14I
4033         if (doDSPDis)
4034                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4035 #endif
4036 }
4037
4038 static void DSP_load_r14_r(void)
4039 {
4040 #ifdef DSP_DIS_LOAD14R
4041         if (doDSPDis)
4042                 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);
4043 #endif
4044 #ifdef DSP_CORRECT_ALIGNMENT
4045         PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4046 #else
4047         PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4048 #endif
4049 #ifdef DSP_DIS_LOAD14R
4050         if (doDSPDis)
4051                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4052 #endif
4053 }
4054
4055 static void DSP_load_r15_i(void)
4056 {
4057 #ifdef DSP_DIS_LOAD15I
4058         if (doDSPDis)
4059                 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);
4060 #endif
4061 #ifdef DSP_CORRECT_ALIGNMENT
4062         PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4063 #else
4064         PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4065 #endif
4066 #ifdef DSP_DIS_LOAD15I
4067         if (doDSPDis)
4068                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4069 #endif
4070 }
4071
4072 static void DSP_load_r15_r(void)
4073 {
4074 #ifdef DSP_DIS_LOAD15R
4075         if (doDSPDis)
4076                 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);
4077 #endif
4078 #ifdef DSP_CORRECT_ALIGNMENT
4079         PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4080 #else
4081         PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4082 #endif
4083 #ifdef DSP_DIS_LOAD15R
4084         if (doDSPDis)
4085                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4086 #endif
4087 }
4088
4089 static void DSP_mirror(void)
4090 {
4091         uint32_t r1 = PRN;
4092         PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4093         SET_ZN(PRES);
4094 }
4095
4096 static void DSP_mmult(void)
4097 {
4098         int count       = dsp_matrix_control&0x0f;
4099         uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4100         int64_t accum = 0;
4101         uint32_t res;
4102
4103         if (!(dsp_matrix_control & 0x10))
4104         {
4105                 for (int i = 0; i < count; i++)
4106                 {
4107                         int16_t a;
4108                         if (i&0x01)
4109                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4110                         else
4111                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4112                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4113                         accum += a*b;
4114                         addr += 4;
4115                 }
4116         }
4117         else
4118         {
4119                 for (int i = 0; i < count; i++)
4120                 {
4121                         int16_t a;
4122                         if (i&0x01)
4123                                 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4124                         else
4125                                 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4126                         int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4127                         accum += a*b;
4128                         addr += 4 * count;
4129                 }
4130         }
4131
4132         PRES = res = (int32_t)accum;
4133         // carry flag to do
4134 //NOTE: The flags are set based upon the last add/multiply done...
4135         SET_ZN(PRES);
4136 }
4137
4138 static void DSP_move(void)
4139 {
4140 #ifdef DSP_DIS_MOVE
4141         if (doDSPDis)
4142                 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);
4143 #endif
4144         PRES = PRM;
4145 #ifdef DSP_DIS_MOVE
4146         if (doDSPDis)
4147                 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);
4148 #endif
4149 }
4150
4151 static void DSP_movefa(void)
4152 {
4153 #ifdef DSP_DIS_MOVEFA
4154         if (doDSPDis)
4155 //              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);
4156                 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);
4157 #endif
4158 //      PRES = ALTERNATE_RM;
4159         PRES = dsp_alternate_reg[PIMM1];
4160 #ifdef DSP_DIS_MOVEFA
4161         if (doDSPDis)
4162 //              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);
4163                 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);
4164 #endif
4165 }
4166
4167 static void DSP_movei(void)
4168 {
4169 #ifdef DSP_DIS_MOVEI
4170         if (doDSPDis)
4171                 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);
4172 #endif
4173 //      // This instruction is followed by 32-bit value in LSW / MSW format...
4174 //      PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4175 //      dsp_pc += 4;
4176 #ifdef DSP_DIS_MOVEI
4177         if (doDSPDis)
4178                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4179 #endif
4180 }
4181
4182 static void DSP_movepc(void)
4183 {
4184 #ifdef DSP_DIS_MOVEPC
4185         if (doDSPDis)
4186                 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);
4187 #endif
4188 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4189 //      PRES = dsp_pc - 2;
4190 //Account for pipeline effects...
4191         PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4192 #ifdef DSP_DIS_MOVEPC
4193         if (doDSPDis)
4194                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4195 #endif
4196 }
4197
4198 static void DSP_moveq(void)
4199 {
4200 #ifdef DSP_DIS_MOVEQ
4201         if (doDSPDis)
4202                 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);
4203 #endif
4204         PRES = PIMM1;
4205 #ifdef DSP_DIS_MOVEQ
4206         if (doDSPDis)
4207                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4208 #endif
4209 }
4210
4211 static void DSP_moveta(void)
4212 {
4213 #ifdef DSP_DIS_MOVETA
4214         if (doDSPDis)
4215 //              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);
4216                 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]);
4217 #endif
4218 //      ALTERNATE_RN = PRM;
4219         dsp_alternate_reg[PIMM2] = PRM;
4220         NO_WRITEBACK;
4221 #ifdef DSP_DIS_MOVETA
4222         if (doDSPDis)
4223 //              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);
4224                 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]);
4225 #endif
4226 }
4227
4228 static void DSP_mtoi(void)
4229 {
4230         PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4231         SET_ZN(PRES);
4232 }
4233
4234 static void DSP_mult(void)
4235 {
4236 #ifdef DSP_DIS_MULT
4237         if (doDSPDis)
4238                 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);
4239 #endif
4240         PRES = (uint16_t)PRM * (uint16_t)PRN;
4241         SET_ZN(PRES);
4242 #ifdef DSP_DIS_MULT
4243         if (doDSPDis)
4244                 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);
4245 #endif
4246 }
4247
4248 static void DSP_neg(void)
4249 {
4250 #ifdef DSP_DIS_NEG
4251         if (doDSPDis)
4252                 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);
4253 #endif
4254         uint32_t res = -PRN;
4255         SET_ZNC_SUB(0, PRN, res);
4256         PRES = res;
4257 #ifdef DSP_DIS_NEG
4258         if (doDSPDis)
4259                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4260 #endif
4261 }
4262
4263 static void DSP_nop(void)
4264 {
4265 #ifdef DSP_DIS_NOP
4266         if (doDSPDis)
4267                 WriteLog("%06X: NOP    [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4268 #endif
4269         NO_WRITEBACK;
4270 }
4271
4272 static void DSP_normi(void)
4273 {
4274         uint32_t _Rm = PRM;
4275         uint32_t res = 0;
4276
4277         if (_Rm)
4278         {
4279                 while ((_Rm & 0xffc00000) == 0)
4280                 {
4281                         _Rm <<= 1;
4282                         res--;
4283                 }
4284                 while ((_Rm & 0xff800000) != 0)
4285                 {
4286                         _Rm >>= 1;
4287                         res++;
4288                 }
4289         }
4290         PRES = res;
4291         SET_ZN(PRES);
4292 }
4293
4294 static void DSP_not(void)
4295 {
4296 #ifdef DSP_DIS_NOT
4297         if (doDSPDis)
4298                 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);
4299 #endif
4300         PRES = ~PRN;
4301         SET_ZN(PRES);
4302 #ifdef DSP_DIS_NOT
4303         if (doDSPDis)
4304                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4305 #endif
4306 }
4307
4308 static void DSP_or(void)
4309 {
4310 #ifdef DSP_DIS_OR
4311         if (doDSPDis)
4312                 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);
4313 #endif
4314         PRES = PRN | PRM;
4315         SET_ZN(PRES);
4316 #ifdef DSP_DIS_OR
4317         if (doDSPDis)
4318                 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);
4319 #endif
4320 }
4321
4322 static void DSP_resmac(void)
4323 {
4324 #ifdef DSP_DIS_RESMAC
4325         if (doDSPDis)
4326                 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));
4327 #endif
4328         PRES = (uint32_t)dsp_acc;
4329 #ifdef DSP_DIS_RESMAC
4330         if (doDSPDis)
4331                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4332 #endif
4333 }
4334
4335 static void DSP_ror(void)
4336 {
4337 #ifdef DSP_DIS_ROR
4338         if (doDSPDis)
4339                 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);
4340 #endif
4341         uint32_t r1 = PRM & 0x1F;
4342         uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4343         SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4344         PRES = res;
4345 #ifdef DSP_DIS_ROR
4346         if (doDSPDis)
4347                 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);
4348 #endif
4349 }
4350
4351 static void DSP_rorq(void)
4352 {
4353 #ifdef DSP_DIS_RORQ
4354         if (doDSPDis)
4355                 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);
4356 #endif
4357         uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4358         uint32_t r2 = PRN;
4359         uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4360         PRES = res;
4361         SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4362 #ifdef DSP_DIS_RORQ
4363         if (doDSPDis)
4364                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4365 #endif
4366 }
4367
4368 static void DSP_sat16s(void)
4369 {
4370         int32_t r2 = PRN;
4371         uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4372         PRES = res;
4373         SET_ZN(res);
4374 }
4375
4376 static void DSP_sat32s(void)
4377 {
4378         int32_t r2 = (uint32_t)PRN;
4379         int32_t temp = dsp_acc >> 32;
4380         uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4381         PRES = res;
4382         SET_ZN(res);
4383 }
4384
4385 static void DSP_sh(void)
4386 {
4387         int32_t sRm = (int32_t)PRM;
4388         uint32_t _Rn = PRN;
4389
4390         if (sRm < 0)
4391         {
4392                 uint32_t shift = -sRm;
4393
4394                 if (shift >= 32)
4395                         shift = 32;
4396
4397                 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4398
4399                 while (shift)
4400                 {
4401                         _Rn <<= 1;
4402                         shift--;
4403                 }
4404         }
4405         else
4406         {
4407                 uint32_t shift = sRm;
4408
4409                 if (shift >= 32)
4410                         shift = 32;
4411
4412                 dsp_flag_c = _Rn & 0x1;
4413
4414                 while (shift)
4415                 {
4416                         _Rn >>= 1;
4417                         shift--;
4418                 }
4419         }
4420
4421         PRES = _Rn;
4422         SET_ZN(PRES);
4423 }
4424
4425 static void DSP_sha(void)
4426 {
4427         int32_t sRm = (int32_t)PRM;
4428         uint32_t _Rn = PRN;
4429
4430         if (sRm < 0)
4431         {
4432                 uint32_t shift = -sRm;
4433
4434                 if (shift >= 32)
4435                         shift = 32;
4436
4437                 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4438
4439                 while (shift)
4440                 {
4441                         _Rn <<= 1;
4442                         shift--;
4443                 }
4444         }
4445         else
4446         {
4447                 uint32_t shift = sRm;
4448
4449                 if (shift >= 32)
4450                         shift = 32;
4451
4452                 dsp_flag_c = _Rn & 0x1;
4453
4454                 while (shift)
4455                 {
4456                         _Rn = ((int32_t)_Rn) >> 1;
4457                         shift--;
4458                 }
4459         }
4460
4461         PRES = _Rn;
4462         SET_ZN(PRES);
4463 }
4464
4465 static void DSP_sharq(void)
4466 {
4467 #ifdef DSP_DIS_SHARQ
4468         if (doDSPDis)
4469                 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);
4470 #endif
4471         uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4472         SET_ZN(res); dsp_flag_c = PRN & 0x01;
4473         PRES = res;
4474 #ifdef DSP_DIS_SHARQ
4475         if (doDSPDis)
4476                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4477 #endif
4478 }
4479
4480 static void DSP_shlq(void)
4481 {
4482 #ifdef DSP_DIS_SHLQ
4483         if (doDSPDis)
4484                 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);
4485 #endif
4486         int32_t r1 = 32 - PIMM1;
4487         uint32_t res = PRN << r1;
4488         SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4489         PRES = res;
4490 #ifdef DSP_DIS_SHLQ
4491         if (doDSPDis)
4492                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4493 #endif
4494 }
4495
4496 static void DSP_shrq(void)
4497 {
4498 #ifdef DSP_DIS_SHRQ
4499         if (doDSPDis)
4500                 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);
4501 #endif
4502         int32_t r1 = dsp_convert_zero[PIMM1];
4503         uint32_t res = PRN >> r1;
4504         SET_ZN(res); dsp_flag_c = PRN & 1;
4505         PRES = res;
4506 #ifdef DSP_DIS_SHRQ
4507         if (doDSPDis)
4508                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4509 #endif
4510 }
4511
4512 static void DSP_store(void)
4513 {
4514 #ifdef DSP_DIS_STORE
4515         if (doDSPDis)
4516                 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);
4517 #endif
4518 //      DSPWriteLong(PRM, PRN, DSP);
4519 //      NO_WRITEBACK;
4520 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4521         pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4522 #else
4523         pipeline[plPtrExec].address = PRM;
4524 #endif
4525         pipeline[plPtrExec].value = PRN;
4526         pipeline[plPtrExec].type = TYPE_DWORD;
4527         WRITEBACK_ADDR;
4528 }
4529
4530 static void DSP_storeb(void)
4531 {
4532 #ifdef DSP_DIS_STOREB
4533         if (doDSPDis)
4534                 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);
4535 #endif
4536 //      if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4537 //              DSPWriteLong(PRM, PRN & 0xFF, DSP);
4538 //      else
4539 //              JaguarWriteByte(PRM, PRN, DSP);
4540 //
4541 //      NO_WRITEBACK;
4542         pipeline[plPtrExec].address = PRM;
4543
4544         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4545         {
4546                 pipeline[plPtrExec].value = PRN & 0xFF;
4547                 pipeline[plPtrExec].type = TYPE_DWORD;
4548         }
4549         else
4550         {
4551                 pipeline[plPtrExec].value = PRN;
4552                 pipeline[plPtrExec].type = TYPE_BYTE;
4553         }
4554
4555         WRITEBACK_ADDR;
4556 }
4557
4558 static void DSP_storew(void)
4559 {
4560 #ifdef DSP_DIS_STOREW
4561         if (doDSPDis)
4562                 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);
4563 #endif
4564 //      if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4565 //              DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4566 //      else
4567 //              JaguarWriteWord(PRM, PRN, DSP);
4568 //
4569 //      NO_WRITEBACK;
4570 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4571         pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4572 #else
4573         pipeline[plPtrExec].address = PRM;
4574 #endif
4575
4576         if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4577         {
4578                 pipeline[plPtrExec].value = PRN & 0xFFFF;
4579                 pipeline[plPtrExec].type = TYPE_DWORD;
4580         }
4581         else
4582         {
4583                 pipeline[plPtrExec].value = PRN;
4584                 pipeline[plPtrExec].type = TYPE_WORD;
4585         }
4586         WRITEBACK_ADDR;
4587 }
4588
4589 static void DSP_store_r14_i(void)
4590 {
4591 #ifdef DSP_DIS_STORE14I
4592         if (doDSPDis)
4593                 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));
4594 #endif
4595 //      DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4596 //      NO_WRITEBACK;
4597 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4598         pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4599 #else
4600         pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4601 #endif
4602         pipeline[plPtrExec].value = PRN;
4603         pipeline[plPtrExec].type = TYPE_DWORD;
4604         WRITEBACK_ADDR;
4605 }
4606
4607 static void DSP_store_r14_r(void)
4608 {
4609 //      DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4610 //      NO_WRITEBACK;
4611 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4612         pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4613 #else
4614         pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4615 #endif
4616         pipeline[plPtrExec].value = PRN;
4617         pipeline[plPtrExec].type = TYPE_DWORD;
4618         WRITEBACK_ADDR;
4619 }
4620
4621 static void DSP_store_r15_i(void)
4622 {
4623 #ifdef DSP_DIS_STORE15I
4624         if (doDSPDis)
4625                 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));
4626 #endif
4627 //      DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4628 //      NO_WRITEBACK;
4629 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4630         pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4631 #else
4632         pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4633 #endif
4634         pipeline[plPtrExec].value = PRN;
4635         pipeline[plPtrExec].type = TYPE_DWORD;
4636         WRITEBACK_ADDR;
4637 }
4638
4639 static void DSP_store_r15_r(void)
4640 {
4641 //      DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4642 //      NO_WRITEBACK;
4643 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4644         pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4645 #else
4646         pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4647 #endif
4648         pipeline[plPtrExec].value = PRN;
4649         pipeline[plPtrExec].type = TYPE_DWORD;
4650         WRITEBACK_ADDR;
4651 }
4652
4653 static void DSP_sub(void)
4654 {
4655 #ifdef DSP_DIS_SUB
4656         if (doDSPDis)
4657                 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);
4658 #endif
4659         uint32_t res = PRN - PRM;
4660         SET_ZNC_SUB(PRN, PRM, res);
4661         PRES = res;
4662 #ifdef DSP_DIS_SUB
4663         if (doDSPDis)
4664                 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);
4665 #endif
4666 }
4667
4668 static void DSP_subc(void)
4669 {
4670 #ifdef DSP_DIS_SUBC
4671         if (doDSPDis)
4672                 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);
4673 #endif
4674         uint32_t res = PRN - PRM - dsp_flag_c;
4675         uint32_t borrow = dsp_flag_c;
4676         SET_ZNC_SUB(PRN - borrow, PRM, res);
4677         PRES = res;
4678 #ifdef DSP_DIS_SUBC
4679         if (doDSPDis)
4680                 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);
4681 #endif
4682 }
4683
4684 static void DSP_subq(void)
4685 {
4686 #ifdef DSP_DIS_SUBQ
4687         if (doDSPDis)
4688                 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);
4689 #endif
4690         uint32_t r1 = dsp_convert_zero[PIMM1];
4691         uint32_t res = PRN - r1;
4692         SET_ZNC_SUB(PRN, r1, res);
4693         PRES = res;
4694 #ifdef DSP_DIS_SUBQ
4695         if (doDSPDis)
4696                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4697 #endif
4698 }
4699
4700 static void DSP_subqmod(void)
4701 {
4702         uint32_t r1 = dsp_convert_zero[PIMM1];
4703         uint32_t r2 = PRN;
4704         uint32_t res = r2 - r1;
4705         res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4706         PRES = res;
4707         SET_ZNC_SUB(r2, r1, res);
4708 }
4709
4710 static void DSP_subqt(void)
4711 {
4712 #ifdef DSP_DIS_SUBQT
4713         if (doDSPDis)
4714                 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);
4715 #endif
4716         PRES = PRN - dsp_convert_zero[PIMM1];
4717 #ifdef DSP_DIS_SUBQT
4718         if (doDSPDis)
4719                 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4720 #endif
4721 }
4722
4723 static void DSP_xor(void)
4724 {
4725 #ifdef DSP_DIS_XOR
4726         if (doDSPDis)
4727                 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);
4728 #endif
4729         PRES = PRN ^ PRM;
4730         SET_ZN(PRES);
4731 #ifdef DSP_DIS_XOR
4732         if (doDSPDis)
4733                 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);
4734 #endif
4735 }