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