4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James L. Hammons
11 #include <SDL.h> // Used only for SDL_GetTicks...
22 //#define DSP_DEBUG_IRQ
23 //#define DSP_DEBUG_PL2
24 //#define DSP_DEBUG_STALL
25 //#define DSP_DEBUG_CC
26 #define NEW_SCOREBOARD
28 // Disassembly definitions
34 #define DSP_DIS_ADDQMOD
44 #define DSP_DIS_IMULTN
45 #define DSP_DIS_ILLEGAL
49 #define DSP_DIS_LOAD14I
50 #define DSP_DIS_LOAD14R
51 #define DSP_DIS_LOAD15I
52 #define DSP_DIS_LOAD15R
58 #define DSP_DIS_MOVEFA
59 #define DSP_DIS_MOVEPC // Pipeline only!
60 #define DSP_DIS_MOVETA
66 #define DSP_DIS_RESMAC
73 #define DSP_DIS_STORE14I
74 #define DSP_DIS_STORE15I
75 #define DSP_DIS_STOREB
76 #define DSP_DIS_STOREW
83 bool doDSPDis = false;
84 //bool doDSPDis = true;
119 + load_r15_indexed 284500
121 + store_r15_indexed 47416
125 + load_r14_ri 1229448
128 // Pipeline structures
130 const bool affectsScoreboard[64] =
132 true, true, true, true,
133 true, true, true, true,
134 true, true, true, true,
135 true, false, true, true,
137 true, true, false, true,
138 false, true, true, true,
139 true, true, true, true,
140 true, true, false, false,
142 true, true, true, true,
143 false, true, true, true,
144 true, true, true, true,
145 true, false, false, false,
147 true, false, false, true,
148 false, false, true, true,
149 true, false, true, true,
150 false, false, false, true
156 uint8 opcode, operand1, operand2;
157 uint32 reg1, reg2, areg1, areg2;
159 uint8 writebackRegister;
160 // General memory store...
169 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
170 #ifndef NEW_SCOREBOARD
173 uint8 scoreboard[32];
175 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
176 PipelineStage pipeline[4];
177 bool IMASKCleared = false;
179 // DSP flags (old--have to get rid of this crap)
181 #define CINT0FLAG 0x00200
182 #define CINT1FLAG 0x00400
183 #define CINT2FLAG 0x00800
184 #define CINT3FLAG 0x01000
185 #define CINT4FLAG 0x02000
186 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
187 #define CINT5FLAG 0x20000 /* DSP only */
191 #define ZERO_FLAG 0x00001
192 #define CARRY_FLAG 0x00002
193 #define NEGA_FLAG 0x00004
194 #define IMASK 0x00008
195 #define INT_ENA0 0x00010
196 #define INT_ENA1 0x00020
197 #define INT_ENA2 0x00040
198 #define INT_ENA3 0x00080
199 #define INT_ENA4 0x00100
200 #define INT_CLR0 0x00200
201 #define INT_CLR1 0x00400
202 #define INT_CLR2 0x00800
203 #define INT_CLR3 0x01000
204 #define INT_CLR4 0x02000
205 #define REGPAGE 0x04000
206 #define DMAEN 0x08000
207 #define INT_ENA5 0x10000
208 #define INT_CLR5 0x20000
212 #define DSPGO 0x00001
213 #define CPUINT 0x00002
214 #define DSPINT0 0x00004
215 #define SINGLE_STEP 0x00008
216 #define SINGLE_GO 0x00010
218 #define INT_LAT0 0x00040
219 #define INT_LAT1 0x00080
220 #define INT_LAT2 0x00100
221 #define INT_LAT3 0x00200
222 #define INT_LAT4 0x00400
223 #define BUS_HOG 0x00800
224 #define VERSION 0x0F000
225 #define INT_LAT5 0x10000
227 extern uint32 jaguar_mainRom_crc32;
229 // Is opcode 62 *really* a NOP? Seems like it...
230 static void dsp_opcode_abs(void);
231 static void dsp_opcode_add(void);
232 static void dsp_opcode_addc(void);
233 static void dsp_opcode_addq(void);
234 static void dsp_opcode_addqmod(void);
235 static void dsp_opcode_addqt(void);
236 static void dsp_opcode_and(void);
237 static void dsp_opcode_bclr(void);
238 static void dsp_opcode_bset(void);
239 static void dsp_opcode_btst(void);
240 static void dsp_opcode_cmp(void);
241 static void dsp_opcode_cmpq(void);
242 static void dsp_opcode_div(void);
243 static void dsp_opcode_imacn(void);
244 static void dsp_opcode_imult(void);
245 static void dsp_opcode_imultn(void);
246 static void dsp_opcode_jr(void);
247 static void dsp_opcode_jump(void);
248 static void dsp_opcode_load(void);
249 static void dsp_opcode_loadb(void);
250 static void dsp_opcode_loadw(void);
251 static void dsp_opcode_load_r14_indexed(void);
252 static void dsp_opcode_load_r14_ri(void);
253 static void dsp_opcode_load_r15_indexed(void);
254 static void dsp_opcode_load_r15_ri(void);
255 static void dsp_opcode_mirror(void);
256 static void dsp_opcode_mmult(void);
257 static void dsp_opcode_move(void);
258 static void dsp_opcode_movei(void);
259 static void dsp_opcode_movefa(void);
260 static void dsp_opcode_move_pc(void);
261 static void dsp_opcode_moveq(void);
262 static void dsp_opcode_moveta(void);
263 static void dsp_opcode_mtoi(void);
264 static void dsp_opcode_mult(void);
265 static void dsp_opcode_neg(void);
266 static void dsp_opcode_nop(void);
267 static void dsp_opcode_normi(void);
268 static void dsp_opcode_not(void);
269 static void dsp_opcode_or(void);
270 static void dsp_opcode_resmac(void);
271 static void dsp_opcode_ror(void);
272 static void dsp_opcode_rorq(void);
273 static void dsp_opcode_xor(void);
274 static void dsp_opcode_sat16s(void);
275 static void dsp_opcode_sat32s(void);
276 static void dsp_opcode_sh(void);
277 static void dsp_opcode_sha(void);
278 static void dsp_opcode_sharq(void);
279 static void dsp_opcode_shlq(void);
280 static void dsp_opcode_shrq(void);
281 static void dsp_opcode_store(void);
282 static void dsp_opcode_storeb(void);
283 static void dsp_opcode_storew(void);
284 static void dsp_opcode_store_r14_indexed(void);
285 static void dsp_opcode_store_r14_ri(void);
286 static void dsp_opcode_store_r15_indexed(void);
287 static void dsp_opcode_store_r15_ri(void);
288 static void dsp_opcode_sub(void);
289 static void dsp_opcode_subc(void);
290 static void dsp_opcode_subq(void);
291 static void dsp_opcode_subqmod(void);
292 static void dsp_opcode_subqt(void);
294 uint8 dsp_opcode_cycles[64] =
296 3, 3, 3, 3, 3, 3, 3, 3,
297 3, 3, 3, 3, 3, 3, 3, 3,
298 3, 3, 1, 3, 1, 18, 3, 3,
299 3, 3, 3, 3, 3, 3, 3, 3,
300 3, 3, 2, 2, 2, 2, 3, 4,
301 5, 4, 5, 6, 6, 1, 1, 1,
302 1, 2, 2, 2, 1, 1, 9, 3,
303 3, 1, 6, 6, 2, 2, 3, 3
305 //Here's a QnD kludge...
306 //This is wrong, wrong, WRONG, but it seems to work for the time being...
307 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
308 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
309 /*uint8 dsp_opcode_cycles[64] =
311 1, 1, 1, 1, 1, 1, 1, 1,
312 1, 1, 1, 1, 1, 1, 1, 1,
313 1, 1, 1, 1, 1, 9, 1, 1,
314 1, 1, 1, 1, 1, 1, 1, 1,
315 1, 1, 1, 1, 1, 1, 1, 2,
316 2, 2, 2, 3, 3, 1, 1, 1,
317 1, 1, 1, 1, 1, 1, 4, 1,
318 1, 1, 3, 3, 1, 1, 1, 1
321 void (* dsp_opcode[64])() =
323 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
324 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
325 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
326 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
327 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
328 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
329 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
330 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
331 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
332 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
333 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
334 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
335 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
336 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
337 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
338 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
341 uint32 dsp_opcode_use[65];
343 const char * dsp_opcode_str[65]=
345 "add", "addc", "addq", "addqt",
346 "sub", "subc", "subq", "subqt",
347 "neg", "and", "or", "xor",
348 "not", "btst", "bset", "bclr",
349 "mult", "imult", "imultn", "resmac",
350 "imacn", "div", "abs", "sh",
351 "shlq", "shrq", "sha", "sharq",
352 "ror", "rorq", "cmp", "cmpq",
353 "subqmod", "sat16s", "move", "moveq",
354 "moveta", "movefa", "movei", "loadb",
355 "loadw", "load", "sat32s", "load_r14_indexed",
356 "load_r15_indexed", "storeb", "storew", "store",
357 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
358 "jump", "jr", "mmult", "mtoi",
359 "normi", "nop", "load_r14_ri", "load_r15_ri",
360 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
365 static uint64 dsp_acc; // 40 bit register, NOT 32!
366 static uint32 dsp_remain;
367 static uint32 dsp_modulo;
368 static uint32 dsp_flags;
369 static uint32 dsp_matrix_control;
370 static uint32 dsp_pointer_to_matrix;
371 static uint32 dsp_data_organization;
373 static uint32 dsp_div_control;
374 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
375 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
376 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
378 static uint32 dsp_opcode_first_parameter;
379 static uint32 dsp_opcode_second_parameter;
381 #define DSP_RUNNING (dsp_control & 0x01)
383 #define RM dsp_reg[dsp_opcode_first_parameter]
384 #define RN dsp_reg[dsp_opcode_second_parameter]
385 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
386 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
387 #define IMM_1 dsp_opcode_first_parameter
388 #define IMM_2 dsp_opcode_second_parameter
390 #define CLR_Z (dsp_flag_z = 0)
391 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
392 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
393 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
394 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
395 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
396 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
397 #define SET_ZN(r) SET_N(r); SET_Z(r)
398 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
399 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
401 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 };
402 uint8 * dsp_branch_condition_table = NULL;
403 static uint16 * mirror_table = NULL;
404 static uint8 dsp_ram_8[0x2000];
406 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
408 static uint32 dsp_in_exec = 0;
409 static uint32 dsp_releaseTimeSlice_flag = 0;
414 // Comparison core vars (used only for core comparison! :-)
415 static uint64 count = 0;
416 static uint8 ram1[0x2000], ram2[0x2000];
417 static uint32 regs1[64], regs2[64];
418 static uint32 ctrl1[14], ctrl2[14];
421 // Private function prototypes
423 void DSPDumpRegisters(void);
424 void DSPDumpDisassembly(void);
425 void FlushDSPPipeline(void);
428 void dsp_reset_stats(void)
430 for(int i=0; i<65; i++)
431 dsp_opcode_use[i] = 0;
434 void DSPReleaseTimeslice(void)
436 //This does absolutely nothing!!! !!! FIX !!!
437 dsp_releaseTimeSlice_flag = 1;
440 void dsp_build_branch_condition_table(void)
442 // Allocate the mirror table
444 mirror_table = (uint16 *)memory_malloc(65536 * sizeof(uint16), "DSP mirror table");
446 // Fill in the mirror table
448 for(int i=0; i<65536; i++)
449 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
450 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
451 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
452 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
453 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
454 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
455 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
456 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
458 if (!dsp_branch_condition_table)
460 dsp_branch_condition_table = (uint8 *)memory_malloc(32 * 8 * sizeof(uint8), "DSP branch condition table");
462 // Fill in the condition table
463 if (dsp_branch_condition_table)
465 for(int i=0; i<8; i++)
467 for(int j=0; j<32; j++)
474 if (!(i & ZERO_FLAG))
477 if (i & (CARRY_FLAG << (j >> 4)))
480 if (!(i & (CARRY_FLAG << (j >> 4))))
482 dsp_branch_condition_table[i * 32 + j] = result;
489 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
491 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
492 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
494 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
497 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
499 if (offset==0xF1CFE0)
502 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
503 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
505 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
507 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
509 if ((offset&0x03)==0)
512 if ((offset&0x03)==1)
513 return((data>>16)&0xff);
515 if ((offset&0x03)==2)
516 return((data>>8)&0xff);
518 if ((offset&0x03)==3)
522 return JaguarReadByte(offset, who);
525 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
527 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
528 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
530 offset &= 0xFFFFFFFE;
532 /* if (jaguar_mainRom_crc32==0xa74a97cd)
534 if (offset==0xF1A114) return(0x0000);
535 if (offset==0xF1A116) return(0x0000);
536 if (offset==0xF1B000) return(0x1234);
537 if (offset==0xF1B002) return(0x5678);
540 if (jaguar_mainRom_crc32==0x7ae20823)
542 if (offset==0xF1B9D8) return(0x0000);
543 if (offset==0xF1B9Da) return(0x0000);
544 if (offset==0xF1B2C0) return(0x0000);
545 if (offset==0xF1B2C2) return(0x0000);
548 // pour permettre � wolfenstein 3d de tourner sans le dsp
549 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
553 // pour permettre � nba jam de tourner sans le dsp
554 /* if (jaguar_mainRom_crc32==0x4faddb18)
556 if (offset==0xf1b2c0) return(0);
557 if (offset==0xf1b2c2) return(0);
558 if (offset==0xf1b240) return(0);
559 if (offset==0xf1b242) return(0);
560 if (offset==0xF1B340) return(0);
561 if (offset==0xF1B342) return(0);
562 if (offset==0xF1BAD8) return(0);
563 if (offset==0xF1BADA) return(0);
564 if (offset==0xF1B040) return(0);
565 if (offset==0xF1B042) return(0);
566 if (offset==0xF1B0C0) return(0);
567 if (offset==0xF1B0C2) return(0);
568 if (offset==0xF1B140) return(0);
569 if (offset==0xF1B142) return(0);
570 if (offset==0xF1B1C0) return(0);
571 if (offset==0xF1B1C2) return(0);
574 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
576 offset -= DSP_WORK_RAM_BASE;
577 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
579 return GET16(dsp_ram_8, offset);
581 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
583 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
586 return data & 0xFFFF;
591 return JaguarReadWord(offset, who);
594 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
596 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
597 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
600 offset &= 0xFFFFFFFC;
601 /*if (offset == 0xF1BCF4)
603 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));
604 DSPDumpDisassembly();
606 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
608 offset -= DSP_WORK_RAM_BASE;
609 return GET32(dsp_ram_8, offset);
611 //NOTE: Didn't return DSP_ACCUM!!!
612 //Mebbe it's not 'spose to! Yes, it is!
613 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
618 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
619 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
620 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
622 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
623 return dsp_flags & 0xFFFFC1FF;
624 case 0x04: return dsp_matrix_control;
625 case 0x08: return dsp_pointer_to_matrix;
626 case 0x0C: return dsp_data_organization;
627 case 0x10: return dsp_pc;
628 case 0x14: return dsp_control;
629 case 0x18: return dsp_modulo;
630 case 0x1C: return dsp_remain;
632 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
634 // unaligned long read-- !!! FIX !!!
638 return JaguarReadLong(offset, who);
641 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
643 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
644 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
646 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
648 offset -= DSP_WORK_RAM_BASE;
649 dsp_ram_8[offset] = data;
650 //This is rather stupid! !!! FIX !!!
651 /* if (dsp_in_exec == 0)
653 m68k_end_timeslice();
654 gpu_releaseTimeslice();
658 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
660 uint32 reg = offset & 0x1C;
661 int bytenum = offset & 0x03;
663 if ((reg >= 0x1C) && (reg <= 0x1F))
664 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
667 //This looks funky. !!! FIX !!!
668 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
669 bytenum = 3 - bytenum; // convention motorola !!!
670 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
671 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
675 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
676 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
677 JaguarWriteByte(offset, data, who);
680 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
682 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
683 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
684 offset &= 0xFFFFFFFE;
685 /*if (offset == 0xF1BCF4)
687 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
689 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
690 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
692 /*if (offset == 0xF1B2F4)
694 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
696 offset -= DSP_WORK_RAM_BASE;
697 dsp_ram_8[offset] = data >> 8;
698 dsp_ram_8[offset+1] = data & 0xFF;
699 //This is rather stupid! !!! FIX !!!
700 /* if (dsp_in_exec == 0)
702 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
703 m68k_end_timeslice();
704 gpu_releaseTimeslice();
708 SET16(ram1, offset, data),
709 SET16(ram2, offset, data);
714 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
716 if ((offset & 0x1C) == 0x1C)
719 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
721 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
725 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
727 old_data = (old_data&0xffff0000)|(data&0xffff);
729 old_data = (old_data&0xffff)|((data&0xffff)<<16);
730 DSPWriteLong(offset & 0xffffffc, old_data, who);
735 JaguarWriteWord(offset, data, who);
738 //bool badWrite = false;
739 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
741 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
742 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
744 offset &= 0xFFFFFFFC;
745 /*if (offset == 0xF1BCF4)
747 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
749 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
750 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
752 /*if (offset == 0xF1BE2C)
754 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
756 offset -= DSP_WORK_RAM_BASE;
757 SET32(dsp_ram_8, offset, data);
760 SET32(ram1, offset, data),
761 SET32(ram2, offset, data);
766 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
774 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
776 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
777 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
779 dsp_flag_z = dsp_flags & 0x01;
780 dsp_flag_c = (dsp_flags >> 1) & 0x01;
781 dsp_flag_n = (dsp_flags >> 2) & 0x01;
782 DSPUpdateRegisterBanks();
783 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
784 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
785 /* if (IMASKCleared) // If IMASK was cleared,
788 WriteLog("DSP: Finished interrupt.\n");
790 DSPHandleIRQs(); // see if any other interrupts need servicing!
795 if (/*4-8, 16*/data & 0x101F0)
796 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
797 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
798 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
799 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
800 /*if (data & 0x00020) // CD BIOS DSP code...
802 //001AC1BA: movea.l #$1AC200, A0
803 //001AC1C0: move.l #$1AC68C, D0
806 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
807 uint32 j = 0xF1B97C;//0x1AC200;
808 while (j <= 0xF1BE08)//0x1AC68C)
811 j += dasmjag(JAGUAR_DSP, buffer, j);
812 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
813 WriteLog("\t%08X: %s\n", oldj, buffer);
820 dsp_matrix_control = data;
823 // According to JTRM, only lines 2-11 are addressable, the rest being
824 // hardwired to $F1Bxxx.
825 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
828 dsp_data_organization = data;
833 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
838 ctrl1[0] = ctrl2[0] = data;
845 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
847 bool wasRunning = DSP_RUNNING;
848 // uint32 dsp_was_running = DSP_RUNNING;
849 // Check for DSP -> CPU interrupt
853 WriteLog("DSP: DSP -> CPU interrupt\n");
856 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
857 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
859 JERRYSetPendingIRQ(IRQ2_DSP);
860 DSPReleaseTimeslice();
861 m68k_set_irq(7); // Set 68000 NMI...
865 // Check for CPU -> DSP interrupt
869 WriteLog("DSP: CPU -> DSP interrupt\n");
871 m68k_end_timeslice();
872 GPUReleaseTimeslice();
873 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
877 if (data & SINGLE_STEP)
879 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
882 // Protect writes to VERSION and the interrupt latches...
883 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
884 dsp_control = (dsp_control & mask) | (data & ~mask);
888 ctrl1[8] = ctrl2[8] = dsp_control;
892 // if dsp wasn't running but is now running
893 // execute a few cycles
894 //This is just plain wrong, wrong, WRONG!
895 #ifndef DSP_SINGLE_STEPPING
896 /* if (!dsp_was_running && DSP_RUNNING)
901 //This is WRONG! !!! FIX !!!
902 if (dsp_control & 0x18)
907 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
909 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
912 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
913 // !!! FIX !!! [DONE]
917 m68k_end_timeslice();
919 GPUReleaseTimeslice();
923 //DSPDumpDisassembly();
931 dsp_div_control = data;
933 // default: // unaligned long read
939 //We don't have to break this up like this! We CAN do 32 bit writes!
940 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
941 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
942 //if (offset > 0xF1FFFF)
944 JaguarWriteLong(offset, data, who);
948 // Update the DSP register file pointers depending on REGPAGE bit
950 void DSPUpdateRegisterBanks(void)
952 int bank = (dsp_flags & REGPAGE);
954 if (dsp_flags & IMASK)
955 bank = 0; // IMASK forces main bank to be bank 0
958 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
960 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
964 // Check for and handle any asserted DSP IRQs
966 void DSPHandleIRQs(void)
968 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
971 // Get the active interrupt bits (latches) & interrupt mask (enables)
972 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
973 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
975 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
978 if (!bits) // Bail if nothing is enabled
981 int which = 0; // Determine which interrupt
996 WriteLog("DSP: Generating interrupt #%i...", which);
999 //if (which == 0) doDSPDis = true;
1001 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1002 // directly into the pipeline, it has the side effect of ensuring that the
1003 // instruction interrupted also gets to do its writeback. We simulate that
1005 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1007 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1008 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1010 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1011 scoreboard[pipeline[plPtrWrite].operand2] = false;
1013 //This should be execute (or should it?--not sure now!)
1014 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1015 //and what just executed is now in the Write position...). So why didn't it do the
1016 //writeback into register 0?
1017 #ifdef DSP_DEBUG_IRQ
1018 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1019 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]);
1020 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]);
1021 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]);
1023 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1025 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1027 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1028 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1031 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1032 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1033 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1034 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1036 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1040 #ifndef NEW_SCOREBOARD
1041 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1042 scoreboard[pipeline[plPtrWrite].operand2] = false;
1044 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1045 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1046 if (scoreboard[pipeline[plPtrWrite].operand2])
1047 scoreboard[pipeline[plPtrWrite].operand2]--;
1054 ctrl2[4] = dsp_flags;
1057 DSPUpdateRegisterBanks();
1058 #ifdef DSP_DEBUG_IRQ
1059 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1060 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]);
1063 // subqt #4,r31 ; pre-decrement stack pointer
1064 // move pc,r30 ; address of interrupted code
1065 // store r30,(r31) ; store return address
1072 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1073 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1074 //It missed the place that it was supposed to come back to, so this is WRONG!
1076 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1078 // R -> baz (<- PC points here)
1079 // E -> bar (when it should point here!)
1082 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1083 // which means (assuming they're all 2 bytes long) that the code below will come back on
1084 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1085 // instruction stream...
1087 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1088 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1091 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1095 // movei #service_address,r30 ; pointer to ISR entry
1096 // jump (r30) ; jump to ISR
1098 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1101 ctrl2[0] = regs2[30] = dsp_pc;
1108 // Non-pipelined version...
1110 void DSPHandleIRQsNP(void)
1114 memcpy(dsp_ram_8, ram1, 0x2000);
1115 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1116 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1119 dsp_remain = ctrl1[2];
1120 dsp_modulo = ctrl1[3];
1121 dsp_flags = ctrl1[4];
1122 dsp_matrix_control = ctrl1[5];
1123 dsp_pointer_to_matrix = ctrl1[6];
1124 dsp_data_organization = ctrl1[7];
1125 dsp_control = ctrl1[8];
1126 dsp_div_control = ctrl1[9];
1127 IMASKCleared = ctrl1[10];
1128 dsp_flag_z = ctrl1[11];
1129 dsp_flag_n = ctrl1[12];
1130 dsp_flag_c = ctrl1[13];
1131 DSPUpdateRegisterBanks();
1134 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1137 // Get the active interrupt bits (latches) & interrupt mask (enables)
1138 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1139 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1141 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1144 if (!bits) // Bail if nothing is enabled
1147 int which = 0; // Determine which interrupt
1161 #ifdef DSP_DEBUG_IRQ
1162 WriteLog("DSP: Generating interrupt #%i...", which);
1168 ctrl1[4] = dsp_flags;
1171 DSPUpdateRegisterBanks();
1172 #ifdef DSP_DEBUG_IRQ
1173 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1176 // subqt #4,r31 ; pre-decrement stack pointer
1177 // move pc,r30 ; address of interrupted code
1178 // store r30,(r31) ; store return address
1185 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1188 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1192 // movei #service_address,r30 ; pointer to ISR entry
1193 // jump (r30) ; jump to ISR
1195 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1198 ctrl1[0] = regs1[30] = dsp_pc;
1204 // Set the specified DSP IRQ line to a given state
1206 void DSPSetIRQLine(int irqline, int state)
1208 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1209 uint32 mask = INT_LAT0 << irqline;
1210 dsp_control &= ~mask; // Clear the latch bit
1213 ctrl1[8] = ctrl2[8] = dsp_control;
1219 dsp_control |= mask; // Set the latch bit
1223 ctrl1[8] = ctrl2[8] = dsp_control;
1229 // Not sure if this is correct behavior, but according to JTRM,
1230 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1231 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1232 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1237 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1238 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1239 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1241 dsp_build_branch_condition_table();
1247 dsp_pc = 0x00F1B000;
1248 dsp_acc = 0x00000000;
1249 dsp_remain = 0x00000000;
1250 dsp_modulo = 0xFFFFFFFF;
1251 dsp_flags = 0x00040000;
1252 dsp_matrix_control = 0x00000000;
1253 dsp_pointer_to_matrix = 0x00000000;
1254 dsp_data_organization = 0xFFFFFFFF;
1255 dsp_control = 0x00002000; // Report DSP version 2
1256 dsp_div_control = 0x00000000;
1259 dsp_reg = dsp_reg_bank_0;
1260 dsp_alternate_reg = dsp_reg_bank_1;
1262 for(int i=0; i<32; i++)
1263 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1266 IMASKCleared = false;
1269 memset(dsp_ram_8, 0xFF, 0x2000);
1272 void DSPDumpDisassembly(void)
1276 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1277 uint32 j = 0xF1B000;
1278 while (j <= 0xF1CFFF)
1281 j += dasmjag(JAGUAR_DSP, buffer, j);
1282 WriteLog("\t%08X: %s\n", oldj, buffer);
1286 void DSPDumpRegisters(void)
1288 //Shoud add modulus, etc to dump here...
1289 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1290 WriteLog("\nRegisters bank 0\n");
1291 for(int j=0; j<8; j++)
1293 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1294 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1295 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1296 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1297 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1299 WriteLog("Registers bank 1\n");
1300 for(int j=0; j<8; j++)
1302 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1303 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1304 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1305 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1306 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1313 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1314 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1316 // get the active interrupt bits
1317 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1318 // get the interrupt mask
1319 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1321 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1322 WriteLog("\nRegisters bank 0\n");
1323 for(int j=0; j<8; j++)
1325 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1326 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1327 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1328 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1329 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1331 WriteLog("\nRegisters bank 1\n");
1334 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1335 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1336 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1337 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1338 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1342 static char buffer[512];
1343 j = DSP_WORK_RAM_BASE;
1344 while (j <= 0xF1BFFF)
1347 j += dasmjag(JAGUAR_DSP, buffer, j);
1348 WriteLog("\t%08X: %s\n", oldj, buffer);
1351 WriteLog("DSP opcodes use:\n");
1354 if (dsp_opcode_use[i])
1355 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1358 // memory_free(dsp_ram_8);
1359 // memory_free(dsp_reg_bank_0);
1360 // memory_free(dsp_reg_bank_1);
1366 // DSP comparison core...
1369 static uint16 lastExec;
1370 void DSPExecComp(int32 cycles)
1372 while (cycles > 0 && DSP_RUNNING)
1374 // Load up vars for non-pipelined core
1375 memcpy(dsp_ram_8, ram1, 0x2000);
1376 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1377 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1380 dsp_remain = ctrl1[2];
1381 dsp_modulo = ctrl1[3];
1382 dsp_flags = ctrl1[4];
1383 dsp_matrix_control = ctrl1[5];
1384 dsp_pointer_to_matrix = ctrl1[6];
1385 dsp_data_organization = ctrl1[7];
1386 dsp_control = ctrl1[8];
1387 dsp_div_control = ctrl1[9];
1388 IMASKCleared = ctrl1[10];
1389 dsp_flag_z = ctrl1[11];
1390 dsp_flag_n = ctrl1[12];
1391 dsp_flag_c = ctrl1[13];
1392 DSPUpdateRegisterBanks();
1394 // Decrement cycles based on non-pipelined core...
1395 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1396 cycles -= dsp_opcode_cycles[instr1 >> 10];
1398 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1399 DSPExec(1); // Do *one* instruction
1402 memcpy(ram1, dsp_ram_8, 0x2000);
1403 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1404 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1407 ctrl1[2] = dsp_remain;
1408 ctrl1[3] = dsp_modulo;
1409 ctrl1[4] = dsp_flags;
1410 ctrl1[5] = dsp_matrix_control;
1411 ctrl1[6] = dsp_pointer_to_matrix;
1412 ctrl1[7] = dsp_data_organization;
1413 ctrl1[8] = dsp_control;
1414 ctrl1[9] = dsp_div_control;
1415 ctrl1[10] = IMASKCleared;
1416 ctrl1[11] = dsp_flag_z;
1417 ctrl1[12] = dsp_flag_n;
1418 ctrl1[13] = dsp_flag_c;
1420 // Load up vars for pipelined core
1421 memcpy(dsp_ram_8, ram2, 0x2000);
1422 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1423 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1426 dsp_remain = ctrl2[2];
1427 dsp_modulo = ctrl2[3];
1428 dsp_flags = ctrl2[4];
1429 dsp_matrix_control = ctrl2[5];
1430 dsp_pointer_to_matrix = ctrl2[6];
1431 dsp_data_organization = ctrl2[7];
1432 dsp_control = ctrl2[8];
1433 dsp_div_control = ctrl2[9];
1434 IMASKCleared = ctrl2[10];
1435 dsp_flag_z = ctrl2[11];
1436 dsp_flag_n = ctrl2[12];
1437 dsp_flag_c = ctrl2[13];
1438 DSPUpdateRegisterBanks();
1440 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1441 DSPExecP2(1); // Do *one* instruction
1444 memcpy(ram2, dsp_ram_8, 0x2000);
1445 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1446 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1449 ctrl2[2] = dsp_remain;
1450 ctrl2[3] = dsp_modulo;
1451 ctrl2[4] = dsp_flags;
1452 ctrl2[5] = dsp_matrix_control;
1453 ctrl2[6] = dsp_pointer_to_matrix;
1454 ctrl2[7] = dsp_data_organization;
1455 ctrl2[8] = dsp_control;
1456 ctrl2[9] = dsp_div_control;
1457 ctrl2[10] = IMASKCleared;
1458 ctrl2[11] = dsp_flag_z;
1459 ctrl2[12] = dsp_flag_n;
1460 ctrl2[13] = dsp_flag_c;
1462 if (instr1 != lastExec)
1464 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1466 // uint32 ppc = ctrl2[0] - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrWrite].opcode == 38 ? 6 : (pipeline[plPtrWrite].opcode == PIPELINE_STALL ? 0 : 2));
1467 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1468 // if (ctrl1[0] < ppc) // P ran ahead of NP
1469 //How to test this crap???
1472 DSPExecP2(1); // Do one more instruction
1475 memcpy(ram2, dsp_ram_8, 0x2000);
1476 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1477 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1480 ctrl2[2] = dsp_remain;
1481 ctrl2[3] = dsp_modulo;
1482 ctrl2[4] = dsp_flags;
1483 ctrl2[5] = dsp_matrix_control;
1484 ctrl2[6] = dsp_pointer_to_matrix;
1485 ctrl2[7] = dsp_data_organization;
1486 ctrl2[8] = dsp_control;
1487 ctrl2[9] = dsp_div_control;
1488 ctrl2[10] = IMASKCleared;
1489 ctrl2[11] = dsp_flag_z;
1490 ctrl2[12] = dsp_flag_n;
1491 ctrl2[13] = dsp_flag_c;
1493 // else // NP ran ahead of P
1494 if (instr1 != lastExec) // Must be the other way...
1497 // Load up vars for non-pipelined core
1498 memcpy(dsp_ram_8, ram1, 0x2000);
1499 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1500 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1503 dsp_remain = ctrl1[2];
1504 dsp_modulo = ctrl1[3];
1505 dsp_flags = ctrl1[4];
1506 dsp_matrix_control = ctrl1[5];
1507 dsp_pointer_to_matrix = ctrl1[6];
1508 dsp_data_organization = ctrl1[7];
1509 dsp_control = ctrl1[8];
1510 dsp_div_control = ctrl1[9];
1511 IMASKCleared = ctrl1[10];
1512 dsp_flag_z = ctrl1[11];
1513 dsp_flag_n = ctrl1[12];
1514 dsp_flag_c = ctrl1[13];
1515 DSPUpdateRegisterBanks();
1517 for(int k=0; k<2; k++)
1519 // Decrement cycles based on non-pipelined core...
1520 instr1 = DSPReadWord(dsp_pc, DSP);
1521 cycles -= dsp_opcode_cycles[instr1 >> 10];
1523 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1524 DSPExec(1); // Do *one* instruction
1528 memcpy(ram1, dsp_ram_8, 0x2000);
1529 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1530 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1533 ctrl1[2] = dsp_remain;
1534 ctrl1[3] = dsp_modulo;
1535 ctrl1[4] = dsp_flags;
1536 ctrl1[5] = dsp_matrix_control;
1537 ctrl1[6] = dsp_pointer_to_matrix;
1538 ctrl1[7] = dsp_data_organization;
1539 ctrl1[8] = dsp_control;
1540 ctrl1[9] = dsp_div_control;
1541 ctrl1[10] = IMASKCleared;
1542 ctrl1[11] = dsp_flag_z;
1543 ctrl1[12] = dsp_flag_n;
1544 ctrl1[13] = dsp_flag_c;
1548 if (instr1 != lastExec)
1550 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1552 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1553 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1566 // DSP execution core
1568 //static bool R20Set = false, tripwire = false;
1569 //static uint32 pcQueue[32], ptrPCQ = 0;
1570 void DSPExec(int32 cycles)
1572 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1573 dsp_check_if_i2s_interrupt_needed();*/
1575 #ifdef DSP_SINGLE_STEPPING
1576 if (dsp_control & 0x18)
1579 dsp_control &= ~0x10;
1582 //There is *no* good reason to do this here!
1584 dsp_releaseTimeSlice_flag = 0;
1587 while (cycles > 0 && DSP_RUNNING)
1589 /*extern uint32 totalFrames;
1590 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1591 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1592 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1594 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1597 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1599 if (dsp_pc == 0xF1B092)
1600 doDSPDis = false;//*/
1601 /*if (dsp_pc == 0xF1B140)
1602 doDSPDis = true;//*/
1604 if (IMASKCleared) // If IMASK was cleared,
1606 #ifdef DSP_DEBUG_IRQ
1607 WriteLog("DSP: Finished interrupt.\n");
1609 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1610 IMASKCleared = false;
1615 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1616 for(int i=0; i<80; i+=4)
1617 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1620 /*if (dsp_pc == 0xF1B55E)
1622 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1624 /*if (dsp_pc == 0xF1B7D2) // Start here???
1626 pcQueue[ptrPCQ++] = dsp_pc;
1628 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1629 uint32 index = opcode >> 10;
1630 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1631 dsp_opcode_second_parameter = opcode & 0x1F;
1633 dsp_opcode[index]();
1634 dsp_opcode_use[index]++;
1635 cycles -= dsp_opcode_cycles[index];
1636 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1638 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1641 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1643 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1645 DSPDumpDisassembly();
1648 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1651 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1654 WriteLog("\nBacktrace:\n");
1655 for(int i=0; i<32; i++)
1657 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1658 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1668 // DSP opcode handlers
1671 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1672 // can cause trouble because an interrupt can occur *before* the instruction following the
1673 // jump can execute... !!! FIX !!!
1674 static void dsp_opcode_jump(void)
1677 const char * condition[32] =
1678 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1679 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1680 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1681 "???", "???", "???", "F" };
1683 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);
1686 /* dsp_flag_c=dsp_flag_c?1:0;
1687 dsp_flag_z=dsp_flag_z?1:0;
1688 dsp_flag_n=dsp_flag_n?1:0;*/
1689 // KLUDGE: Used by BRANCH_CONDITION
1690 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1692 if (BRANCH_CONDITION(IMM_2))
1696 WriteLog("Branched!\n");
1698 uint32 delayed_pc = RM;
1700 dsp_pc = delayed_pc;
1705 WriteLog("Branch NOT taken.\n");
1709 static void dsp_opcode_jr(void)
1712 const char * condition[32] =
1713 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1714 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1715 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1716 "???", "???", "???", "F" };
1718 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);
1721 /* dsp_flag_c=dsp_flag_c?1:0;
1722 dsp_flag_z=dsp_flag_z?1:0;
1723 dsp_flag_n=dsp_flag_n?1:0;*/
1724 // KLUDGE: Used by BRANCH_CONDITION
1725 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1727 if (BRANCH_CONDITION(IMM_2))
1731 WriteLog("Branched!\n");
1733 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1734 int32 delayed_pc = dsp_pc + (offset * 2);
1736 dsp_pc = delayed_pc;
1741 WriteLog("Branch NOT taken.\n");
1745 static void dsp_opcode_add(void)
1749 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);
1751 uint32 res = RN + RM;
1752 SET_ZNC_ADD(RN, RM, res);
1756 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);
1760 static void dsp_opcode_addc(void)
1764 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);
1766 uint32 res = RN + RM + dsp_flag_c;
1767 uint32 carry = dsp_flag_c;
1768 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1769 SET_ZNC_ADD(RN + carry, RM, res);
1770 // SET_ZNC_ADD(RN, RM + carry, res);
1774 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);
1778 static void dsp_opcode_addq(void)
1782 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);
1784 uint32 r1 = dsp_convert_zero[IMM_1];
1785 uint32 res = RN + r1;
1786 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1790 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1794 static void dsp_opcode_sub(void)
1798 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);
1800 uint32 res = RN - RM;
1801 SET_ZNC_SUB(RN, RM, res);
1805 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1809 static void dsp_opcode_subc(void)
1813 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);
1815 uint32 res = RN - RM - dsp_flag_c;
1816 uint32 borrow = dsp_flag_c;
1817 SET_ZNC_SUB(RN - borrow, RM, res);
1821 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);
1825 static void dsp_opcode_subq(void)
1829 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);
1831 uint32 r1 = dsp_convert_zero[IMM_1];
1832 uint32 res = RN - r1;
1833 SET_ZNC_SUB(RN, r1, res);
1837 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1841 static void dsp_opcode_cmp(void)
1845 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);
1847 uint32 res = RN - RM;
1848 SET_ZNC_SUB(RN, RM, res);
1851 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1855 static void dsp_opcode_cmpq(void)
1857 static int32 sqtable[32] =
1858 { 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 };
1861 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);
1863 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1864 uint32 res = RN - r1;
1865 SET_ZNC_SUB(RN, r1, res);
1868 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1872 static void dsp_opcode_and(void)
1876 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);
1882 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1886 static void dsp_opcode_or(void)
1890 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);
1896 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);
1900 static void dsp_opcode_xor(void)
1904 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);
1910 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);
1914 static void dsp_opcode_not(void)
1918 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1924 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1928 static void dsp_opcode_move_pc(void)
1933 static void dsp_opcode_store_r14_indexed(void)
1935 #ifdef DSP_DIS_STORE14I
1937 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));
1939 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1942 static void dsp_opcode_store_r15_indexed(void)
1944 #ifdef DSP_DIS_STORE15I
1946 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));
1948 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1951 static void dsp_opcode_load_r14_ri(void)
1953 #ifdef DSP_DIS_LOAD14R
1955 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);
1957 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1958 #ifdef DSP_DIS_LOAD14R
1960 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1964 static void dsp_opcode_load_r15_ri(void)
1966 #ifdef DSP_DIS_LOAD15R
1968 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);
1970 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1971 #ifdef DSP_DIS_LOAD15R
1973 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1977 static void dsp_opcode_store_r14_ri(void)
1979 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1982 static void dsp_opcode_store_r15_ri(void)
1984 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1987 static void dsp_opcode_nop(void)
1991 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1995 static void dsp_opcode_storeb(void)
1997 #ifdef DSP_DIS_STOREB
1999 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);
2001 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2002 DSPWriteLong(RM, RN & 0xFF, DSP);
2004 JaguarWriteByte(RM, RN, DSP);
2007 static void dsp_opcode_storew(void)
2009 #ifdef DSP_DIS_STOREW
2011 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);
2013 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2014 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2016 JaguarWriteWord(RM, RN, DSP);
2019 static void dsp_opcode_store(void)
2021 #ifdef DSP_DIS_STORE
2023 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);
2025 DSPWriteLong(RM, RN, DSP);
2028 static void dsp_opcode_loadb(void)
2030 #ifdef DSP_DIS_LOADB
2032 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);
2034 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2035 RN = DSPReadLong(RM, DSP) & 0xFF;
2037 RN = JaguarReadByte(RM, DSP);
2038 #ifdef DSP_DIS_LOADB
2040 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2044 static void dsp_opcode_loadw(void)
2046 #ifdef DSP_DIS_LOADW
2048 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);
2050 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2051 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2053 RN = JaguarReadWord(RM, DSP);
2054 #ifdef DSP_DIS_LOADW
2056 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2060 static void dsp_opcode_load(void)
2064 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);
2066 RN = DSPReadLong(RM, DSP);
2069 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2073 static void dsp_opcode_load_r14_indexed(void)
2075 #ifdef DSP_DIS_LOAD14I
2077 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);
2079 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2080 #ifdef DSP_DIS_LOAD14I
2082 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2086 static void dsp_opcode_load_r15_indexed(void)
2088 #ifdef DSP_DIS_LOAD15I
2090 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);
2092 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2093 #ifdef DSP_DIS_LOAD15I
2095 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2099 static void dsp_opcode_movei(void)
2101 #ifdef DSP_DIS_MOVEI
2103 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);
2105 // This instruction is followed by 32-bit value in LSW / MSW format...
2106 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2108 #ifdef DSP_DIS_MOVEI
2110 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2114 static void dsp_opcode_moveta(void)
2116 #ifdef DSP_DIS_MOVETA
2118 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);
2121 #ifdef DSP_DIS_MOVETA
2123 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);
2127 static void dsp_opcode_movefa(void)
2129 #ifdef DSP_DIS_MOVEFA
2131 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);
2134 #ifdef DSP_DIS_MOVEFA
2136 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);
2140 static void dsp_opcode_move(void)
2144 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);
2149 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);
2153 static void dsp_opcode_moveq(void)
2155 #ifdef DSP_DIS_MOVEQ
2157 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);
2160 #ifdef DSP_DIS_MOVEQ
2162 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2166 static void dsp_opcode_resmac(void)
2168 #ifdef DSP_DIS_RESMAC
2170 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));
2172 RN = (uint32)dsp_acc;
2173 #ifdef DSP_DIS_RESMAC
2175 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2179 static void dsp_opcode_imult(void)
2181 #ifdef DSP_DIS_IMULT
2183 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);
2185 RN = (int16)RN * (int16)RM;
2187 #ifdef DSP_DIS_IMULT
2189 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);
2193 static void dsp_opcode_mult(void)
2197 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);
2199 RN = (uint16)RM * (uint16)RN;
2203 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2207 static void dsp_opcode_bclr(void)
2211 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);
2213 uint32 res = RN & ~(1 << IMM_1);
2218 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2222 static void dsp_opcode_btst(void)
2226 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);
2228 dsp_flag_z = (~RN >> IMM_1) & 1;
2231 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2235 static void dsp_opcode_bset(void)
2239 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);
2241 uint32 res = RN | (1 << IMM_1);
2246 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2250 static void dsp_opcode_subqt(void)
2252 #ifdef DSP_DIS_SUBQT
2254 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);
2256 RN -= dsp_convert_zero[IMM_1];
2257 #ifdef DSP_DIS_SUBQT
2259 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2263 static void dsp_opcode_addqt(void)
2265 #ifdef DSP_DIS_ADDQT
2267 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);
2269 RN += dsp_convert_zero[IMM_1];
2270 #ifdef DSP_DIS_ADDQT
2272 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2276 static void dsp_opcode_imacn(void)
2278 #ifdef DSP_DIS_IMACN
2280 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);
2282 int32 res = (int16)RM * (int16)RN;
2283 dsp_acc += (int64)res;
2284 //Should we AND the result to fit into 40 bits here???
2285 #ifdef DSP_DIS_IMACN
2287 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));
2291 static void dsp_opcode_mtoi(void)
2293 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2297 static void dsp_opcode_normi(void)
2304 while ((_Rm & 0xffc00000) == 0)
2309 while ((_Rm & 0xff800000) != 0)
2319 static void dsp_opcode_mmult(void)
2321 int count = dsp_matrix_control&0x0f;
2322 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2326 if (!(dsp_matrix_control & 0x10))
2328 for (int i = 0; i < count; i++)
2332 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2334 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2335 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2342 for (int i = 0; i < count; i++)
2346 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2348 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2349 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2354 RN = res = (int32)accum;
2356 //NOTE: The flags are set based upon the last add/multiply done...
2360 static void dsp_opcode_abs(void)
2364 WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2369 if (_Rn == 0x80000000)
2373 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2374 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2379 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2383 static void dsp_opcode_div(void)
2390 if (dsp_div_control & 1)
2392 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2393 if (dsp_remain&0x80000000)
2395 RN = (((uint64)_Rn) << 16) / _Rm;
2399 dsp_remain = _Rn % _Rm;
2400 if (dsp_remain&0x80000000)
2409 static void dsp_opcode_imultn(void)
2411 #ifdef DSP_DIS_IMULTN
2413 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);
2415 // This is OK, since this multiply won't overflow 32 bits...
2416 int32 res = (int32)((int16)RN * (int16)RM);
2417 dsp_acc = (int64)res;
2419 #ifdef DSP_DIS_IMULTN
2421 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));
2425 static void dsp_opcode_neg(void)
2429 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);
2432 SET_ZNC_SUB(0, RN, res);
2436 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2440 static void dsp_opcode_shlq(void)
2444 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);
2446 int32 r1 = 32 - IMM_1;
2447 uint32 res = RN << r1;
2448 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2452 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2456 static void dsp_opcode_shrq(void)
2460 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);
2462 int32 r1 = dsp_convert_zero[IMM_1];
2463 uint32 res = RN >> r1;
2464 SET_ZN(res); dsp_flag_c = RN & 1;
2468 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2472 static void dsp_opcode_ror(void)
2476 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);
2478 uint32 r1 = RM & 0x1F;
2479 uint32 res = (RN >> r1) | (RN << (32 - r1));
2480 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2484 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);
2488 static void dsp_opcode_rorq(void)
2492 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);
2494 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2496 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2498 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2501 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2505 static void dsp_opcode_sha(void)
2507 int32 sRm=(int32)RM;
2513 if (shift>=32) shift=32;
2514 dsp_flag_c=(_Rn&0x80000000)>>31;
2524 if (shift>=32) shift=32;
2528 _Rn=((int32)_Rn)>>1;
2536 static void dsp_opcode_sharq(void)
2538 #ifdef DSP_DIS_SHARQ
2540 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);
2542 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2543 SET_ZN(res); dsp_flag_c = RN & 0x01;
2545 #ifdef DSP_DIS_SHARQ
2547 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2551 static void dsp_opcode_sh(void)
2553 int32 sRm=(int32)RM;
2558 uint32 shift=(-sRm);
2559 if (shift>=32) shift=32;
2560 dsp_flag_c=(_Rn&0x80000000)>>31;
2570 if (shift>=32) shift=32;
2582 void dsp_opcode_addqmod(void)
2584 #ifdef DSP_DIS_ADDQMOD
2586 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);
2588 uint32 r1 = dsp_convert_zero[IMM_1];
2590 uint32 res = r2 + r1;
2591 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2593 SET_ZNC_ADD(r2, r1, res);
2594 #ifdef DSP_DIS_ADDQMOD
2596 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2600 void dsp_opcode_subqmod(void)
2602 uint32 r1 = dsp_convert_zero[IMM_1];
2604 uint32 res = r2 - r1;
2605 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2608 SET_ZNC_SUB(r2, r1, res);
2611 void dsp_opcode_mirror(void)
2614 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2618 void dsp_opcode_sat32s(void)
2620 int32 r2 = (uint32)RN;
2621 int32 temp = dsp_acc >> 32;
2622 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2627 void dsp_opcode_sat16s(void)
2630 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2636 // New pipelined DSP core
2639 static void DSP_abs(void);
2640 static void DSP_add(void);
2641 static void DSP_addc(void);
2642 static void DSP_addq(void);
2643 static void DSP_addqmod(void);
2644 static void DSP_addqt(void);
2645 static void DSP_and(void);
2646 static void DSP_bclr(void);
2647 static void DSP_bset(void);
2648 static void DSP_btst(void);
2649 static void DSP_cmp(void);
2650 static void DSP_cmpq(void);
2651 static void DSP_div(void);
2652 static void DSP_imacn(void);
2653 static void DSP_imult(void);
2654 static void DSP_imultn(void);
2655 static void DSP_illegal(void);
2656 static void DSP_jr(void);
2657 static void DSP_jump(void);
2658 static void DSP_load(void);
2659 static void DSP_loadb(void);
2660 static void DSP_loadw(void);
2661 static void DSP_load_r14_i(void);
2662 static void DSP_load_r14_r(void);
2663 static void DSP_load_r15_i(void);
2664 static void DSP_load_r15_r(void);
2665 static void DSP_mirror(void);
2666 static void DSP_mmult(void);
2667 static void DSP_move(void);
2668 static void DSP_movefa(void);
2669 static void DSP_movei(void);
2670 static void DSP_movepc(void);
2671 static void DSP_moveq(void);
2672 static void DSP_moveta(void);
2673 static void DSP_mtoi(void);
2674 static void DSP_mult(void);
2675 static void DSP_neg(void);
2676 static void DSP_nop(void);
2677 static void DSP_normi(void);
2678 static void DSP_not(void);
2679 static void DSP_or(void);
2680 static void DSP_resmac(void);
2681 static void DSP_ror(void);
2682 static void DSP_rorq(void);
2683 static void DSP_sat16s(void);
2684 static void DSP_sat32s(void);
2685 static void DSP_sh(void);
2686 static void DSP_sha(void);
2687 static void DSP_sharq(void);
2688 static void DSP_shlq(void);
2689 static void DSP_shrq(void);
2690 static void DSP_store(void);
2691 static void DSP_storeb(void);
2692 static void DSP_storew(void);
2693 static void DSP_store_r14_i(void);
2694 static void DSP_store_r14_r(void);
2695 static void DSP_store_r15_i(void);
2696 static void DSP_store_r15_r(void);
2697 static void DSP_sub(void);
2698 static void DSP_subc(void);
2699 static void DSP_subq(void);
2700 static void DSP_subqmod(void);
2701 static void DSP_subqt(void);
2702 static void DSP_xor(void);
2704 void (* DSPOpcode[64])() =
2706 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2707 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2708 DSP_neg, DSP_and, DSP_or, DSP_xor,
2709 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2711 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2712 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2713 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2714 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2716 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2717 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2718 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2719 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2721 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2722 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2723 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2724 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2727 bool readAffected[64][2] =
2729 { true, true}, { true, true}, {false, true}, {false, true},
2730 { true, true}, { true, true}, {false, true}, {false, true},
2731 {false, true}, { true, true}, { true, true}, { true, true},
2732 {false, true}, {false, true}, {false, true}, {false, true},
2734 { true, true}, { true, true}, { true, true}, {false, true},
2735 { true, true}, { true, true}, {false, true}, { true, true},
2736 {false, true}, {false, true}, { true, true}, {false, true},
2737 { true, true}, {false, true}, { true, true}, {false, true},
2739 {false, true}, {false, true}, { true, false}, {false, false},
2740 { true, false}, {false, false}, {false, false}, { true, false},
2741 { true, false}, { true, false}, {false, true}, { true, false},
2742 { true, false}, { true, true}, { true, true}, { true, true},
2744 {false, true}, { true, true}, { true, true}, {false, true},
2745 { true, false}, { true, false}, { true, true}, { true, false},
2746 { true, false}, {false, false}, { true, false}, { true, false},
2747 { true, true}, { true, true}, {false, false}, {false, true}
2750 bool isLoadStore[65] =
2752 false, false, false, false, false, false, false, false,
2753 false, false, false, false, false, false, false, false,
2755 false, false, false, false, false, false, false, false,
2756 false, false, false, false, false, false, false, false,
2758 false, false, false, false, false, false, false, true,
2759 true, true, false, true, true, true, true, true,
2761 false, true, true, false, false, false, false, false,
2762 false, false, true, true, true, true, false, false, false
2765 void FlushDSPPipeline(void)
2767 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2769 for(int i=0; i<4; i++)
2770 pipeline[i].opcode = PIPELINE_STALL;
2772 for(int i=0; i<32; i++)
2777 // New pipelined DSP execution core
2779 /*void DSPExecP(int32 cycles)
2781 // bool inhibitFetch = false;
2783 dsp_releaseTimeSlice_flag = 0;
2786 while (cycles > 0 && DSP_RUNNING)
2788 WriteLog("DSPExecP: Pipeline status...\n");
2789 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);
2790 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);
2791 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);
2792 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);
2793 WriteLog(" --> Scoreboard: ");
2794 for(int i=0; i<32; i++)
2795 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2797 // Stage 1: Instruction fetch
2798 // if (!inhibitFetch)
2800 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2801 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2802 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2803 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2804 if (pipeline[plPtrFetch].opcode == 38)
2805 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2806 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2809 // inhibitFetch = false;
2810 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2812 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2813 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);
2814 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);
2815 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);
2816 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);
2817 // Stage 2: Read registers
2818 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2819 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2820 if (scoreboard[pipeline[plPtrRead].operand2])
2821 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2822 // We have a hit in the scoreboard, so we have to stall the pipeline...
2824 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2825 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2826 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2827 pipeline[plPtrFetch] = pipeline[plPtrRead];
2828 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2832 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2833 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2834 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2836 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2837 // Shouldn't we be more selective with the register scoreboarding?
2838 // Yes, we should. !!! FIX !!!
2839 scoreboard[pipeline[plPtrRead].operand2] = true;
2840 //Advance PC here??? Yes.
2841 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2842 //This is a mangling of the pipeline stages, but what else to do???
2843 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2846 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2847 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);
2848 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);
2849 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);
2850 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);
2852 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2854 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2855 DSPOpcode[pipeline[plPtrExec].opcode]();
2856 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2857 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2862 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2863 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);
2864 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);
2865 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);
2866 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);
2867 // Stage 4: Write back register
2868 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2870 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2871 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2873 scoreboard[pipeline[plPtrWrite].operand1]
2874 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2877 // Push instructions through the pipeline...
2878 plPtrFetch = (++plPtrFetch) & 0x03;
2879 plPtrRead = (++plPtrRead) & 0x03;
2880 plPtrExec = (++plPtrExec) & 0x03;
2881 plPtrWrite = (++plPtrWrite) & 0x03;
2888 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2890 // Should be fixed now. Another problem is figuring how to do the sequence following
2891 // a branch followed with the JR & JUMP instructions...
2893 // There are two conflicting problems:
2896 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2897 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2898 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2899 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2900 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2901 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2902 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2903 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2904 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2905 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2906 DSP: Finished interrupt.
2907 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2908 ; bank 0 (where is was prepared)!
2909 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2910 F1B252: NOP [NCZ:001]
2913 // The other is when you see this at the end of an IRQ:
2916 JUMP T, (R29) ; R29 = Previous stack + 2
2917 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2919 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2920 ; 1) The STORE goes through the pipeline and is executed/written back
2921 ; 2) The pipeline is flushed
2922 ; 3) The DSP_PC is set to the new address
2923 ; 4) Execution resumes
2925 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2926 ; bank 0 instead of the current bank 1 and so goes astray!
2929 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2930 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2934 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2935 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2936 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2937 If it were done properly, the STORE write back would occur *after* (well, technically,
2938 during) the execution of the the JUMP that follows it.
2942 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2943 F1B08A: NOP [NCZ:001]
2945 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2948 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2951 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2952 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2953 F1B08A: NOP [NCZ:001]
2955 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2958 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2959 DSP: CPU -> DSP interrupt
2960 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2961 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2963 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2966 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2967 F1B006: NOP [NCZ:001]
2969 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2972 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2973 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2976 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2977 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2980 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2981 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2984 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2985 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
2988 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
2991 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
2994 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
2995 F1B0FE: NOP [NCZ:000]
2997 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3000 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3003 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3004 F1B138: NOP [NCZ:000]
3006 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3009 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3010 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3011 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3014 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3015 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3018 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3019 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3020 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3022 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3023 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3026 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3027 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3028 DSP: Finished interrupt.
3029 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3031 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3034 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3035 F1B016: NOP [NCZ:001]
3037 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3040 uint32 pcQueue1[0x400];
3042 static uint32 prevR1;
3043 //Let's try a 3 stage pipeline....
3044 //Looks like 3 stage is correct, otherwise bad things happen...
3045 void DSPExecP2(int32 cycles)
3047 dsp_releaseTimeSlice_flag = 0;
3050 while (cycles > 0 && DSP_RUNNING)
3052 /*extern uint32 totalFrames;
3053 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3054 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3055 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3057 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3060 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3062 if (dsp_pc == 0xF1B092)
3063 doDSPDis = false;//*/
3064 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3065 doDSPDis = true;//*/
3066 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3067 doDSPDis = true;//*/
3068 /*if (dsp_pc == 0xF1B0A0)
3069 doDSPDis = true;//*/
3070 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3071 doDSPDis = true;//*/
3072 //Two parter... (not sure how to write this)
3073 //if (dsp_pc == 0xF1B0D2)
3074 // prevR1 = dsp_reg[1];
3076 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3077 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3080 pcQueue1[pcQPtr1++] = dsp_pc;
3083 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3085 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3090 for(int i=0; i<0x400; i++)
3092 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3093 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3097 if (IMASKCleared) // If IMASK was cleared,
3099 #ifdef DSP_DEBUG_IRQ
3100 WriteLog("DSP: Finished interrupt.\n");
3102 DSPHandleIRQs(); // See if any other interrupts are pending!
3103 IMASKCleared = false;
3106 //if (dsp_flags & REGPAGE)
3107 // WriteLog(" --> REGPAGE has just been set!\n");
3108 #ifdef DSP_DEBUG_PL2
3111 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3112 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]);
3113 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]);
3114 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]);
3115 WriteLog(" --> Scoreboard: ");
3116 for(int i=0; i<32; i++)
3117 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3121 // Stage 1a: Instruction fetch
3122 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3123 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3124 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3125 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3126 if (pipeline[plPtrRead].opcode == 38)
3127 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3128 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3129 #ifdef DSP_DEBUG_PL2
3132 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3133 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3134 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]);
3135 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]);
3136 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]);
3139 // Stage 1b: Read registers
3140 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3141 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3143 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3144 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3145 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3146 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3147 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3148 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3149 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3151 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3152 // We have a hit in the scoreboard, so we have to stall the pipeline...
3153 #ifdef DSP_DEBUG_PL2
3157 WriteLog(" --> Stalling pipeline: ");
3158 if (readAffected[pipeline[plPtrRead].opcode][0])
3159 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3160 if (readAffected[pipeline[plPtrRead].opcode][1])
3161 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3165 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3166 #ifdef DSP_DEBUG_PL2
3171 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3172 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3173 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3175 // Shouldn't we be more selective with the register scoreboarding?
3176 // Yes, we should. !!! FIX !!! Kinda [DONE]
3177 #ifndef NEW_SCOREBOARD
3178 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3180 //Hopefully this will fix the dual MOVEQ # problem...
3181 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3184 //Advance PC here??? Yes.
3185 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3188 #ifdef DSP_DEBUG_PL2
3191 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3192 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]);
3193 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]);
3194 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]);
3198 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3201 WriteLog("\t[inst=%02u][R28=%08X, alt R28=%08X, REGPAGE=%s]\n", pipeline[plPtrExec].opcode, dsp_reg[28], dsp_alternate_reg[28], (dsp_flags & REGPAGE ? "set" : "not set"));
3202 #ifdef DSP_DEBUG_PL2
3205 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3210 lastExec = pipeline[plPtrExec].instruction;
3211 //WriteLog("[lastExec = %04X]\n", lastExec);
3213 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3214 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3215 DSPOpcode[pipeline[plPtrExec].opcode]();
3216 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3220 //Let's not, until we do the stalling correctly...
3221 //But, we gotta while we're doing the comparison core...!
3222 //Or do we? cycles--;
3223 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3224 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3225 //to model this clock cycle behavior correctly...
3226 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3227 //don't affect the reads at stage 1...
3228 #ifdef DSP_DEBUG_STALL
3230 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3234 #ifdef DSP_DEBUG_PL2
3237 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3238 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]);
3239 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]);
3240 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]);
3244 // Stage 3: Write back register/memory address
3245 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3247 /*if (pipeline[plPtrWrite].writebackRegister == 3
3248 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3251 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3254 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3256 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3257 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3260 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3261 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3262 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3263 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3265 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3269 #ifndef NEW_SCOREBOARD
3270 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3271 scoreboard[pipeline[plPtrWrite].operand2] = false;
3273 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3274 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3275 if (scoreboard[pipeline[plPtrWrite].operand2])
3276 scoreboard[pipeline[plPtrWrite].operand2]--;
3280 // Push instructions through the pipeline...
3281 plPtrRead = (++plPtrRead) & 0x03;
3282 plPtrExec = (++plPtrExec) & 0x03;
3283 plPtrWrite = (++plPtrWrite) & 0x03;
3292 //#define DSP_DEBUG_PL3
3293 //Let's try a 2 stage pipeline....
3294 void DSPExecP3(int32 cycles)
3296 dsp_releaseTimeSlice_flag = 0;
3299 while (cycles > 0 && DSP_RUNNING)
3301 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3303 #ifdef DSP_DEBUG_PL3
3304 WriteLog("DSPExecP: Pipeline status...\n");
3305 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]);
3306 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]);
3307 WriteLog(" --> Scoreboard: ");
3308 for(int i=0; i<32; i++)
3309 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3312 // Stage 1a: Instruction fetch
3313 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3314 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3315 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3316 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3317 if (pipeline[plPtrRead].opcode == 38)
3318 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3319 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3320 #ifdef DSP_DEBUG_PL3
3321 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3322 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3323 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]);
3324 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]);
3326 // Stage 1b: Read registers
3327 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3328 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3329 // We have a hit in the scoreboard, so we have to stall the pipeline...
3330 #ifdef DSP_DEBUG_PL3
3332 WriteLog(" --> Stalling pipeline: ");
3333 if (readAffected[pipeline[plPtrRead].opcode][0])
3334 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3335 if (readAffected[pipeline[plPtrRead].opcode][1])
3336 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3339 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3340 #ifdef DSP_DEBUG_PL3
3345 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3346 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3347 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3349 // Shouldn't we be more selective with the register scoreboarding?
3350 // Yes, we should. !!! FIX !!! [Kinda DONE]
3351 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3353 //Advance PC here??? Yes.
3354 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3357 #ifdef DSP_DEBUG_PL3
3358 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3359 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]);
3360 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]);
3362 // Stage 2a: Execute
3363 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3365 #ifdef DSP_DEBUG_PL3
3366 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3368 DSPOpcode[pipeline[plPtrExec].opcode]();
3369 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3370 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3375 #ifdef DSP_DEBUG_PL3
3376 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3377 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]);
3378 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]);
3381 // Stage 2b: Write back register
3382 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3384 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3385 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3387 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3388 scoreboard[pipeline[plPtrExec].operand2] = false;
3391 // Push instructions through the pipeline...
3392 plPtrRead = (++plPtrRead) & 0x03;
3393 plPtrExec = (++plPtrExec) & 0x03;
3400 // DSP pipelined opcode handlers
3403 #define PRM pipeline[plPtrExec].reg1
3404 #define PRN pipeline[plPtrExec].reg2
3405 #define PIMM1 pipeline[plPtrExec].operand1
3406 #define PIMM2 pipeline[plPtrExec].operand2
3407 #define PRES pipeline[plPtrExec].result
3408 #define PWBR pipeline[plPtrExec].writebackRegister
3409 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3410 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3411 #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))
3412 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3414 static void DSP_abs(void)
3418 WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3422 if (_Rn == 0x80000000)
3426 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3427 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3428 CLR_ZN; SET_Z(PRES);
3432 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3436 static void DSP_add(void)
3440 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);
3442 uint32 res = PRN + PRM;
3443 SET_ZNC_ADD(PRN, PRM, res);
3447 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);
3451 static void DSP_addc(void)
3455 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);
3457 uint32 res = PRN + PRM + dsp_flag_c;
3458 uint32 carry = dsp_flag_c;
3459 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3460 SET_ZNC_ADD(PRN + carry, PRM, res);
3461 // SET_ZNC_ADD(PRN, PRM + carry, res);
3465 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);
3469 static void DSP_addq(void)
3473 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);
3475 uint32 r1 = dsp_convert_zero[PIMM1];
3476 uint32 res = PRN + r1;
3477 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3481 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3485 static void DSP_addqmod(void)
3487 #ifdef DSP_DIS_ADDQMOD
3489 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);
3491 uint32 r1 = dsp_convert_zero[PIMM1];
3493 uint32 res = r2 + r1;
3494 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3496 SET_ZNC_ADD(r2, r1, res);
3497 #ifdef DSP_DIS_ADDQMOD
3499 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3503 static void DSP_addqt(void)
3505 #ifdef DSP_DIS_ADDQT
3507 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);
3509 PRES = PRN + dsp_convert_zero[PIMM1];
3510 #ifdef DSP_DIS_ADDQT
3512 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3516 static void DSP_and(void)
3520 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);
3526 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);
3530 static void DSP_bclr(void)
3534 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);
3536 PRES = PRN & ~(1 << PIMM1);
3540 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3544 static void DSP_bset(void)
3548 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);
3550 PRES = PRN | (1 << PIMM1);
3554 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3558 static void DSP_btst(void)
3562 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);
3564 dsp_flag_z = (~PRN >> PIMM1) & 1;
3568 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3572 static void DSP_cmp(void)
3576 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);
3578 uint32 res = PRN - PRM;
3579 SET_ZNC_SUB(PRN, PRM, res);
3583 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3587 static void DSP_cmpq(void)
3589 static int32 sqtable[32] =
3590 { 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 };
3593 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);
3595 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3596 uint32 res = PRN - r1;
3597 SET_ZNC_SUB(PRN, r1, res);
3601 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3605 static void DSP_div(void)
3607 uint32 _Rm = PRM, _Rn = PRN;
3611 if (dsp_div_control & 1)
3613 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3614 if (dsp_remain & 0x80000000)
3616 PRES = (((uint64)_Rn) << 16) / _Rm;
3620 dsp_remain = _Rn % _Rm;
3621 if (dsp_remain & 0x80000000)
3630 static void DSP_imacn(void)
3632 #ifdef DSP_DIS_IMACN
3634 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);
3636 int32 res = (int16)PRM * (int16)PRN;
3637 dsp_acc += (int64)res;
3638 //Should we AND the result to fit into 40 bits here???
3640 #ifdef DSP_DIS_IMACN
3642 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));
3646 static void DSP_imult(void)
3648 #ifdef DSP_DIS_IMULT
3650 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);
3652 PRES = (int16)PRN * (int16)PRM;
3654 #ifdef DSP_DIS_IMULT
3656 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
3660 static void DSP_imultn(void)
3662 #ifdef DSP_DIS_IMULTN
3664 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);
3666 // This is OK, since this multiply won't overflow 32 bits...
3667 int32 res = (int32)((int16)PRN * (int16)PRM);
3668 dsp_acc = (int64)res;
3671 #ifdef DSP_DIS_IMULTN
3673 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));
3677 static void DSP_illegal(void)
3679 #ifdef DSP_DIS_ILLEGAL
3681 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3686 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3687 // can cause trouble because an interrupt can occur *before* the instruction following the
3688 // jump can execute... !!! FIX !!!
3689 // This can probably be solved by judicious coding in the pipeline execution core...
3690 // And should be fixed now...
3691 static void DSP_jr(void)
3694 const char * condition[32] =
3695 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3696 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3697 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3698 "???", "???", "???", "F" };
3700 //How come this is always off by 2???
3701 WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", DSP_PPC, condition[PIMM2], DSP_PPC+((PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1) * 2)+2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3703 // KLUDGE: Used by BRANCH_CONDITION macro
3704 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3706 if (BRANCH_CONDITION(PIMM2))
3710 WriteLog("Branched!\n");
3712 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3713 //Account for pipeline effects...
3714 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3715 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3717 // Now that we've branched, we have to make sure that the following instruction
3718 // is executed atomically with this one and then flush the pipeline before setting
3721 // Step 1: Handle writebacks at stage 3 of pipeline
3722 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3724 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3725 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3727 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3728 scoreboard[pipeline[plPtrWrite].operand2] = false;
3730 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3732 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3734 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3735 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3738 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3739 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3740 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3741 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3743 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3747 #ifndef NEW_SCOREBOARD
3748 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3749 scoreboard[pipeline[plPtrWrite].operand2] = false;
3751 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3752 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3753 if (scoreboard[pipeline[plPtrWrite].operand2])
3754 scoreboard[pipeline[plPtrWrite].operand2]--;
3758 // Step 2: Push instruction through pipeline & execute following instruction
3759 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3760 // we effectively handle the final push of the instruction through the
3761 // pipeline when the new PC takes effect (since when we return, the
3762 // pipeline code will be executing the writeback stage. If we reverse
3763 // the execution order of the pipeline stages, this will no longer be
3765 pipeline[plPtrExec] = pipeline[plPtrRead];
3766 //This is BAD. We need to get that next opcode and execute it!
3767 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3768 // remove this crap.
3769 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3771 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3772 pipeline[plPtrExec].opcode = instruction >> 10;
3773 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3774 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3775 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3776 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3777 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3779 dsp_pc += 2; // For DSP_DIS_* accuracy
3780 DSPOpcode[pipeline[plPtrExec].opcode]();
3781 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3782 pipeline[plPtrWrite] = pipeline[plPtrExec];
3784 // Step 3: Flush pipeline & set new PC
3785 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3792 WriteLog("Branch NOT taken.\n");
3798 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3801 static void DSP_jump(void)
3804 const char * condition[32] =
3805 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3806 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3807 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3808 "???", "???", "???", "F" };
3810 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);
3812 // KLUDGE: Used by BRANCH_CONDITION macro
3813 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3815 if (BRANCH_CONDITION(PIMM2))
3819 WriteLog("Branched!\n");
3821 uint32 PCSave = PRM;
3822 // Now that we've branched, we have to make sure that the following instruction
3823 // is executed atomically with this one and then flush the pipeline before setting
3826 // Step 1: Handle writebacks at stage 3 of pipeline
3827 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3829 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3830 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3832 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3833 scoreboard[pipeline[plPtrWrite].operand2] = false;
3835 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3837 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3839 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3840 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3843 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3844 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3845 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3846 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3848 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3852 #ifndef NEW_SCOREBOARD
3853 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3854 scoreboard[pipeline[plPtrWrite].operand2] = false;
3856 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3857 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3858 if (scoreboard[pipeline[plPtrWrite].operand2])
3859 scoreboard[pipeline[plPtrWrite].operand2]--;
3863 // Step 2: Push instruction through pipeline & execute following instruction
3864 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3865 // we effectively handle the final push of the instruction through the
3866 // pipeline when the new PC takes effect (since when we return, the
3867 // pipeline code will be executing the writeback stage. If we reverse
3868 // the execution order of the pipeline stages, this will no longer be
3870 pipeline[plPtrExec] = pipeline[plPtrRead];
3871 //This is BAD. We need to get that next opcode and execute it!
3872 //Also, same problem in JR!
3873 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3874 // remove this crap.
3875 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3877 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3878 pipeline[plPtrExec].opcode = instruction >> 10;
3879 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3880 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3881 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3882 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3883 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3885 dsp_pc += 2; // For DSP_DIS_* accuracy
3886 DSPOpcode[pipeline[plPtrExec].opcode]();
3887 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3888 pipeline[plPtrWrite] = pipeline[plPtrExec];
3890 // Step 3: Flush pipeline & set new PC
3891 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3898 WriteLog("Branch NOT taken.\n");
3906 static void DSP_load(void)
3910 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);
3912 PRES = DSPReadLong(PRM, DSP);
3915 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3919 static void DSP_loadb(void)
3921 #ifdef DSP_DIS_LOADB
3923 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);
3925 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3926 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3928 PRES = JaguarReadByte(PRM, DSP);
3929 #ifdef DSP_DIS_LOADB
3931 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3935 static void DSP_loadw(void)
3937 #ifdef DSP_DIS_LOADW
3939 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);
3941 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3942 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3944 PRES = JaguarReadWord(PRM, DSP);
3945 #ifdef DSP_DIS_LOADW
3947 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3951 static void DSP_load_r14_i(void)
3953 #ifdef DSP_DIS_LOAD14I
3955 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);
3957 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3958 #ifdef DSP_DIS_LOAD14I
3960 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3964 static void DSP_load_r14_r(void)
3966 #ifdef DSP_DIS_LOAD14R
3968 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);
3970 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3971 #ifdef DSP_DIS_LOAD14R
3973 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3977 static void DSP_load_r15_i(void)
3979 #ifdef DSP_DIS_LOAD15I
3981 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);
3983 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3984 #ifdef DSP_DIS_LOAD15I
3986 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3990 static void DSP_load_r15_r(void)
3992 #ifdef DSP_DIS_LOAD15R
3994 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);
3996 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
3997 #ifdef DSP_DIS_LOAD15R
3999 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4003 static void DSP_mirror(void)
4006 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4010 static void DSP_mmult(void)
4012 int count = dsp_matrix_control&0x0f;
4013 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4017 if (!(dsp_matrix_control & 0x10))
4019 for (int i = 0; i < count; i++)
4023 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4025 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4026 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4033 for (int i = 0; i < count; i++)
4037 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4039 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4040 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4046 PRES = res = (int32)accum;
4048 //NOTE: The flags are set based upon the last add/multiply done...
4052 static void DSP_move(void)
4056 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);
4061 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);
4065 static void DSP_movefa(void)
4067 #ifdef DSP_DIS_MOVEFA
4069 // 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);
4070 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);
4072 // PRES = ALTERNATE_RM;
4073 PRES = dsp_alternate_reg[PIMM1];
4074 #ifdef DSP_DIS_MOVEFA
4076 // 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);
4077 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);
4081 static void DSP_movei(void)
4083 #ifdef DSP_DIS_MOVEI
4085 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);
4087 // // This instruction is followed by 32-bit value in LSW / MSW format...
4088 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4090 #ifdef DSP_DIS_MOVEI
4092 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4096 static void DSP_movepc(void)
4098 #ifdef DSP_DIS_MOVEPC
4100 WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4102 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4103 // PRES = dsp_pc - 2;
4104 //Account for pipeline effects...
4105 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4106 #ifdef DSP_DIS_MOVEPC
4108 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4112 static void DSP_moveq(void)
4114 #ifdef DSP_DIS_MOVEQ
4116 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);
4119 #ifdef DSP_DIS_MOVEQ
4121 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4125 static void DSP_moveta(void)
4127 #ifdef DSP_DIS_MOVETA
4129 // 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);
4130 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]);
4132 // ALTERNATE_RN = PRM;
4133 dsp_alternate_reg[PIMM2] = PRM;
4135 #ifdef DSP_DIS_MOVETA
4137 // 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);
4138 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]);
4142 static void DSP_mtoi(void)
4144 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4148 static void DSP_mult(void)
4152 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);
4154 PRES = (uint16)PRM * (uint16)PRN;
4158 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);
4162 static void DSP_neg(void)
4166 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);
4169 SET_ZNC_SUB(0, PRN, res);
4173 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4177 static void DSP_nop(void)
4181 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4186 static void DSP_normi(void)
4193 while ((_Rm & 0xffc00000) == 0)
4198 while ((_Rm & 0xff800000) != 0)
4208 static void DSP_not(void)
4212 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4218 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4222 static void DSP_or(void)
4226 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);
4232 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);
4236 static void DSP_resmac(void)
4238 #ifdef DSP_DIS_RESMAC
4240 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));
4242 PRES = (uint32)dsp_acc;
4243 #ifdef DSP_DIS_RESMAC
4245 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4249 static void DSP_ror(void)
4253 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);
4255 uint32 r1 = PRM & 0x1F;
4256 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4257 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4261 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);
4265 static void DSP_rorq(void)
4269 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);
4271 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4273 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4275 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4278 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4282 static void DSP_sat16s(void)
4285 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4290 static void DSP_sat32s(void)
4292 int32 r2 = (uint32)PRN;
4293 int32 temp = dsp_acc >> 32;
4294 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4299 static void DSP_sh(void)
4301 int32 sRm = (int32)PRM;
4306 uint32 shift = -sRm;
4311 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4326 dsp_flag_c = _Rn & 0x1;
4339 static void DSP_sha(void)
4341 int32 sRm = (int32)PRM;
4346 uint32 shift = -sRm;
4351 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4366 dsp_flag_c = _Rn & 0x1;
4370 _Rn = ((int32)_Rn) >> 1;
4379 static void DSP_sharq(void)
4381 #ifdef DSP_DIS_SHARQ
4383 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);
4385 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4386 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4388 #ifdef DSP_DIS_SHARQ
4390 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4394 static void DSP_shlq(void)
4398 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);
4400 int32 r1 = 32 - PIMM1;
4401 uint32 res = PRN << r1;
4402 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4406 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4410 static void DSP_shrq(void)
4414 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);
4416 int32 r1 = dsp_convert_zero[PIMM1];
4417 uint32 res = PRN >> r1;
4418 SET_ZN(res); dsp_flag_c = PRN & 1;
4422 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4426 static void DSP_store(void)
4428 #ifdef DSP_DIS_STORE
4430 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);
4432 // DSPWriteLong(PRM, PRN, DSP);
4434 pipeline[plPtrExec].address = PRM;
4435 pipeline[plPtrExec].value = PRN;
4436 pipeline[plPtrExec].type = TYPE_DWORD;
4440 static void DSP_storeb(void)
4442 #ifdef DSP_DIS_STOREB
4444 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);
4446 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4447 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4449 // JaguarWriteByte(PRM, PRN, DSP);
4452 pipeline[plPtrExec].address = PRM;
4454 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4456 pipeline[plPtrExec].value = PRN & 0xFF;
4457 pipeline[plPtrExec].type = TYPE_DWORD;
4461 pipeline[plPtrExec].value = PRN;
4462 pipeline[plPtrExec].type = TYPE_BYTE;
4468 static void DSP_storew(void)
4470 #ifdef DSP_DIS_STOREW
4472 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);
4474 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4475 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4477 // JaguarWriteWord(PRM, PRN, DSP);
4480 pipeline[plPtrExec].address = PRM;
4482 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4484 pipeline[plPtrExec].value = PRN & 0xFFFF;
4485 pipeline[plPtrExec].type = TYPE_DWORD;
4489 pipeline[plPtrExec].value = PRN;
4490 pipeline[plPtrExec].type = TYPE_WORD;
4495 static void DSP_store_r14_i(void)
4497 #ifdef DSP_DIS_STORE14I
4499 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));
4501 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4503 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4504 pipeline[plPtrExec].value = PRN;
4505 pipeline[plPtrExec].type = TYPE_DWORD;
4509 static void DSP_store_r14_r(void)
4511 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4513 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4514 pipeline[plPtrExec].value = PRN;
4515 pipeline[plPtrExec].type = TYPE_DWORD;
4519 static void DSP_store_r15_i(void)
4521 #ifdef DSP_DIS_STORE15I
4523 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));
4525 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4527 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4528 pipeline[plPtrExec].value = PRN;
4529 pipeline[plPtrExec].type = TYPE_DWORD;
4533 static void DSP_store_r15_r(void)
4535 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4537 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4538 pipeline[plPtrExec].value = PRN;
4539 pipeline[plPtrExec].type = TYPE_DWORD;
4543 static void DSP_sub(void)
4547 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);
4549 uint32 res = PRN - PRM;
4550 SET_ZNC_SUB(PRN, PRM, res);
4554 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);
4558 static void DSP_subc(void)
4562 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);
4564 uint32 res = PRN - PRM - dsp_flag_c;
4565 uint32 borrow = dsp_flag_c;
4566 SET_ZNC_SUB(PRN - borrow, PRM, res);
4570 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);
4574 static void DSP_subq(void)
4578 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);
4580 uint32 r1 = dsp_convert_zero[PIMM1];
4581 uint32 res = PRN - r1;
4582 SET_ZNC_SUB(PRN, r1, res);
4586 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4590 static void DSP_subqmod(void)
4592 uint32 r1 = dsp_convert_zero[PIMM1];
4594 uint32 res = r2 - r1;
4595 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4597 SET_ZNC_SUB(r2, r1, res);
4600 static void DSP_subqt(void)
4602 #ifdef DSP_DIS_SUBQT
4604 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);
4606 PRES = PRN - dsp_convert_zero[PIMM1];
4607 #ifdef DSP_DIS_SUBQT
4609 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4613 static void DSP_xor(void)
4617 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);
4623 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);