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