4 // Original source by Cal2
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James L. Hammons
9 #include <SDL.h> // Used only for SDL_GetTicks...
13 //#define DSP_DEBUG_IRQ
14 //#define DSP_DEBUG_PL2
15 //#define DSP_DEBUG_STALL
16 //#define DSP_DEBUG_CC
17 #define NEW_SCOREBOARD
19 // Disassembly definitions
25 #define DSP_DIS_ADDQMOD
35 #define DSP_DIS_IMULTN
36 #define DSP_DIS_ILLEGAL
40 #define DSP_DIS_LOAD14I
41 #define DSP_DIS_LOAD14R
42 #define DSP_DIS_LOAD15I
43 #define DSP_DIS_LOAD15R
49 #define DSP_DIS_MOVEFA
50 #define DSP_DIS_MOVEPC // Pipeline only!
51 #define DSP_DIS_MOVETA
57 #define DSP_DIS_RESMAC
64 #define DSP_DIS_STORE14I
65 #define DSP_DIS_STORE15I
66 #define DSP_DIS_STOREB
67 #define DSP_DIS_STOREW
74 bool doDSPDis = false;
75 //bool doDSPDis = true;
110 + load_r15_indexed 284500
112 + store_r15_indexed 47416
116 + load_r14_ri 1229448
119 // Pipeline structures
121 const bool affectsScoreboard[64] =
123 true, true, true, true,
124 true, true, true, true,
125 true, true, true, true,
126 true, false, true, true,
128 true, true, false, true,
129 false, true, true, true,
130 true, true, true, true,
131 true, true, false, false,
133 true, true, true, true,
134 false, true, true, true,
135 true, true, true, true,
136 true, false, false, false,
138 true, false, false, true,
139 false, false, true, true,
140 true, false, true, true,
141 false, false, false, true
147 uint8 opcode, operand1, operand2;
148 uint32 reg1, reg2, areg1, areg2;
150 uint8 writebackRegister;
151 // General memory store...
160 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
161 #ifndef NEW_SCOREBOARD
164 uint8 scoreboard[32];
166 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
167 PipelineStage pipeline[4];
168 bool IMASKCleared = false;
170 // DSP flags (old--have to get rid of this crap)
172 #define CINT0FLAG 0x00200
173 #define CINT1FLAG 0x00400
174 #define CINT2FLAG 0x00800
175 #define CINT3FLAG 0x01000
176 #define CINT4FLAG 0x02000
177 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
178 #define CINT5FLAG 0x20000 /* DSP only */
182 #define ZERO_FLAG 0x00001
183 #define CARRY_FLAG 0x00002
184 #define NEGA_FLAG 0x00004
185 #define IMASK 0x00008
186 #define INT_ENA0 0x00010
187 #define INT_ENA1 0x00020
188 #define INT_ENA2 0x00040
189 #define INT_ENA3 0x00080
190 #define INT_ENA4 0x00100
191 #define INT_CLR0 0x00200
192 #define INT_CLR1 0x00400
193 #define INT_CLR2 0x00800
194 #define INT_CLR3 0x01000
195 #define INT_CLR4 0x02000
196 #define REGPAGE 0x04000
197 #define DMAEN 0x08000
198 #define INT_ENA5 0x10000
199 #define INT_CLR5 0x20000
203 #define DSPGO 0x00001
204 #define CPUINT 0x00002
205 #define DSPINT0 0x00004
206 #define SINGLE_STEP 0x00008
207 #define SINGLE_GO 0x00010
209 #define INT_LAT0 0x00040
210 #define INT_LAT1 0x00080
211 #define INT_LAT2 0x00100
212 #define INT_LAT3 0x00200
213 #define INT_LAT4 0x00400
214 #define BUS_HOG 0x00800
215 #define VERSION 0x0F000
216 #define INT_LAT5 0x10000
218 extern uint32 jaguar_mainRom_crc32;
220 // Is opcode 62 *really* a NOP? Seems like it...
221 static void dsp_opcode_abs(void);
222 static void dsp_opcode_add(void);
223 static void dsp_opcode_addc(void);
224 static void dsp_opcode_addq(void);
225 static void dsp_opcode_addqmod(void);
226 static void dsp_opcode_addqt(void);
227 static void dsp_opcode_and(void);
228 static void dsp_opcode_bclr(void);
229 static void dsp_opcode_bset(void);
230 static void dsp_opcode_btst(void);
231 static void dsp_opcode_cmp(void);
232 static void dsp_opcode_cmpq(void);
233 static void dsp_opcode_div(void);
234 static void dsp_opcode_imacn(void);
235 static void dsp_opcode_imult(void);
236 static void dsp_opcode_imultn(void);
237 static void dsp_opcode_jr(void);
238 static void dsp_opcode_jump(void);
239 static void dsp_opcode_load(void);
240 static void dsp_opcode_loadb(void);
241 static void dsp_opcode_loadw(void);
242 static void dsp_opcode_load_r14_indexed(void);
243 static void dsp_opcode_load_r14_ri(void);
244 static void dsp_opcode_load_r15_indexed(void);
245 static void dsp_opcode_load_r15_ri(void);
246 static void dsp_opcode_mirror(void);
247 static void dsp_opcode_mmult(void);
248 static void dsp_opcode_move(void);
249 static void dsp_opcode_movei(void);
250 static void dsp_opcode_movefa(void);
251 static void dsp_opcode_move_pc(void);
252 static void dsp_opcode_moveq(void);
253 static void dsp_opcode_moveta(void);
254 static void dsp_opcode_mtoi(void);
255 static void dsp_opcode_mult(void);
256 static void dsp_opcode_neg(void);
257 static void dsp_opcode_nop(void);
258 static void dsp_opcode_normi(void);
259 static void dsp_opcode_not(void);
260 static void dsp_opcode_or(void);
261 static void dsp_opcode_resmac(void);
262 static void dsp_opcode_ror(void);
263 static void dsp_opcode_rorq(void);
264 static void dsp_opcode_xor(void);
265 static void dsp_opcode_sat16s(void);
266 static void dsp_opcode_sat32s(void);
267 static void dsp_opcode_sh(void);
268 static void dsp_opcode_sha(void);
269 static void dsp_opcode_sharq(void);
270 static void dsp_opcode_shlq(void);
271 static void dsp_opcode_shrq(void);
272 static void dsp_opcode_store(void);
273 static void dsp_opcode_storeb(void);
274 static void dsp_opcode_storew(void);
275 static void dsp_opcode_store_r14_indexed(void);
276 static void dsp_opcode_store_r14_ri(void);
277 static void dsp_opcode_store_r15_indexed(void);
278 static void dsp_opcode_store_r15_ri(void);
279 static void dsp_opcode_sub(void);
280 static void dsp_opcode_subc(void);
281 static void dsp_opcode_subq(void);
282 static void dsp_opcode_subqmod(void);
283 static void dsp_opcode_subqt(void);
285 uint8 dsp_opcode_cycles[64] =
305 void (* dsp_opcode[64])() =
307 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
308 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
309 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
310 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
311 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
312 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
313 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
314 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
315 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
316 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
317 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
318 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
319 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
320 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
321 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
322 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
325 uint32 dsp_opcode_use[65];
327 char * dsp_opcode_str[65]=
329 "add", "addc", "addq", "addqt",
330 "sub", "subc", "subq", "subqt",
331 "neg", "and", "or", "xor",
332 "not", "btst", "bset", "bclr",
333 "mult", "imult", "imultn", "resmac",
334 "imacn", "div", "abs", "sh",
335 "shlq", "shrq", "sha", "sharq",
336 "ror", "rorq", "cmp", "cmpq",
337 "subqmod", "sat16s", "move", "moveq",
338 "moveta", "movefa", "movei", "loadb",
339 "loadw", "load", "sat32s", "load_r14_indexed",
340 "load_r15_indexed", "storeb", "storew", "store",
341 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
342 "jump", "jr", "mmult", "mtoi",
343 "normi", "nop", "load_r14_ri", "load_r15_ri",
344 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
349 static uint64 dsp_acc; // 40 bit register, NOT 32!
350 static uint32 dsp_remain;
351 static uint32 dsp_modulo;
352 static uint32 dsp_flags;
353 static uint32 dsp_matrix_control;
354 static uint32 dsp_pointer_to_matrix;
355 static uint32 dsp_data_organization;
357 static uint32 dsp_div_control;
358 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
359 static uint32 * dsp_reg, * dsp_alternate_reg;
360 static uint32 * dsp_reg_bank_0, * dsp_reg_bank_1;
362 static uint32 dsp_opcode_first_parameter;
363 static uint32 dsp_opcode_second_parameter;
365 #define DSP_RUNNING (dsp_control & 0x01)
367 #define RM dsp_reg[dsp_opcode_first_parameter]
368 #define RN dsp_reg[dsp_opcode_second_parameter]
369 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
370 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
371 #define IMM_1 dsp_opcode_first_parameter
372 #define IMM_2 dsp_opcode_second_parameter
374 #define CLR_Z (dsp_flag_z = 0)
375 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
376 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
377 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
378 #define SET_N(r) (dsp_flag_n = (((UINT32)(r) >> 31) & 0x01))
379 #define SET_C_ADD(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(~(a))))
380 #define SET_C_SUB(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(a)))
381 #define SET_ZN(r) SET_N(r); SET_Z(r)
382 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
383 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
385 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 };
386 uint8 * dsp_branch_condition_table = NULL;
387 static uint16 * mirror_table = NULL;
388 static uint8 * dsp_ram_8 = NULL;
390 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
392 static uint32 dsp_in_exec = 0;
393 static uint32 dsp_releaseTimeSlice_flag = 0;
398 // Comparison core vars (used only for core comparison! :-)
399 static uint64 count = 0;
400 static uint8 ram1[0x2000], ram2[0x2000];
401 static uint32 regs1[64], regs2[64];
402 static uint32 ctrl1[14], ctrl2[14];
405 // Private function prototypes
407 void DSPDumpRegisters(void);
408 void DSPDumpDisassembly(void);
409 void FlushDSPPipeline(void);
412 void dsp_reset_stats(void)
414 for(int i=0; i<65; i++)
415 dsp_opcode_use[i] = 0;
418 void dsp_releaseTimeslice(void)
420 //This does absolutely nothing!!! !!! FIX !!!
421 dsp_releaseTimeSlice_flag = 1;
424 void dsp_build_branch_condition_table(void)
426 // Allocate the mirror table
428 mirror_table = (uint16 *)malloc(65536 * sizeof(mirror_table[0]));
430 // Fill in the mirror table
432 for(int i=0; i<65536; i++)
433 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
434 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
435 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
436 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
437 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
438 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
439 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
440 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
442 if (!dsp_branch_condition_table)
444 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(dsp_branch_condition_table[0]));
446 // Fill in the condition table
447 if (dsp_branch_condition_table)
449 for(int i=0; i<8; i++)
451 for(int j=0; j<32; j++)
458 if (!(i & ZERO_FLAG))
461 if (i & (CARRY_FLAG << (j >> 4)))
464 if (!(i & (CARRY_FLAG << (j >> 4))))
466 dsp_branch_condition_table[i * 32 + j] = result;
473 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
475 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
476 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
478 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
481 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
483 if (offset==0xF1CFE0)
486 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
487 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
489 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
491 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
493 if ((offset&0x03)==0)
496 if ((offset&0x03)==1)
497 return((data>>16)&0xff);
499 if ((offset&0x03)==2)
500 return((data>>8)&0xff);
502 if ((offset&0x03)==3)
506 return JaguarReadByte(offset, who);
509 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
511 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
512 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
514 offset &= 0xFFFFFFFE;
516 /* if (jaguar_mainRom_crc32==0xa74a97cd)
518 if (offset==0xF1A114) return(0x0000);
519 if (offset==0xF1A116) return(0x0000);
520 if (offset==0xF1B000) return(0x1234);
521 if (offset==0xF1B002) return(0x5678);
524 if (jaguar_mainRom_crc32==0x7ae20823)
526 if (offset==0xF1B9D8) return(0x0000);
527 if (offset==0xF1B9Da) return(0x0000);
528 if (offset==0xF1B2C0) return(0x0000);
529 if (offset==0xF1B2C2) return(0x0000);
532 // pour permettre à wolfenstein 3d de tourner sans le dsp
533 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
537 // pour permettre à nba jam de tourner sans le dsp
538 /* if (jaguar_mainRom_crc32==0x4faddb18)
540 if (offset==0xf1b2c0) return(0);
541 if (offset==0xf1b2c2) return(0);
542 if (offset==0xf1b240) return(0);
543 if (offset==0xf1b242) return(0);
544 if (offset==0xF1B340) return(0);
545 if (offset==0xF1B342) return(0);
546 if (offset==0xF1BAD8) return(0);
547 if (offset==0xF1BADA) return(0);
548 if (offset==0xF1B040) return(0);
549 if (offset==0xF1B042) return(0);
550 if (offset==0xF1B0C0) return(0);
551 if (offset==0xF1B0C2) return(0);
552 if (offset==0xF1B140) return(0);
553 if (offset==0xF1B142) return(0);
554 if (offset==0xF1B1C0) return(0);
555 if (offset==0xF1B1C2) return(0);
558 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
560 offset -= DSP_WORK_RAM_BASE;
561 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
563 return GET16(dsp_ram_8, offset);
565 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
567 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
570 return data & 0xFFFF;
575 return JaguarReadWord(offset, who);
578 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
580 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
581 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
584 offset &= 0xFFFFFFFC;
585 /*if (offset == 0xF1BCF4)
587 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));
588 DSPDumpDisassembly();
590 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
592 offset -= DSP_WORK_RAM_BASE;
593 return GET32(dsp_ram_8, offset);
595 //NOTE: Didn't return DSP_ACCUM!!!
596 //Mebbe it's not 'spose to! Yes, it is!
597 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
602 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
603 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
604 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
606 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
607 return dsp_flags & 0xFFFFC1FF;
608 case 0x04: return dsp_matrix_control;
609 case 0x08: return dsp_pointer_to_matrix;
610 case 0x0C: return dsp_data_organization;
611 case 0x10: return dsp_pc;
612 case 0x14: return dsp_control;
613 case 0x18: return dsp_modulo;
614 case 0x1C: return dsp_remain;
616 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
618 // unaligned long read-- !!! FIX !!!
622 return JaguarReadLong(offset, who);
625 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
627 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
628 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
630 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
632 offset -= DSP_WORK_RAM_BASE;
633 dsp_ram_8[offset] = data;
634 //This is rather stupid! !!! FIX !!!
635 /* if (dsp_in_exec == 0)
637 m68k_end_timeslice();
638 gpu_releaseTimeslice();
642 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
644 uint32 reg = offset & 0x1C;
645 int bytenum = offset & 0x03;
647 if ((reg >= 0x1C) && (reg <= 0x1F))
648 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
651 //This looks funky. !!! FIX !!!
652 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
653 bytenum = 3 - bytenum; // convention motorola !!!
654 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
655 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
659 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
660 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
661 JaguarWriteByte(offset, data, who);
664 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
666 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
667 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
668 offset &= 0xFFFFFFFE;
669 /*if (offset == 0xF1BCF4)
671 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
673 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
674 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
676 /*if (offset == 0xF1B2F4)
678 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
680 offset -= DSP_WORK_RAM_BASE;
681 dsp_ram_8[offset] = data >> 8;
682 dsp_ram_8[offset+1] = data & 0xFF;
683 //This is rather stupid! !!! FIX !!!
684 /* if (dsp_in_exec == 0)
686 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
687 m68k_end_timeslice();
688 gpu_releaseTimeslice();
692 SET16(ram1, offset, data),
693 SET16(ram2, offset, data);
698 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
700 if ((offset & 0x1C) == 0x1C)
703 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
705 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
709 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
711 old_data = (old_data&0xffff0000)|(data&0xffff);
713 old_data = (old_data&0xffff)|((data&0xffff)<<16);
714 DSPWriteLong(offset & 0xffffffc, old_data, who);
719 JaguarWriteWord(offset, data, who);
722 //bool badWrite = false;
723 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
725 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
726 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
728 offset &= 0xFFFFFFFC;
729 /*if (offset == 0xF1BCF4)
731 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
733 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
734 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
736 /*if (offset == 0xF1BE2C)
738 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
740 offset -= DSP_WORK_RAM_BASE;
741 SET32(dsp_ram_8, offset, data);
744 SET32(ram1, offset, data),
745 SET32(ram2, offset, data);
750 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
758 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
760 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
761 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
763 dsp_flag_z = dsp_flags & 0x01;
764 dsp_flag_c = (dsp_flags >> 1) & 0x01;
765 dsp_flag_n = (dsp_flags >> 2) & 0x01;
766 DSPUpdateRegisterBanks();
767 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
768 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
769 /* if (IMASKCleared) // If IMASK was cleared,
772 WriteLog("DSP: Finished interrupt.\n");
774 DSPHandleIRQs(); // see if any other interrupts need servicing!
781 dsp_matrix_control = data;
784 // According to JTRM, only lines 2-11 are addressable, the rest being
785 // hardwired to $F1Bxxx.
786 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
789 dsp_data_organization = data;
794 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
799 ctrl1[0] = ctrl2[0] = data;
806 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
808 bool wasRunning = DSP_RUNNING;
809 // uint32 dsp_was_running = DSP_RUNNING;
810 // Check for DSP -> CPU interrupt
814 WriteLog("DSP: DSP -> CPU interrupt\n");
817 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
818 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
820 JERRYSetPendingIRQ(IRQ2_DSP);
821 dsp_releaseTimeslice();
822 m68k_set_irq(7); // Set 68000 NMI...
826 // Check for CPU -> DSP interrupt
830 WriteLog("DSP: CPU -> DSP interrupt\n");
832 m68k_end_timeslice();
833 gpu_releaseTimeslice();
834 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
838 if (data & SINGLE_STEP)
840 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
843 // Protect writes to VERSION and the interrupt latches...
844 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
845 dsp_control = (dsp_control & mask) | (data & ~mask);
849 ctrl1[8] = ctrl2[8] = dsp_control;
853 // if dsp wasn't running but is now running
854 // execute a few cycles
855 //This is just plain wrong, wrong, WRONG!
856 #ifndef DSP_SINGLE_STEPPING
857 /* if (!dsp_was_running && DSP_RUNNING)
862 //This is WRONG! !!! FIX !!!
863 if (dsp_control & 0x18)
868 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
870 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
873 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
874 // !!! FIX !!! [DONE]
878 m68k_end_timeslice();
880 gpu_releaseTimeslice();
884 //DSPDumpDisassembly();
892 dsp_div_control = data;
894 // default: // unaligned long read
900 //We don't have to break this up like this! We CAN do 32 bit writes!
901 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
902 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
903 //if (offset > 0xF1FFFF)
905 JaguarWriteLong(offset, data, who);
909 // Update the DSP register file pointers depending on REGPAGE bit
911 void DSPUpdateRegisterBanks(void)
913 int bank = (dsp_flags & REGPAGE);
915 if (dsp_flags & IMASK)
916 bank = 0; // IMASK forces main bank to be bank 0
919 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
921 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
925 // Check for and handle any asserted DSP IRQs
927 void DSPHandleIRQs(void)
929 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
932 // Get the active interrupt bits (latches) & interrupt mask (enables)
933 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
934 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
936 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
939 if (!bits) // Bail if nothing is enabled
942 int which = 0; // Determine which interrupt
957 WriteLog("DSP: Generating interrupt #%i...", which);
960 //if (which == 0) doDSPDis = true;
962 // NOTE: Since the actual Jaguar hardware injects the code sequence below
963 // directly into the pipeline, it has the side effect of ensuring that the
964 // instruction interrupted also gets to do its writeback. We simulate that
966 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
968 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
969 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
971 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
972 scoreboard[pipeline[plPtrWrite].operand2] = false;
974 //This should be execute (or should it?--not sure now!)
975 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
976 //and what just executed is now in the Write position...). So why didn't it do the
977 //writeback into register 0?
979 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
980 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]);
981 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]);
982 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]);
984 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
986 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
988 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
989 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
992 if (pipeline[plPtrWrite].type == TYPE_BYTE)
993 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
994 else if (pipeline[plPtrWrite].type == TYPE_WORD)
995 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
997 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1001 #ifndef NEW_SCOREBOARD
1002 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1003 scoreboard[pipeline[plPtrWrite].operand2] = false;
1005 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1006 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1007 if (scoreboard[pipeline[plPtrWrite].operand2])
1008 scoreboard[pipeline[plPtrWrite].operand2]--;
1015 ctrl2[4] = dsp_flags;
1018 DSPUpdateRegisterBanks();
1019 #ifdef DSP_DEBUG_IRQ
1020 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1021 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]);
1024 // subqt #4,r31 ; pre-decrement stack pointer
1025 // move pc,r30 ; address of interrupted code
1026 // store r30,(r31) ; store return address
1033 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1034 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1035 //It missed the place that it was supposed to come back to, so this is WRONG!
1037 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1039 // R -> baz (<- PC points here)
1040 // E -> bar (when it should point here!)
1043 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1044 // which means (assuming they're all 2 bytes long) that the code below will come back on
1045 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1046 // instruction stream...
1048 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1049 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1052 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1056 // movei #service_address,r30 ; pointer to ISR entry
1057 // jump (r30) ; jump to ISR
1059 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1062 ctrl2[0] = regs2[30] = dsp_pc;
1069 // Non-pipelined version...
1071 void DSPHandleIRQsNP(void)
1075 memcpy(dsp_ram_8, ram1, 0x2000);
1076 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1077 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1080 dsp_remain = ctrl1[2];
1081 dsp_modulo = ctrl1[3];
1082 dsp_flags = ctrl1[4];
1083 dsp_matrix_control = ctrl1[5];
1084 dsp_pointer_to_matrix = ctrl1[6];
1085 dsp_data_organization = ctrl1[7];
1086 dsp_control = ctrl1[8];
1087 dsp_div_control = ctrl1[9];
1088 IMASKCleared = ctrl1[10];
1089 dsp_flag_z = ctrl1[11];
1090 dsp_flag_n = ctrl1[12];
1091 dsp_flag_c = ctrl1[13];
1092 DSPUpdateRegisterBanks();
1095 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1098 // Get the active interrupt bits (latches) & interrupt mask (enables)
1099 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1100 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1102 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1105 if (!bits) // Bail if nothing is enabled
1108 int which = 0; // Determine which interrupt
1122 #ifdef DSP_DEBUG_IRQ
1123 WriteLog("DSP: Generating interrupt #%i...", which);
1129 ctrl1[4] = dsp_flags;
1132 DSPUpdateRegisterBanks();
1133 #ifdef DSP_DEBUG_IRQ
1134 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1137 // subqt #4,r31 ; pre-decrement stack pointer
1138 // move pc,r30 ; address of interrupted code
1139 // store r30,(r31) ; store return address
1146 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1149 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1153 // movei #service_address,r30 ; pointer to ISR entry
1154 // jump (r30) ; jump to ISR
1156 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1159 ctrl1[0] = regs1[30] = dsp_pc;
1165 // Set the specified DSP IRQ line to a given state
1167 void DSPSetIRQLine(int irqline, int state)
1169 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1170 uint32 mask = INT_LAT0 << irqline;
1171 dsp_control &= ~mask; // Clear the latch bit
1174 ctrl1[8] = ctrl2[8] = dsp_control;
1180 dsp_control |= mask; // Set the latch bit
1184 ctrl1[8] = ctrl2[8] = dsp_control;
1193 memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1194 memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1195 memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1197 dsp_build_branch_condition_table();
1203 dsp_pc = 0x00F1B000;
1204 dsp_acc = 0x00000000;
1205 dsp_remain = 0x00000000;
1206 dsp_modulo = 0xFFFFFFFF;
1207 dsp_flags = 0x00040000;
1208 dsp_matrix_control = 0x00000000;
1209 dsp_pointer_to_matrix = 0x00000000;
1210 dsp_data_organization = 0xFFFFFFFF;
1211 dsp_control = 0x00002000; // Report DSP version 2
1212 dsp_div_control = 0x00000000;
1215 dsp_reg = dsp_reg_bank_0;
1216 dsp_alternate_reg = dsp_reg_bank_1;
1218 for(int i=0; i<32; i++)
1219 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1222 IMASKCleared = false;
1225 memset(dsp_ram_8, 0xFF, 0x2000);
1228 void DSPDumpDisassembly(void)
1232 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1233 uint32 j = 0xF1B000;
1234 while (j <= 0xF1CFFF)
1237 j += dasmjag(JAGUAR_DSP, buffer, j);
1238 WriteLog("\t%08X: %s\n", oldj, buffer);
1242 void DSPDumpRegisters(void)
1244 //Shoud add modulus, etc to dump here...
1245 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1246 WriteLog("\nRegisters bank 0\n");
1247 for(int j=0; j<8; j++)
1249 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1250 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1251 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1252 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1253 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1255 WriteLog("Registers bank 1\n");
1256 for(int j=0; j<8; j++)
1258 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1259 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1260 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1261 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1262 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1269 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1270 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1272 // get the active interrupt bits
1273 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1274 // get the interrupt mask
1275 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1277 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1278 WriteLog("\nRegisters bank 0\n");
1279 for(int j=0; j<8; j++)
1281 WriteLog("\tr%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x\n",
1282 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1283 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1284 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1285 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1287 WriteLog("\nRegisters bank 1\n");
1290 WriteLog("\tr%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x\n",
1291 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1292 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1293 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1294 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1298 static char buffer[512];
1299 j = DSP_WORK_RAM_BASE;
1300 while (j <= 0xF1BFFF)
1303 j += dasmjag(JAGUAR_DSP, buffer, j);
1304 WriteLog("\t%08X: %s\n", oldj, buffer);
1307 WriteLog("DSP opcodes use:\n");
1310 if (dsp_opcode_use[i])
1311 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1314 memory_free(dsp_ram_8);
1320 // DSP comparison core...
1323 static uint16 lastExec;
1324 void DSPExecComp(int32 cycles)
1326 while (cycles > 0 && DSP_RUNNING)
1328 // Load up vars for non-pipelined core
1329 memcpy(dsp_ram_8, ram1, 0x2000);
1330 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1331 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1334 dsp_remain = ctrl1[2];
1335 dsp_modulo = ctrl1[3];
1336 dsp_flags = ctrl1[4];
1337 dsp_matrix_control = ctrl1[5];
1338 dsp_pointer_to_matrix = ctrl1[6];
1339 dsp_data_organization = ctrl1[7];
1340 dsp_control = ctrl1[8];
1341 dsp_div_control = ctrl1[9];
1342 IMASKCleared = ctrl1[10];
1343 dsp_flag_z = ctrl1[11];
1344 dsp_flag_n = ctrl1[12];
1345 dsp_flag_c = ctrl1[13];
1346 DSPUpdateRegisterBanks();
1348 // Decrement cycles based on non-pipelined core...
1349 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1350 cycles -= dsp_opcode_cycles[instr1 >> 10];
1352 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1353 DSPExec(1); // Do *one* instruction
1356 memcpy(ram1, dsp_ram_8, 0x2000);
1357 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1358 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1361 ctrl1[2] = dsp_remain;
1362 ctrl1[3] = dsp_modulo;
1363 ctrl1[4] = dsp_flags;
1364 ctrl1[5] = dsp_matrix_control;
1365 ctrl1[6] = dsp_pointer_to_matrix;
1366 ctrl1[7] = dsp_data_organization;
1367 ctrl1[8] = dsp_control;
1368 ctrl1[9] = dsp_div_control;
1369 ctrl1[10] = IMASKCleared;
1370 ctrl1[11] = dsp_flag_z;
1371 ctrl1[12] = dsp_flag_n;
1372 ctrl1[13] = dsp_flag_c;
1374 // Load up vars for pipelined core
1375 memcpy(dsp_ram_8, ram2, 0x2000);
1376 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1377 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1380 dsp_remain = ctrl2[2];
1381 dsp_modulo = ctrl2[3];
1382 dsp_flags = ctrl2[4];
1383 dsp_matrix_control = ctrl2[5];
1384 dsp_pointer_to_matrix = ctrl2[6];
1385 dsp_data_organization = ctrl2[7];
1386 dsp_control = ctrl2[8];
1387 dsp_div_control = ctrl2[9];
1388 IMASKCleared = ctrl2[10];
1389 dsp_flag_z = ctrl2[11];
1390 dsp_flag_n = ctrl2[12];
1391 dsp_flag_c = ctrl2[13];
1392 DSPUpdateRegisterBanks();
1394 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1395 DSPExecP2(1); // Do *one* instruction
1398 memcpy(ram2, dsp_ram_8, 0x2000);
1399 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1400 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1403 ctrl2[2] = dsp_remain;
1404 ctrl2[3] = dsp_modulo;
1405 ctrl2[4] = dsp_flags;
1406 ctrl2[5] = dsp_matrix_control;
1407 ctrl2[6] = dsp_pointer_to_matrix;
1408 ctrl2[7] = dsp_data_organization;
1409 ctrl2[8] = dsp_control;
1410 ctrl2[9] = dsp_div_control;
1411 ctrl2[10] = IMASKCleared;
1412 ctrl2[11] = dsp_flag_z;
1413 ctrl2[12] = dsp_flag_n;
1414 ctrl2[13] = dsp_flag_c;
1416 if (instr1 != lastExec)
1418 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1420 // 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));
1421 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1422 // if (ctrl1[0] < ppc) // P ran ahead of NP
1423 //How to test this crap???
1426 DSPExecP2(1); // Do one more instruction
1429 memcpy(ram2, dsp_ram_8, 0x2000);
1430 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1431 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1434 ctrl2[2] = dsp_remain;
1435 ctrl2[3] = dsp_modulo;
1436 ctrl2[4] = dsp_flags;
1437 ctrl2[5] = dsp_matrix_control;
1438 ctrl2[6] = dsp_pointer_to_matrix;
1439 ctrl2[7] = dsp_data_organization;
1440 ctrl2[8] = dsp_control;
1441 ctrl2[9] = dsp_div_control;
1442 ctrl2[10] = IMASKCleared;
1443 ctrl2[11] = dsp_flag_z;
1444 ctrl2[12] = dsp_flag_n;
1445 ctrl2[13] = dsp_flag_c;
1447 // else // NP ran ahead of P
1448 if (instr1 != lastExec) // Must be the other way...
1451 // Load up vars for non-pipelined core
1452 memcpy(dsp_ram_8, ram1, 0x2000);
1453 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1454 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1457 dsp_remain = ctrl1[2];
1458 dsp_modulo = ctrl1[3];
1459 dsp_flags = ctrl1[4];
1460 dsp_matrix_control = ctrl1[5];
1461 dsp_pointer_to_matrix = ctrl1[6];
1462 dsp_data_organization = ctrl1[7];
1463 dsp_control = ctrl1[8];
1464 dsp_div_control = ctrl1[9];
1465 IMASKCleared = ctrl1[10];
1466 dsp_flag_z = ctrl1[11];
1467 dsp_flag_n = ctrl1[12];
1468 dsp_flag_c = ctrl1[13];
1469 DSPUpdateRegisterBanks();
1471 for(int k=0; k<2; k++)
1473 // Decrement cycles based on non-pipelined core...
1474 instr1 = DSPReadWord(dsp_pc, DSP);
1475 cycles -= dsp_opcode_cycles[instr1 >> 10];
1477 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1478 DSPExec(1); // Do *one* instruction
1482 memcpy(ram1, dsp_ram_8, 0x2000);
1483 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1484 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1487 ctrl1[2] = dsp_remain;
1488 ctrl1[3] = dsp_modulo;
1489 ctrl1[4] = dsp_flags;
1490 ctrl1[5] = dsp_matrix_control;
1491 ctrl1[6] = dsp_pointer_to_matrix;
1492 ctrl1[7] = dsp_data_organization;
1493 ctrl1[8] = dsp_control;
1494 ctrl1[9] = dsp_div_control;
1495 ctrl1[10] = IMASKCleared;
1496 ctrl1[11] = dsp_flag_z;
1497 ctrl1[12] = dsp_flag_n;
1498 ctrl1[13] = dsp_flag_c;
1502 if (instr1 != lastExec)
1504 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1506 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1507 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1520 // DSP execution core
1522 //static bool R20Set = false, tripwire = false;
1523 //static uint32 pcQueue[32], ptrPCQ = 0;
1524 void DSPExec(int32 cycles)
1526 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1527 dsp_check_if_i2s_interrupt_needed();*/
1529 #ifdef DSP_SINGLE_STEPPING
1530 if (dsp_control & 0x18)
1533 dsp_control &= ~0x10;
1536 //There is *no* good reason to do this here!
1538 dsp_releaseTimeSlice_flag = 0;
1541 while (cycles > 0 && DSP_RUNNING)
1543 /*extern uint32 totalFrames;
1544 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1545 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1546 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1548 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1551 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1553 if (dsp_pc == 0xF1B092)
1554 doDSPDis = false;//*/
1555 /*if (dsp_pc == 0xF1B140)
1556 doDSPDis = true;//*/
1558 if (IMASKCleared) // If IMASK was cleared,
1560 #ifdef DSP_DEBUG_IRQ
1561 WriteLog("DSP: Finished interrupt.\n");
1563 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1564 IMASKCleared = false;
1569 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1570 for(int i=0; i<80; i+=4)
1571 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1574 /*if (dsp_pc == 0xF1B55E)
1576 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1578 /*if (dsp_pc == 0xF1B7D2) // Start here???
1580 pcQueue[ptrPCQ++] = dsp_pc;
1582 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1583 uint32 index = opcode >> 10;
1584 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1585 dsp_opcode_second_parameter = opcode & 0x1F;
1587 dsp_opcode[index]();
1588 dsp_opcode_use[index]++;
1589 cycles -= dsp_opcode_cycles[index];
1590 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1592 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1595 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1597 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1599 DSPDumpDisassembly();
1602 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1605 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1608 WriteLog("\nBacktrace:\n");
1609 for(int i=0; i<32; i++)
1611 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1612 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1622 // DSP opcode handlers
1625 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1626 // can cause trouble because an interrupt can occur *before* the instruction following the
1627 // jump can execute... !!! FIX !!!
1628 static void dsp_opcode_jump(void)
1631 char * condition[32] =
1632 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1633 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1634 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1635 "???", "???", "???", "F" };
1637 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);
1640 /* dsp_flag_c=dsp_flag_c?1:0;
1641 dsp_flag_z=dsp_flag_z?1:0;
1642 dsp_flag_n=dsp_flag_n?1:0;*/
1643 // KLUDGE: Used by BRANCH_CONDITION
1644 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1646 if (BRANCH_CONDITION(IMM_2))
1650 WriteLog("Branched!\n");
1652 uint32 delayed_pc = RM;
1654 dsp_pc = delayed_pc;
1659 WriteLog("Branch NOT taken.\n");
1663 static void dsp_opcode_jr(void)
1666 char * condition[32] =
1667 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1668 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1669 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1670 "???", "???", "???", "F" };
1672 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);
1675 /* dsp_flag_c=dsp_flag_c?1:0;
1676 dsp_flag_z=dsp_flag_z?1:0;
1677 dsp_flag_n=dsp_flag_n?1:0;*/
1678 // KLUDGE: Used by BRANCH_CONDITION
1679 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1681 if (BRANCH_CONDITION(IMM_2))
1685 WriteLog("Branched!\n");
1687 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1688 int32 delayed_pc = dsp_pc + (offset * 2);
1690 dsp_pc = delayed_pc;
1695 WriteLog("Branch NOT taken.\n");
1699 static void dsp_opcode_add(void)
1703 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);
1705 UINT32 res = RN + RM;
1706 SET_ZNC_ADD(RN, RM, res);
1710 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);
1714 static void dsp_opcode_addc(void)
1718 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);
1720 UINT32 res = RN + RM + dsp_flag_c;
1721 UINT32 carry = dsp_flag_c;
1722 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1723 SET_ZNC_ADD(RN + carry, RM, res);
1724 // SET_ZNC_ADD(RN, RM + carry, res);
1728 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);
1732 static void dsp_opcode_addq(void)
1736 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);
1738 UINT32 r1 = dsp_convert_zero[IMM_1];
1739 UINT32 res = RN + r1;
1740 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1744 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1748 static void dsp_opcode_sub(void)
1752 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);
1754 UINT32 res = RN - RM;
1755 SET_ZNC_SUB(RN, RM, res);
1759 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);
1763 static void dsp_opcode_subc(void)
1767 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);
1769 UINT32 res = RN - RM - dsp_flag_c;
1770 UINT32 borrow = dsp_flag_c;
1771 SET_ZNC_SUB(RN - borrow, RM, res);
1775 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);
1779 static void dsp_opcode_subq(void)
1783 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);
1785 UINT32 r1 = dsp_convert_zero[IMM_1];
1786 UINT32 res = RN - r1;
1787 SET_ZNC_SUB(RN, r1, res);
1791 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1795 static void dsp_opcode_cmp(void)
1799 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);
1801 UINT32 res = RN - RM;
1802 SET_ZNC_SUB(RN, RM, res);
1805 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1809 static void dsp_opcode_cmpq(void)
1811 static int32 sqtable[32] =
1812 { 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 };
1815 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);
1817 UINT32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1818 UINT32 res = RN - r1;
1819 SET_ZNC_SUB(RN, r1, res);
1822 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1826 static void dsp_opcode_and(void)
1830 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);
1836 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1840 static void dsp_opcode_or(void)
1844 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);
1850 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);
1854 static void dsp_opcode_xor(void)
1858 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);
1864 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);
1868 static void dsp_opcode_not(void)
1872 WriteLog("%06X: NOT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1878 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);
1882 static void dsp_opcode_move_pc(void)
1887 static void dsp_opcode_store_r14_indexed(void)
1889 #ifdef DSP_DIS_STORE14I
1891 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));
1893 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1896 static void dsp_opcode_store_r15_indexed(void)
1898 #ifdef DSP_DIS_STORE15I
1900 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));
1902 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1905 static void dsp_opcode_load_r14_ri(void)
1907 #ifdef DSP_DIS_LOAD14R
1909 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);
1911 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1912 #ifdef DSP_DIS_LOAD14R
1914 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1918 static void dsp_opcode_load_r15_ri(void)
1920 #ifdef DSP_DIS_LOAD15R
1922 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);
1924 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1925 #ifdef DSP_DIS_LOAD15R
1927 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1931 static void dsp_opcode_store_r14_ri(void)
1933 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1936 static void dsp_opcode_store_r15_ri(void)
1938 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1941 static void dsp_opcode_nop(void)
1945 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1949 static void dsp_opcode_storeb(void)
1951 #ifdef DSP_DIS_STOREB
1953 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);
1955 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1956 DSPWriteLong(RM, RN & 0xFF, DSP);
1958 JaguarWriteByte(RM, RN, DSP);
1961 static void dsp_opcode_storew(void)
1963 #ifdef DSP_DIS_STOREW
1965 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);
1967 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1968 DSPWriteLong(RM, RN & 0xFFFF, DSP);
1970 JaguarWriteWord(RM, RN, DSP);
1973 static void dsp_opcode_store(void)
1975 #ifdef DSP_DIS_STORE
1977 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);
1979 DSPWriteLong(RM, RN, DSP);
1982 static void dsp_opcode_loadb(void)
1984 #ifdef DSP_DIS_LOADB
1986 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);
1988 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1989 RN = DSPReadLong(RM, DSP) & 0xFF;
1991 RN = JaguarReadByte(RM, DSP);
1992 #ifdef DSP_DIS_LOADB
1994 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1998 static void dsp_opcode_loadw(void)
2000 #ifdef DSP_DIS_LOADW
2002 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);
2004 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2005 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2007 RN = JaguarReadWord(RM, DSP);
2008 #ifdef DSP_DIS_LOADW
2010 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2014 static void dsp_opcode_load(void)
2018 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);
2020 RN = DSPReadLong(RM, DSP);
2023 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2027 static void dsp_opcode_load_r14_indexed(void)
2029 #ifdef DSP_DIS_LOAD14I
2031 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);
2033 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2034 #ifdef DSP_DIS_LOAD14I
2036 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2040 static void dsp_opcode_load_r15_indexed(void)
2042 #ifdef DSP_DIS_LOAD15I
2044 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);
2046 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2047 #ifdef DSP_DIS_LOAD15I
2049 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2053 static void dsp_opcode_movei(void)
2055 #ifdef DSP_DIS_MOVEI
2057 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);
2059 // This instruction is followed by 32-bit value in LSW / MSW format...
2060 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2062 #ifdef DSP_DIS_MOVEI
2064 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2068 static void dsp_opcode_moveta(void)
2070 #ifdef DSP_DIS_MOVETA
2072 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);
2075 #ifdef DSP_DIS_MOVETA
2077 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);
2081 static void dsp_opcode_movefa(void)
2083 #ifdef DSP_DIS_MOVEFA
2085 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);
2088 #ifdef DSP_DIS_MOVEFA
2090 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);
2094 static void dsp_opcode_move(void)
2098 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);
2103 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);
2107 static void dsp_opcode_moveq(void)
2109 #ifdef DSP_DIS_MOVEQ
2111 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);
2114 #ifdef DSP_DIS_MOVEQ
2116 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2120 static void dsp_opcode_resmac(void)
2122 #ifdef DSP_DIS_RESMAC
2124 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));
2126 RN = (uint32)dsp_acc;
2127 #ifdef DSP_DIS_RESMAC
2129 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2133 static void dsp_opcode_imult(void)
2135 #ifdef DSP_DIS_IMULT
2137 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);
2139 RN = (int16)RN * (int16)RM;
2141 #ifdef DSP_DIS_IMULT
2143 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);
2147 static void dsp_opcode_mult(void)
2151 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);
2153 RN = (uint16)RM * (uint16)RN;
2157 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);
2161 static void dsp_opcode_bclr(void)
2165 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);
2167 UINT32 res = RN & ~(1 << IMM_1);
2172 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2176 static void dsp_opcode_btst(void)
2180 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);
2182 dsp_flag_z = (~RN >> IMM_1) & 1;
2185 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2189 static void dsp_opcode_bset(void)
2193 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);
2195 UINT32 res = RN | (1 << IMM_1);
2200 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2204 static void dsp_opcode_subqt(void)
2206 #ifdef DSP_DIS_SUBQT
2208 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);
2210 RN -= dsp_convert_zero[IMM_1];
2211 #ifdef DSP_DIS_SUBQT
2213 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2217 static void dsp_opcode_addqt(void)
2219 #ifdef DSP_DIS_ADDQT
2221 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);
2223 RN += dsp_convert_zero[IMM_1];
2224 #ifdef DSP_DIS_ADDQT
2226 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2230 static void dsp_opcode_imacn(void)
2232 #ifdef DSP_DIS_IMACN
2234 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);
2236 int32 res = (int16)RM * (int16)RN;
2237 dsp_acc += (int64)res;
2238 //Should we AND the result to fit into 40 bits here???
2239 #ifdef DSP_DIS_IMACN
2241 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));
2245 static void dsp_opcode_mtoi(void)
2247 RN = (((INT32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2251 static void dsp_opcode_normi(void)
2258 while ((_Rm & 0xffc00000) == 0)
2263 while ((_Rm & 0xff800000) != 0)
2273 static void dsp_opcode_mmult(void)
2275 int count = dsp_matrix_control&0x0f;
2276 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2280 if (!(dsp_matrix_control & 0x10))
2282 for (int i = 0; i < count; i++)
2286 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2288 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2289 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2296 for (int i = 0; i < count; i++)
2300 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2302 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2303 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2308 RN = res = (int32)accum;
2310 //NOTE: The flags are set based upon the last add/multiply done...
2314 static void dsp_opcode_abs(void)
2318 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);
2323 if (_Rn == 0x80000000)
2327 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2328 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2333 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2337 static void dsp_opcode_div(void)
2344 if (dsp_div_control & 1)
2346 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2347 if (dsp_remain&0x80000000)
2349 RN = (((uint64)_Rn) << 16) / _Rm;
2353 dsp_remain = _Rn % _Rm;
2354 if (dsp_remain&0x80000000)
2363 static void dsp_opcode_imultn(void)
2365 #ifdef DSP_DIS_IMULTN
2367 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);
2369 // This is OK, since this multiply won't overflow 32 bits...
2370 int32 res = (int32)((int16)RN * (int16)RM);
2371 dsp_acc = (int64)res;
2373 #ifdef DSP_DIS_IMULTN
2375 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));
2379 static void dsp_opcode_neg(void)
2383 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);
2386 SET_ZNC_SUB(0, RN, res);
2390 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2394 static void dsp_opcode_shlq(void)
2398 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);
2400 INT32 r1 = 32 - IMM_1;
2401 UINT32 res = RN << r1;
2402 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2406 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2410 static void dsp_opcode_shrq(void)
2414 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);
2416 INT32 r1 = dsp_convert_zero[IMM_1];
2417 UINT32 res = RN >> r1;
2418 SET_ZN(res); dsp_flag_c = RN & 1;
2422 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2426 static void dsp_opcode_ror(void)
2430 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);
2432 UINT32 r1 = RM & 0x1F;
2433 UINT32 res = (RN >> r1) | (RN << (32 - r1));
2434 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2438 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);
2442 static void dsp_opcode_rorq(void)
2446 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);
2448 UINT32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2450 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
2452 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2455 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2459 static void dsp_opcode_sha(void)
2461 int32 sRm=(int32)RM;
2467 if (shift>=32) shift=32;
2468 dsp_flag_c=(_Rn&0x80000000)>>31;
2478 if (shift>=32) shift=32;
2482 _Rn=((int32)_Rn)>>1;
2490 static void dsp_opcode_sharq(void)
2492 #ifdef DSP_DIS_SHARQ
2494 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);
2496 UINT32 res = (INT32)RN >> dsp_convert_zero[IMM_1];
2497 SET_ZN(res); dsp_flag_c = RN & 0x01;
2499 #ifdef DSP_DIS_SHARQ
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_sh(void)
2507 int32 sRm=(int32)RM;
2512 uint32 shift=(-sRm);
2513 if (shift>=32) shift=32;
2514 dsp_flag_c=(_Rn&0x80000000)>>31;
2524 if (shift>=32) shift=32;
2536 void dsp_opcode_addqmod(void)
2538 #ifdef DSP_DIS_ADDQMOD
2540 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);
2542 UINT32 r1 = dsp_convert_zero[IMM_1];
2544 UINT32 res = r2 + r1;
2545 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2547 SET_ZNC_ADD(r2, r1, res);
2548 #ifdef DSP_DIS_ADDQMOD
2550 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2554 void dsp_opcode_subqmod(void)
2556 UINT32 r1 = dsp_convert_zero[IMM_1];
2558 UINT32 res = r2 - r1;
2559 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2562 SET_ZNC_SUB(r2, r1, res);
2565 void dsp_opcode_mirror(void)
2568 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2572 void dsp_opcode_sat32s(void)
2574 INT32 r2 = (UINT32)RN;
2575 INT32 temp = dsp_acc >> 32;
2576 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
2581 void dsp_opcode_sat16s(void)
2584 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2590 // New pipelined DSP core
2593 static void DSP_abs(void);
2594 static void DSP_add(void);
2595 static void DSP_addc(void);
2596 static void DSP_addq(void);
2597 static void DSP_addqmod(void);
2598 static void DSP_addqt(void);
2599 static void DSP_and(void);
2600 static void DSP_bclr(void);
2601 static void DSP_bset(void);
2602 static void DSP_btst(void);
2603 static void DSP_cmp(void);
2604 static void DSP_cmpq(void);
2605 static void DSP_div(void);
2606 static void DSP_imacn(void);
2607 static void DSP_imult(void);
2608 static void DSP_imultn(void);
2609 static void DSP_illegal(void);
2610 static void DSP_jr(void);
2611 static void DSP_jump(void);
2612 static void DSP_load(void);
2613 static void DSP_loadb(void);
2614 static void DSP_loadw(void);
2615 static void DSP_load_r14_i(void);
2616 static void DSP_load_r14_r(void);
2617 static void DSP_load_r15_i(void);
2618 static void DSP_load_r15_r(void);
2619 static void DSP_mirror(void);
2620 static void DSP_mmult(void);
2621 static void DSP_move(void);
2622 static void DSP_movefa(void);
2623 static void DSP_movei(void);
2624 static void DSP_movepc(void);
2625 static void DSP_moveq(void);
2626 static void DSP_moveta(void);
2627 static void DSP_mtoi(void);
2628 static void DSP_mult(void);
2629 static void DSP_neg(void);
2630 static void DSP_nop(void);
2631 static void DSP_normi(void);
2632 static void DSP_not(void);
2633 static void DSP_or(void);
2634 static void DSP_resmac(void);
2635 static void DSP_ror(void);
2636 static void DSP_rorq(void);
2637 static void DSP_sat16s(void);
2638 static void DSP_sat32s(void);
2639 static void DSP_sh(void);
2640 static void DSP_sha(void);
2641 static void DSP_sharq(void);
2642 static void DSP_shlq(void);
2643 static void DSP_shrq(void);
2644 static void DSP_store(void);
2645 static void DSP_storeb(void);
2646 static void DSP_storew(void);
2647 static void DSP_store_r14_i(void);
2648 static void DSP_store_r14_r(void);
2649 static void DSP_store_r15_i(void);
2650 static void DSP_store_r15_r(void);
2651 static void DSP_sub(void);
2652 static void DSP_subc(void);
2653 static void DSP_subq(void);
2654 static void DSP_subqmod(void);
2655 static void DSP_subqt(void);
2656 static void DSP_xor(void);
2658 void (* DSPOpcode[64])() =
2660 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2661 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2662 DSP_neg, DSP_and, DSP_or, DSP_xor,
2663 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2665 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2666 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2667 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2668 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2670 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2671 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2672 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2673 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2675 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2676 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2677 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2678 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2681 bool readAffected[64][2] =
2683 { true, true}, { true, true}, {false, true}, {false, true},
2684 { true, true}, { true, true}, {false, true}, {false, true},
2685 {false, true}, { true, true}, { true, true}, { true, true},
2686 {false, true}, {false, true}, {false, true}, {false, true},
2688 { true, true}, { true, true}, { true, true}, {false, true},
2689 { true, true}, { true, true}, {false, true}, { true, true},
2690 {false, true}, {false, true}, { true, true}, {false, true},
2691 { true, true}, {false, true}, { true, true}, {false, true},
2693 {false, true}, {false, true}, { true, false}, {false, false},
2694 { true, false}, {false, false}, {false, false}, { true, false},
2695 { true, false}, { true, false}, {false, true}, { true, false},
2696 { true, false}, { true, true}, { true, true}, { true, true},
2698 {false, true}, { true, true}, { true, true}, {false, true},
2699 { true, false}, { true, false}, { true, true}, { true, false},
2700 { true, false}, {false, false}, { true, false}, { true, false},
2701 { true, true}, { true, true}, {false, false}, {false, true}
2704 bool isLoadStore[65] =
2706 false, false, false, false, false, false, false, false,
2707 false, false, false, false, false, false, false, false,
2709 false, false, false, false, false, false, false, false,
2710 false, false, false, false, false, false, false, false,
2712 false, false, false, false, false, false, false, true,
2713 true, true, false, true, true, true, true, true,
2715 false, true, true, false, false, false, false, false,
2716 false, false, true, true, true, true, false, false, false
2719 void FlushDSPPipeline(void)
2721 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2723 for(int i=0; i<4; i++)
2724 pipeline[i].opcode = PIPELINE_STALL;
2726 for(int i=0; i<32; i++)
2731 // New pipelined DSP execution core
2733 /*void DSPExecP(int32 cycles)
2735 // bool inhibitFetch = false;
2737 dsp_releaseTimeSlice_flag = 0;
2740 while (cycles > 0 && DSP_RUNNING)
2742 WriteLog("DSPExecP: Pipeline status...\n");
2743 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);
2744 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);
2745 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);
2746 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);
2747 WriteLog(" --> Scoreboard: ");
2748 for(int i=0; i<32; i++)
2749 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2751 // Stage 1: Instruction fetch
2752 // if (!inhibitFetch)
2754 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2755 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2756 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2757 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2758 if (pipeline[plPtrFetch].opcode == 38)
2759 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2760 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2763 // inhibitFetch = false;
2764 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2766 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2767 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);
2768 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);
2769 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);
2770 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);
2771 // Stage 2: Read registers
2772 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2773 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2774 if (scoreboard[pipeline[plPtrRead].operand2])
2775 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2776 // We have a hit in the scoreboard, so we have to stall the pipeline...
2778 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2779 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2780 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2781 pipeline[plPtrFetch] = pipeline[plPtrRead];
2782 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2786 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2787 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2788 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2790 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2791 // Shouldn't we be more selective with the register scoreboarding?
2792 // Yes, we should. !!! FIX !!!
2793 scoreboard[pipeline[plPtrRead].operand2] = true;
2794 //Advance PC here??? Yes.
2795 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2796 //This is a mangling of the pipeline stages, but what else to do???
2797 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2800 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2801 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);
2802 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);
2803 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);
2804 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);
2806 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2808 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2809 DSPOpcode[pipeline[plPtrExec].opcode]();
2810 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2811 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2816 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2817 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);
2818 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);
2819 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);
2820 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);
2821 // Stage 4: Write back register
2822 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2824 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2825 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2827 scoreboard[pipeline[plPtrWrite].operand1]
2828 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2831 // Push instructions through the pipeline...
2832 plPtrFetch = (++plPtrFetch) & 0x03;
2833 plPtrRead = (++plPtrRead) & 0x03;
2834 plPtrExec = (++plPtrExec) & 0x03;
2835 plPtrWrite = (++plPtrWrite) & 0x03;
2842 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2844 // Should be fixed now. Another problem is figuring how to do the sequence following
2845 // a branch followed with the JR & JUMP instructions...
2847 // There are two conflicting problems:
2850 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2851 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2852 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2853 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2854 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2855 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2856 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2857 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2858 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2859 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2860 DSP: Finished interrupt.
2861 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2862 ; bank 0 (where is was prepared)!
2863 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2864 F1B252: NOP [NCZ:001]
2867 // The other is when you see this at the end of an IRQ:
2870 JUMP T, (R29) ; R29 = Previous stack + 2
2871 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2873 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2874 ; 1) The STORE goes through the pipeline and is executed/written back
2875 ; 2) The pipeline is flushed
2876 ; 3) The DSP_PC is set to the new address
2877 ; 4) Execution resumes
2879 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2880 ; bank 0 instead of the current bank 1 and so goes astray!
2883 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2884 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2888 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2889 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2890 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2891 If it were done properly, the STORE write back would occur *after* (well, technically,
2892 during) the execution of the the JUMP that follows it.
2896 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2897 F1B08A: NOP [NCZ:001]
2899 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2902 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2905 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2906 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2907 F1B08A: NOP [NCZ:001]
2909 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2912 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2913 DSP: CPU -> DSP interrupt
2914 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2915 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2917 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2920 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2921 F1B006: NOP [NCZ:001]
2923 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2926 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2927 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2930 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2931 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2934 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2935 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2938 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2939 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
2942 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
2945 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
2948 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
2949 F1B0FE: NOP [NCZ:000]
2951 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
2954 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
2957 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
2958 F1B138: NOP [NCZ:000]
2960 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
2963 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
2964 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
2965 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
2968 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
2969 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2972 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
2973 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
2974 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2976 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
2977 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
2980 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
2981 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
2982 DSP: Finished interrupt.
2983 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
2985 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
2988 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
2989 F1B016: NOP [NCZ:001]
2991 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2994 uint32 pcQueue1[0x400];
2996 static uint32 prevR1;
2997 //Let's try a 3 stage pipeline....
2998 //Looks like 3 stage is correct, otherwise bad things happen...
2999 void DSPExecP2(int32 cycles)
3001 dsp_releaseTimeSlice_flag = 0;
3004 while (cycles > 0 && DSP_RUNNING)
3006 /*extern uint32 totalFrames;
3007 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3008 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3009 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3011 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3014 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3016 if (dsp_pc == 0xF1B092)
3017 doDSPDis = false;//*/
3018 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3019 doDSPDis = true;//*/
3020 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3021 doDSPDis = true;//*/
3022 /*if (dsp_pc == 0xF1B0A0)
3023 doDSPDis = true;//*/
3024 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3025 doDSPDis = true;//*/
3026 //Two parter... (not sure how to write this)
3027 //if (dsp_pc == 0xF1B0D2)
3028 // prevR1 = dsp_reg[1];
3030 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3031 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3034 pcQueue1[pcQPtr1++] = dsp_pc;
3037 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3039 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3044 for(int i=0; i<0x400; i++)
3046 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3047 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3051 if (IMASKCleared) // If IMASK was cleared,
3053 #ifdef DSP_DEBUG_IRQ
3054 WriteLog("DSP: Finished interrupt.\n");
3056 DSPHandleIRQs(); // See if any other interrupts are pending!
3057 IMASKCleared = false;
3060 //if (dsp_flags & REGPAGE)
3061 // WriteLog(" --> REGPAGE has just been set!\n");
3062 #ifdef DSP_DEBUG_PL2
3065 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3066 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]);
3067 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]);
3068 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]);
3069 WriteLog(" --> Scoreboard: ");
3070 for(int i=0; i<32; i++)
3071 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3075 // Stage 1a: Instruction fetch
3076 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3077 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3078 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3079 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3080 if (pipeline[plPtrRead].opcode == 38)
3081 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3082 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3083 #ifdef DSP_DEBUG_PL2
3086 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3087 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3088 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]);
3089 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]);
3090 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]);
3093 // Stage 1b: Read registers
3094 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3095 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3097 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3098 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3099 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3100 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3101 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3102 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3103 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3105 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3106 // We have a hit in the scoreboard, so we have to stall the pipeline...
3107 #ifdef DSP_DEBUG_PL2
3111 WriteLog(" --> Stalling pipeline: ");
3112 if (readAffected[pipeline[plPtrRead].opcode][0])
3113 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3114 if (readAffected[pipeline[plPtrRead].opcode][1])
3115 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3119 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3120 #ifdef DSP_DEBUG_PL2
3125 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3126 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3127 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3129 // Shouldn't we be more selective with the register scoreboarding?
3130 // Yes, we should. !!! FIX !!! Kinda [DONE]
3131 #ifndef NEW_SCOREBOARD
3132 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3134 //Hopefully this will fix the dual MOVEQ # problem...
3135 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3138 //Advance PC here??? Yes.
3139 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3142 #ifdef DSP_DEBUG_PL2
3145 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3146 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]);
3147 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]);
3148 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]);
3152 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3155 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"));
3156 #ifdef DSP_DEBUG_PL2
3159 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3164 lastExec = pipeline[plPtrExec].instruction;
3165 //WriteLog("[lastExec = %04X]\n", lastExec);
3167 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3168 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3169 DSPOpcode[pipeline[plPtrExec].opcode]();
3170 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3174 //Let's not, until we do the stalling correctly...
3175 //But, we gotta while we're doing the comparison core...!
3176 //Or do we? cycles--;
3177 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3178 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3179 //to model this clock cycle behavior correctly...
3180 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3181 //don't affect the reads at stage 1...
3182 #ifdef DSP_DEBUG_STALL
3184 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3188 #ifdef DSP_DEBUG_PL2
3191 WriteLog("DSPExecP: Pipeline status (after stage 2) [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 // Stage 3: Write back register/memory address
3199 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3201 /*if (pipeline[plPtrWrite].writebackRegister == 3
3202 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3205 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3208 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3210 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3211 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3214 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3215 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3216 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3217 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3219 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3223 #ifndef NEW_SCOREBOARD
3224 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3225 scoreboard[pipeline[plPtrWrite].operand2] = false;
3227 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3228 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3229 if (scoreboard[pipeline[plPtrWrite].operand2])
3230 scoreboard[pipeline[plPtrWrite].operand2]--;
3234 // Push instructions through the pipeline...
3235 plPtrRead = (++plPtrRead) & 0x03;
3236 plPtrExec = (++plPtrExec) & 0x03;
3237 plPtrWrite = (++plPtrWrite) & 0x03;
3246 //#define DSP_DEBUG_PL3
3247 //Let's try a 2 stage pipeline....
3248 void DSPExecP3(int32 cycles)
3250 dsp_releaseTimeSlice_flag = 0;
3253 while (cycles > 0 && DSP_RUNNING)
3255 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3257 #ifdef DSP_DEBUG_PL3
3258 WriteLog("DSPExecP: Pipeline status...\n");
3259 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]);
3260 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]);
3261 WriteLog(" --> Scoreboard: ");
3262 for(int i=0; i<32; i++)
3263 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3266 // Stage 1a: Instruction fetch
3267 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3268 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3269 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3270 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3271 if (pipeline[plPtrRead].opcode == 38)
3272 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3273 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3274 #ifdef DSP_DEBUG_PL3
3275 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3276 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3277 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]);
3278 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]);
3280 // Stage 1b: Read registers
3281 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3282 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3283 // We have a hit in the scoreboard, so we have to stall the pipeline...
3284 #ifdef DSP_DEBUG_PL3
3286 WriteLog(" --> Stalling pipeline: ");
3287 if (readAffected[pipeline[plPtrRead].opcode][0])
3288 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3289 if (readAffected[pipeline[plPtrRead].opcode][1])
3290 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3293 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3294 #ifdef DSP_DEBUG_PL3
3299 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3300 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3301 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3303 // Shouldn't we be more selective with the register scoreboarding?
3304 // Yes, we should. !!! FIX !!! [Kinda DONE]
3305 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3307 //Advance PC here??? Yes.
3308 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3311 #ifdef DSP_DEBUG_PL3
3312 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3313 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]);
3314 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]);
3316 // Stage 2a: Execute
3317 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3319 #ifdef DSP_DEBUG_PL3
3320 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3322 DSPOpcode[pipeline[plPtrExec].opcode]();
3323 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3324 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3329 #ifdef DSP_DEBUG_PL3
3330 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3331 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]);
3332 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]);
3335 // Stage 2b: Write back register
3336 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3338 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3339 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3341 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3342 scoreboard[pipeline[plPtrExec].operand2] = false;
3345 // Push instructions through the pipeline...
3346 plPtrRead = (++plPtrRead) & 0x03;
3347 plPtrExec = (++plPtrExec) & 0x03;
3354 // DSP pipelined opcode handlers
3357 #define PRM pipeline[plPtrExec].reg1
3358 #define PRN pipeline[plPtrExec].reg2
3359 #define PIMM1 pipeline[plPtrExec].operand1
3360 #define PIMM2 pipeline[plPtrExec].operand2
3361 #define PRES pipeline[plPtrExec].result
3362 #define PWBR pipeline[plPtrExec].writebackRegister
3363 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3364 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3365 #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))
3366 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3368 static void DSP_abs(void)
3372 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);
3376 if (_Rn == 0x80000000)
3380 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3381 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3382 CLR_ZN; SET_Z(PRES);
3386 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3390 static void DSP_add(void)
3394 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);
3396 UINT32 res = PRN + PRM;
3397 SET_ZNC_ADD(PRN, PRM, res);
3401 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);
3405 static void DSP_addc(void)
3409 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);
3411 UINT32 res = PRN + PRM + dsp_flag_c;
3412 UINT32 carry = dsp_flag_c;
3413 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3414 SET_ZNC_ADD(PRN + carry, PRM, res);
3415 // SET_ZNC_ADD(PRN, PRM + carry, res);
3419 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);
3423 static void DSP_addq(void)
3427 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);
3429 UINT32 r1 = dsp_convert_zero[PIMM1];
3430 UINT32 res = PRN + r1;
3431 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3435 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3439 static void DSP_addqmod(void)
3441 #ifdef DSP_DIS_ADDQMOD
3443 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);
3445 UINT32 r1 = dsp_convert_zero[PIMM1];
3447 UINT32 res = r2 + r1;
3448 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3450 SET_ZNC_ADD(r2, r1, res);
3451 #ifdef DSP_DIS_ADDQMOD
3453 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3457 static void DSP_addqt(void)
3459 #ifdef DSP_DIS_ADDQT
3461 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);
3463 PRES = PRN + dsp_convert_zero[PIMM1];
3464 #ifdef DSP_DIS_ADDQT
3466 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3470 static void DSP_and(void)
3474 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);
3480 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);
3484 static void DSP_bclr(void)
3488 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);
3490 PRES = PRN & ~(1 << PIMM1);
3494 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3498 static void DSP_bset(void)
3502 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);
3504 PRES = PRN | (1 << PIMM1);
3508 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3512 static void DSP_btst(void)
3516 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);
3518 dsp_flag_z = (~PRN >> PIMM1) & 1;
3522 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3526 static void DSP_cmp(void)
3530 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);
3532 UINT32 res = PRN - PRM;
3533 SET_ZNC_SUB(PRN, PRM, res);
3537 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3541 static void DSP_cmpq(void)
3543 static int32 sqtable[32] =
3544 { 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 };
3547 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);
3549 UINT32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3550 UINT32 res = PRN - r1;
3551 SET_ZNC_SUB(PRN, r1, res);
3555 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3559 static void DSP_div(void)
3561 uint32 _Rm = PRM, _Rn = PRN;
3565 if (dsp_div_control & 1)
3567 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3568 if (dsp_remain & 0x80000000)
3570 PRES = (((uint64)_Rn) << 16) / _Rm;
3574 dsp_remain = _Rn % _Rm;
3575 if (dsp_remain & 0x80000000)
3584 static void DSP_imacn(void)
3586 #ifdef DSP_DIS_IMACN
3588 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);
3590 int32 res = (int16)PRM * (int16)PRN;
3591 dsp_acc += (int64)res;
3592 //Should we AND the result to fit into 40 bits here???
3594 #ifdef DSP_DIS_IMACN
3596 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));
3600 static void DSP_imult(void)
3602 #ifdef DSP_DIS_IMULT
3604 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);
3606 PRES = (int16)PRN * (int16)PRM;
3608 #ifdef DSP_DIS_IMULT
3610 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);
3614 static void DSP_imultn(void)
3616 #ifdef DSP_DIS_IMULTN
3618 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);
3620 // This is OK, since this multiply won't overflow 32 bits...
3621 int32 res = (int32)((int16)PRN * (int16)PRM);
3622 dsp_acc = (int64)res;
3625 #ifdef DSP_DIS_IMULTN
3627 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));
3631 static void DSP_illegal(void)
3633 #ifdef DSP_DIS_ILLEGAL
3635 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3640 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3641 // can cause trouble because an interrupt can occur *before* the instruction following the
3642 // jump can execute... !!! FIX !!!
3643 // This can probably be solved by judicious coding in the pipeline execution core...
3644 // And should be fixed now...
3645 static void DSP_jr(void)
3648 char * condition[32] =
3649 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3650 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3651 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3652 "???", "???", "???", "F" };
3654 //How come this is always off by 2???
3655 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);
3657 // KLUDGE: Used by BRANCH_CONDITION macro
3658 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3660 if (BRANCH_CONDITION(PIMM2))
3664 WriteLog("Branched!\n");
3666 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3667 //Account for pipeline effects...
3668 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3669 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3671 // Now that we've branched, we have to make sure that the following instruction
3672 // is executed atomically with this one and then flush the pipeline before setting
3675 // Step 1: Handle writebacks at stage 3 of pipeline
3676 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3678 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3679 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3681 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3682 scoreboard[pipeline[plPtrWrite].operand2] = false;
3684 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3686 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3688 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3689 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3692 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3693 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3694 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3695 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3697 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3701 #ifndef NEW_SCOREBOARD
3702 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3703 scoreboard[pipeline[plPtrWrite].operand2] = false;
3705 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3706 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3707 if (scoreboard[pipeline[plPtrWrite].operand2])
3708 scoreboard[pipeline[plPtrWrite].operand2]--;
3712 // Step 2: Push instruction through pipeline & execute following instruction
3713 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3714 // we effectively handle the final push of the instruction through the
3715 // pipeline when the new PC takes effect (since when we return, the
3716 // pipeline code will be executing the writeback stage. If we reverse
3717 // the execution order of the pipeline stages, this will no longer be
3719 pipeline[plPtrExec] = pipeline[plPtrRead];
3720 //This is BAD. We need to get that next opcode and execute it!
3721 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3722 // remove this crap.
3723 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3725 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3726 pipeline[plPtrExec].opcode = instruction >> 10;
3727 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3728 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3729 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3730 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3731 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3733 dsp_pc += 2; // For DSP_DIS_* accuracy
3734 DSPOpcode[pipeline[plPtrExec].opcode]();
3735 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3736 pipeline[plPtrWrite] = pipeline[plPtrExec];
3738 // Step 3: Flush pipeline & set new PC
3739 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3746 WriteLog("Branch NOT taken.\n");
3752 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3755 static void DSP_jump(void)
3758 char * condition[32] =
3759 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3760 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3761 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3762 "???", "???", "???", "F" };
3764 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);
3766 // KLUDGE: Used by BRANCH_CONDITION macro
3767 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3769 if (BRANCH_CONDITION(PIMM2))
3773 WriteLog("Branched!\n");
3775 uint32 PCSave = PRM;
3776 // Now that we've branched, we have to make sure that the following instruction
3777 // is executed atomically with this one and then flush the pipeline before setting
3780 // Step 1: Handle writebacks at stage 3 of pipeline
3781 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3783 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3784 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3786 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3787 scoreboard[pipeline[plPtrWrite].operand2] = false;
3789 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3791 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3793 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3794 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3797 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3798 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3799 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3800 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3802 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3806 #ifndef NEW_SCOREBOARD
3807 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3808 scoreboard[pipeline[plPtrWrite].operand2] = false;
3810 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3811 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3812 if (scoreboard[pipeline[plPtrWrite].operand2])
3813 scoreboard[pipeline[plPtrWrite].operand2]--;
3817 // Step 2: Push instruction through pipeline & execute following instruction
3818 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3819 // we effectively handle the final push of the instruction through the
3820 // pipeline when the new PC takes effect (since when we return, the
3821 // pipeline code will be executing the writeback stage. If we reverse
3822 // the execution order of the pipeline stages, this will no longer be
3824 pipeline[plPtrExec] = pipeline[plPtrRead];
3825 //This is BAD. We need to get that next opcode and execute it!
3826 //Also, same problem in JR!
3827 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3828 // remove this crap.
3829 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3831 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3832 pipeline[plPtrExec].opcode = instruction >> 10;
3833 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3834 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3835 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3836 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3837 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3839 dsp_pc += 2; // For DSP_DIS_* accuracy
3840 DSPOpcode[pipeline[plPtrExec].opcode]();
3841 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3842 pipeline[plPtrWrite] = pipeline[plPtrExec];
3844 // Step 3: Flush pipeline & set new PC
3845 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3852 WriteLog("Branch NOT taken.\n");
3860 static void DSP_load(void)
3864 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);
3866 PRES = DSPReadLong(PRM, DSP);
3869 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3873 static void DSP_loadb(void)
3875 #ifdef DSP_DIS_LOADB
3877 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);
3879 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3880 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3882 PRES = JaguarReadByte(PRM, DSP);
3883 #ifdef DSP_DIS_LOADB
3885 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3889 static void DSP_loadw(void)
3891 #ifdef DSP_DIS_LOADW
3893 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);
3895 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3896 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3898 PRES = JaguarReadWord(PRM, DSP);
3899 #ifdef DSP_DIS_LOADW
3901 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3905 static void DSP_load_r14_i(void)
3907 #ifdef DSP_DIS_LOAD14I
3909 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);
3911 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3912 #ifdef DSP_DIS_LOAD14I
3914 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3918 static void DSP_load_r14_r(void)
3920 #ifdef DSP_DIS_LOAD14R
3922 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);
3924 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3925 #ifdef DSP_DIS_LOAD14R
3927 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3931 static void DSP_load_r15_i(void)
3933 #ifdef DSP_DIS_LOAD15I
3935 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);
3937 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3938 #ifdef DSP_DIS_LOAD15I
3940 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3944 static void DSP_load_r15_r(void)
3946 #ifdef DSP_DIS_LOAD15R
3948 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);
3950 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
3951 #ifdef DSP_DIS_LOAD15R
3953 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3957 static void DSP_mirror(void)
3960 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
3964 static void DSP_mmult(void)
3966 int count = dsp_matrix_control&0x0f;
3967 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
3971 if (!(dsp_matrix_control & 0x10))
3973 for (int i = 0; i < count; i++)
3977 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
3979 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
3980 int16 b=((int16)DSPReadWord(addr + 2, DSP));
3987 for (int i = 0; i < count; i++)
3991 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
3993 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
3994 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4000 PRES = res = (int32)accum;
4002 //NOTE: The flags are set based upon the last add/multiply done...
4006 static void DSP_move(void)
4010 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);
4015 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);
4019 static void DSP_movefa(void)
4021 #ifdef DSP_DIS_MOVEFA
4023 // 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);
4024 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);
4026 // PRES = ALTERNATE_RM;
4027 PRES = dsp_alternate_reg[PIMM1];
4028 #ifdef DSP_DIS_MOVEFA
4030 // 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);
4031 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);
4035 static void DSP_movei(void)
4037 #ifdef DSP_DIS_MOVEI
4039 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);
4041 // // This instruction is followed by 32-bit value in LSW / MSW format...
4042 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4044 #ifdef DSP_DIS_MOVEI
4046 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4050 static void DSP_movepc(void)
4052 #ifdef DSP_DIS_MOVEPC
4054 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);
4056 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4057 // PRES = dsp_pc - 2;
4058 //Account for pipeline effects...
4059 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4060 #ifdef DSP_DIS_MOVEPC
4062 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4066 static void DSP_moveq(void)
4068 #ifdef DSP_DIS_MOVEQ
4070 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);
4073 #ifdef DSP_DIS_MOVEQ
4075 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4079 static void DSP_moveta(void)
4081 #ifdef DSP_DIS_MOVETA
4083 // 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);
4084 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]);
4086 // ALTERNATE_RN = PRM;
4087 dsp_alternate_reg[PIMM2] = PRM;
4089 #ifdef DSP_DIS_MOVETA
4091 // 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);
4092 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]);
4096 static void DSP_mtoi(void)
4098 PRES = (((INT32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4102 static void DSP_mult(void)
4106 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);
4108 PRES = (uint16)PRM * (uint16)PRN;
4112 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);
4116 static void DSP_neg(void)
4120 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);
4123 SET_ZNC_SUB(0, PRN, res);
4127 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4131 static void DSP_nop(void)
4135 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4140 static void DSP_normi(void)
4147 while ((_Rm & 0xffc00000) == 0)
4152 while ((_Rm & 0xff800000) != 0)
4162 static void DSP_not(void)
4166 WriteLog("%06X: NOT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
4172 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);
4176 static void DSP_or(void)
4180 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);
4186 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);
4190 static void DSP_resmac(void)
4192 #ifdef DSP_DIS_RESMAC
4194 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));
4196 PRES = (uint32)dsp_acc;
4197 #ifdef DSP_DIS_RESMAC
4199 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4203 static void DSP_ror(void)
4207 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);
4209 UINT32 r1 = PRM & 0x1F;
4210 UINT32 res = (PRN >> r1) | (PRN << (32 - r1));
4211 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4215 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);
4219 static void DSP_rorq(void)
4223 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);
4225 UINT32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4227 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
4229 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4232 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4236 static void DSP_sat16s(void)
4239 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4244 static void DSP_sat32s(void)
4246 INT32 r2 = (UINT32)PRN;
4247 INT32 temp = dsp_acc >> 32;
4248 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
4253 static void DSP_sh(void)
4255 int32 sRm = (int32)PRM;
4260 uint32 shift = -sRm;
4265 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4280 dsp_flag_c = _Rn & 0x1;
4293 static void DSP_sha(void)
4295 int32 sRm = (int32)PRM;
4300 uint32 shift = -sRm;
4305 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4320 dsp_flag_c = _Rn & 0x1;
4324 _Rn = ((int32)_Rn) >> 1;
4333 static void DSP_sharq(void)
4335 #ifdef DSP_DIS_SHARQ
4337 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);
4339 UINT32 res = (INT32)PRN >> dsp_convert_zero[PIMM1];
4340 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4342 #ifdef DSP_DIS_SHARQ
4344 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4348 static void DSP_shlq(void)
4352 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);
4354 INT32 r1 = 32 - PIMM1;
4355 UINT32 res = PRN << r1;
4356 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4360 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4364 static void DSP_shrq(void)
4368 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);
4370 INT32 r1 = dsp_convert_zero[PIMM1];
4371 UINT32 res = PRN >> r1;
4372 SET_ZN(res); dsp_flag_c = PRN & 1;
4376 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4380 static void DSP_store(void)
4382 #ifdef DSP_DIS_STORE
4384 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);
4386 // DSPWriteLong(PRM, PRN, DSP);
4388 pipeline[plPtrExec].address = PRM;
4389 pipeline[plPtrExec].value = PRN;
4390 pipeline[plPtrExec].type = TYPE_DWORD;
4394 static void DSP_storeb(void)
4396 #ifdef DSP_DIS_STOREB
4398 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);
4400 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4401 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4403 // JaguarWriteByte(PRM, PRN, DSP);
4406 pipeline[plPtrExec].address = PRM;
4408 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4410 pipeline[plPtrExec].value = PRN & 0xFF;
4411 pipeline[plPtrExec].type = TYPE_DWORD;
4415 pipeline[plPtrExec].value = PRN;
4416 pipeline[plPtrExec].type = TYPE_BYTE;
4422 static void DSP_storew(void)
4424 #ifdef DSP_DIS_STOREW
4426 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);
4428 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4429 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4431 // JaguarWriteWord(PRM, PRN, DSP);
4434 pipeline[plPtrExec].address = PRM;
4436 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4438 pipeline[plPtrExec].value = PRN & 0xFFFF;
4439 pipeline[plPtrExec].type = TYPE_DWORD;
4443 pipeline[plPtrExec].value = PRN;
4444 pipeline[plPtrExec].type = TYPE_WORD;
4449 static void DSP_store_r14_i(void)
4451 #ifdef DSP_DIS_STORE14I
4453 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));
4455 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4457 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4458 pipeline[plPtrExec].value = PRN;
4459 pipeline[plPtrExec].type = TYPE_DWORD;
4463 static void DSP_store_r14_r(void)
4465 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4467 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4468 pipeline[plPtrExec].value = PRN;
4469 pipeline[plPtrExec].type = TYPE_DWORD;
4473 static void DSP_store_r15_i(void)
4475 #ifdef DSP_DIS_STORE15I
4477 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));
4479 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4481 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4482 pipeline[plPtrExec].value = PRN;
4483 pipeline[plPtrExec].type = TYPE_DWORD;
4487 static void DSP_store_r15_r(void)
4489 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4491 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4492 pipeline[plPtrExec].value = PRN;
4493 pipeline[plPtrExec].type = TYPE_DWORD;
4497 static void DSP_sub(void)
4501 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);
4503 UINT32 res = PRN - PRM;
4504 SET_ZNC_SUB(PRN, PRM, res);
4508 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);
4512 static void DSP_subc(void)
4516 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);
4518 UINT32 res = PRN - PRM - dsp_flag_c;
4519 UINT32 borrow = dsp_flag_c;
4520 SET_ZNC_SUB(PRN - borrow, PRM, res);
4524 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);
4528 static void DSP_subq(void)
4532 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);
4534 UINT32 r1 = dsp_convert_zero[PIMM1];
4535 UINT32 res = PRN - r1;
4536 SET_ZNC_SUB(PRN, r1, res);
4540 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4544 static void DSP_subqmod(void)
4546 UINT32 r1 = dsp_convert_zero[PIMM1];
4548 UINT32 res = r2 - r1;
4549 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4551 SET_ZNC_SUB(r2, r1, res);
4554 static void DSP_subqt(void)
4556 #ifdef DSP_DIS_SUBQT
4558 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);
4560 PRES = PRN - dsp_convert_zero[PIMM1];
4561 #ifdef DSP_DIS_SUBQT
4563 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4567 static void DSP_xor(void)
4571 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);
4577 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);