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