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