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