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