4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James L. Hammons
10 #include <SDL.h> // Used only for SDL_GetTicks...
14 //#define DSP_DEBUG_IRQ
15 //#define DSP_DEBUG_PL2
16 //#define DSP_DEBUG_STALL
17 //#define DSP_DEBUG_CC
18 #define NEW_SCOREBOARD
20 // Disassembly definitions
26 #define DSP_DIS_ADDQMOD
36 #define DSP_DIS_IMULTN
37 #define DSP_DIS_ILLEGAL
41 #define DSP_DIS_LOAD14I
42 #define DSP_DIS_LOAD14R
43 #define DSP_DIS_LOAD15I
44 #define DSP_DIS_LOAD15R
50 #define DSP_DIS_MOVEFA
51 #define DSP_DIS_MOVEPC // Pipeline only!
52 #define DSP_DIS_MOVETA
58 #define DSP_DIS_RESMAC
65 #define DSP_DIS_STORE14I
66 #define DSP_DIS_STORE15I
67 #define DSP_DIS_STOREB
68 #define DSP_DIS_STOREW
75 bool doDSPDis = false;
76 //bool doDSPDis = true;
111 + load_r15_indexed 284500
113 + store_r15_indexed 47416
117 + load_r14_ri 1229448
120 // Pipeline structures
122 const bool affectsScoreboard[64] =
124 true, true, true, true,
125 true, true, true, true,
126 true, true, true, true,
127 true, false, true, true,
129 true, true, false, true,
130 false, true, true, true,
131 true, true, true, true,
132 true, true, false, false,
134 true, true, true, true,
135 false, true, true, true,
136 true, true, true, true,
137 true, false, false, false,
139 true, false, false, true,
140 false, false, true, true,
141 true, false, true, true,
142 false, false, false, true
148 uint8 opcode, operand1, operand2;
149 uint32 reg1, reg2, areg1, areg2;
151 uint8 writebackRegister;
152 // General memory store...
161 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
162 #ifndef NEW_SCOREBOARD
165 uint8 scoreboard[32];
167 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
168 PipelineStage pipeline[4];
169 bool IMASKCleared = false;
171 // DSP flags (old--have to get rid of this crap)
173 #define CINT0FLAG 0x00200
174 #define CINT1FLAG 0x00400
175 #define CINT2FLAG 0x00800
176 #define CINT3FLAG 0x01000
177 #define CINT4FLAG 0x02000
178 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
179 #define CINT5FLAG 0x20000 /* DSP only */
183 #define ZERO_FLAG 0x00001
184 #define CARRY_FLAG 0x00002
185 #define NEGA_FLAG 0x00004
186 #define IMASK 0x00008
187 #define INT_ENA0 0x00010
188 #define INT_ENA1 0x00020
189 #define INT_ENA2 0x00040
190 #define INT_ENA3 0x00080
191 #define INT_ENA4 0x00100
192 #define INT_CLR0 0x00200
193 #define INT_CLR1 0x00400
194 #define INT_CLR2 0x00800
195 #define INT_CLR3 0x01000
196 #define INT_CLR4 0x02000
197 #define REGPAGE 0x04000
198 #define DMAEN 0x08000
199 #define INT_ENA5 0x10000
200 #define INT_CLR5 0x20000
204 #define DSPGO 0x00001
205 #define CPUINT 0x00002
206 #define DSPINT0 0x00004
207 #define SINGLE_STEP 0x00008
208 #define SINGLE_GO 0x00010
210 #define INT_LAT0 0x00040
211 #define INT_LAT1 0x00080
212 #define INT_LAT2 0x00100
213 #define INT_LAT3 0x00200
214 #define INT_LAT4 0x00400
215 #define BUS_HOG 0x00800
216 #define VERSION 0x0F000
217 #define INT_LAT5 0x10000
219 extern uint32 jaguar_mainRom_crc32;
221 // Is opcode 62 *really* a NOP? Seems like it...
222 static void dsp_opcode_abs(void);
223 static void dsp_opcode_add(void);
224 static void dsp_opcode_addc(void);
225 static void dsp_opcode_addq(void);
226 static void dsp_opcode_addqmod(void);
227 static void dsp_opcode_addqt(void);
228 static void dsp_opcode_and(void);
229 static void dsp_opcode_bclr(void);
230 static void dsp_opcode_bset(void);
231 static void dsp_opcode_btst(void);
232 static void dsp_opcode_cmp(void);
233 static void dsp_opcode_cmpq(void);
234 static void dsp_opcode_div(void);
235 static void dsp_opcode_imacn(void);
236 static void dsp_opcode_imult(void);
237 static void dsp_opcode_imultn(void);
238 static void dsp_opcode_jr(void);
239 static void dsp_opcode_jump(void);
240 static void dsp_opcode_load(void);
241 static void dsp_opcode_loadb(void);
242 static void dsp_opcode_loadw(void);
243 static void dsp_opcode_load_r14_indexed(void);
244 static void dsp_opcode_load_r14_ri(void);
245 static void dsp_opcode_load_r15_indexed(void);
246 static void dsp_opcode_load_r15_ri(void);
247 static void dsp_opcode_mirror(void);
248 static void dsp_opcode_mmult(void);
249 static void dsp_opcode_move(void);
250 static void dsp_opcode_movei(void);
251 static void dsp_opcode_movefa(void);
252 static void dsp_opcode_move_pc(void);
253 static void dsp_opcode_moveq(void);
254 static void dsp_opcode_moveta(void);
255 static void dsp_opcode_mtoi(void);
256 static void dsp_opcode_mult(void);
257 static void dsp_opcode_neg(void);
258 static void dsp_opcode_nop(void);
259 static void dsp_opcode_normi(void);
260 static void dsp_opcode_not(void);
261 static void dsp_opcode_or(void);
262 static void dsp_opcode_resmac(void);
263 static void dsp_opcode_ror(void);
264 static void dsp_opcode_rorq(void);
265 static void dsp_opcode_xor(void);
266 static void dsp_opcode_sat16s(void);
267 static void dsp_opcode_sat32s(void);
268 static void dsp_opcode_sh(void);
269 static void dsp_opcode_sha(void);
270 static void dsp_opcode_sharq(void);
271 static void dsp_opcode_shlq(void);
272 static void dsp_opcode_shrq(void);
273 static void dsp_opcode_store(void);
274 static void dsp_opcode_storeb(void);
275 static void dsp_opcode_storew(void);
276 static void dsp_opcode_store_r14_indexed(void);
277 static void dsp_opcode_store_r14_ri(void);
278 static void dsp_opcode_store_r15_indexed(void);
279 static void dsp_opcode_store_r15_ri(void);
280 static void dsp_opcode_sub(void);
281 static void dsp_opcode_subc(void);
282 static void dsp_opcode_subq(void);
283 static void dsp_opcode_subqmod(void);
284 static void dsp_opcode_subqt(void);
286 uint8 dsp_opcode_cycles[64] =
288 3, 3, 3, 3, 3, 3, 3, 3,
289 3, 3, 3, 3, 3, 3, 3, 3,
290 3, 3, 1, 3, 1, 18, 3, 3,
291 3, 3, 3, 3, 3, 3, 3, 3,
292 3, 3, 2, 2, 2, 2, 3, 4,
293 5, 4, 5, 6, 6, 1, 1, 1,
294 1, 2, 2, 2, 1, 1, 9, 3,
295 3, 1, 6, 6, 2, 2, 3, 3
297 //Here's a QnD kludge...
298 //This is wrong, wrong, WRONG, but it seems to work for the time being...
299 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
300 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
301 /*uint8 dsp_opcode_cycles[64] =
303 1, 1, 1, 1, 1, 1, 1, 1,
304 1, 1, 1, 1, 1, 1, 1, 1,
305 1, 1, 1, 1, 1, 9, 1, 1,
306 1, 1, 1, 1, 1, 1, 1, 1,
307 1, 1, 1, 1, 1, 1, 1, 2,
308 2, 2, 2, 3, 3, 1, 1, 1,
309 1, 1, 1, 1, 1, 1, 4, 1,
310 1, 1, 3, 3, 1, 1, 1, 1
313 void (* dsp_opcode[64])() =
315 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
316 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
317 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
318 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
319 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
320 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
321 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
322 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
323 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
324 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
325 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
326 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
327 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
328 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
329 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
330 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
333 uint32 dsp_opcode_use[65];
335 char * dsp_opcode_str[65]=
337 "add", "addc", "addq", "addqt",
338 "sub", "subc", "subq", "subqt",
339 "neg", "and", "or", "xor",
340 "not", "btst", "bset", "bclr",
341 "mult", "imult", "imultn", "resmac",
342 "imacn", "div", "abs", "sh",
343 "shlq", "shrq", "sha", "sharq",
344 "ror", "rorq", "cmp", "cmpq",
345 "subqmod", "sat16s", "move", "moveq",
346 "moveta", "movefa", "movei", "loadb",
347 "loadw", "load", "sat32s", "load_r14_indexed",
348 "load_r15_indexed", "storeb", "storew", "store",
349 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
350 "jump", "jr", "mmult", "mtoi",
351 "normi", "nop", "load_r14_ri", "load_r15_ri",
352 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
357 static uint64 dsp_acc; // 40 bit register, NOT 32!
358 static uint32 dsp_remain;
359 static uint32 dsp_modulo;
360 static uint32 dsp_flags;
361 static uint32 dsp_matrix_control;
362 static uint32 dsp_pointer_to_matrix;
363 static uint32 dsp_data_organization;
365 static uint32 dsp_div_control;
366 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
367 static uint32 * dsp_reg, * dsp_alternate_reg;
368 static uint32 * dsp_reg_bank_0, * dsp_reg_bank_1;
370 static uint32 dsp_opcode_first_parameter;
371 static uint32 dsp_opcode_second_parameter;
373 #define DSP_RUNNING (dsp_control & 0x01)
375 #define RM dsp_reg[dsp_opcode_first_parameter]
376 #define RN dsp_reg[dsp_opcode_second_parameter]
377 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
378 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
379 #define IMM_1 dsp_opcode_first_parameter
380 #define IMM_2 dsp_opcode_second_parameter
382 #define CLR_Z (dsp_flag_z = 0)
383 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
384 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
385 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
386 #define SET_N(r) (dsp_flag_n = (((UINT32)(r) >> 31) & 0x01))
387 #define SET_C_ADD(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(~(a))))
388 #define SET_C_SUB(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(a)))
389 #define SET_ZN(r) SET_N(r); SET_Z(r)
390 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
391 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
393 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 };
394 uint8 * dsp_branch_condition_table = NULL;
395 static uint16 * mirror_table = NULL;
396 static uint8 * dsp_ram_8 = NULL;
398 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
400 static uint32 dsp_in_exec = 0;
401 static uint32 dsp_releaseTimeSlice_flag = 0;
406 // Comparison core vars (used only for core comparison! :-)
407 static uint64 count = 0;
408 static uint8 ram1[0x2000], ram2[0x2000];
409 static uint32 regs1[64], regs2[64];
410 static uint32 ctrl1[14], ctrl2[14];
413 // Private function prototypes
415 void DSPDumpRegisters(void);
416 void DSPDumpDisassembly(void);
417 void FlushDSPPipeline(void);
420 void dsp_reset_stats(void)
422 for(int i=0; i<65; i++)
423 dsp_opcode_use[i] = 0;
426 void dsp_releaseTimeslice(void)
428 //This does absolutely nothing!!! !!! FIX !!!
429 dsp_releaseTimeSlice_flag = 1;
432 void dsp_build_branch_condition_table(void)
434 // Allocate the mirror table
436 mirror_table = (uint16 *)malloc(65536 * sizeof(mirror_table[0]));
438 // Fill in the mirror table
440 for(int i=0; i<65536; i++)
441 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
442 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
443 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
444 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
445 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
446 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
447 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
448 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
450 if (!dsp_branch_condition_table)
452 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(dsp_branch_condition_table[0]));
454 // Fill in the condition table
455 if (dsp_branch_condition_table)
457 for(int i=0; i<8; i++)
459 for(int j=0; j<32; j++)
466 if (!(i & ZERO_FLAG))
469 if (i & (CARRY_FLAG << (j >> 4)))
472 if (!(i & (CARRY_FLAG << (j >> 4))))
474 dsp_branch_condition_table[i * 32 + j] = result;
481 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
483 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
484 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
486 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
489 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
491 if (offset==0xF1CFE0)
494 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
495 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
497 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
499 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
501 if ((offset&0x03)==0)
504 if ((offset&0x03)==1)
505 return((data>>16)&0xff);
507 if ((offset&0x03)==2)
508 return((data>>8)&0xff);
510 if ((offset&0x03)==3)
514 return JaguarReadByte(offset, who);
517 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
519 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
520 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
522 offset &= 0xFFFFFFFE;
524 /* if (jaguar_mainRom_crc32==0xa74a97cd)
526 if (offset==0xF1A114) return(0x0000);
527 if (offset==0xF1A116) return(0x0000);
528 if (offset==0xF1B000) return(0x1234);
529 if (offset==0xF1B002) return(0x5678);
532 if (jaguar_mainRom_crc32==0x7ae20823)
534 if (offset==0xF1B9D8) return(0x0000);
535 if (offset==0xF1B9Da) return(0x0000);
536 if (offset==0xF1B2C0) return(0x0000);
537 if (offset==0xF1B2C2) return(0x0000);
540 // pour permettre à wolfenstein 3d de tourner sans le dsp
541 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
545 // pour permettre à nba jam de tourner sans le dsp
546 /* if (jaguar_mainRom_crc32==0x4faddb18)
548 if (offset==0xf1b2c0) return(0);
549 if (offset==0xf1b2c2) return(0);
550 if (offset==0xf1b240) return(0);
551 if (offset==0xf1b242) return(0);
552 if (offset==0xF1B340) return(0);
553 if (offset==0xF1B342) return(0);
554 if (offset==0xF1BAD8) return(0);
555 if (offset==0xF1BADA) return(0);
556 if (offset==0xF1B040) return(0);
557 if (offset==0xF1B042) return(0);
558 if (offset==0xF1B0C0) return(0);
559 if (offset==0xF1B0C2) return(0);
560 if (offset==0xF1B140) return(0);
561 if (offset==0xF1B142) return(0);
562 if (offset==0xF1B1C0) return(0);
563 if (offset==0xF1B1C2) return(0);
566 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
568 offset -= DSP_WORK_RAM_BASE;
569 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
571 return GET16(dsp_ram_8, offset);
573 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
575 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
578 return data & 0xFFFF;
583 return JaguarReadWord(offset, who);
586 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
588 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
589 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
592 offset &= 0xFFFFFFFC;
593 /*if (offset == 0xF1BCF4)
595 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));
596 DSPDumpDisassembly();
598 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
600 offset -= DSP_WORK_RAM_BASE;
601 return GET32(dsp_ram_8, offset);
603 //NOTE: Didn't return DSP_ACCUM!!!
604 //Mebbe it's not 'spose to! Yes, it is!
605 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
610 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
611 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
612 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
614 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
615 return dsp_flags & 0xFFFFC1FF;
616 case 0x04: return dsp_matrix_control;
617 case 0x08: return dsp_pointer_to_matrix;
618 case 0x0C: return dsp_data_organization;
619 case 0x10: return dsp_pc;
620 case 0x14: return dsp_control;
621 case 0x18: return dsp_modulo;
622 case 0x1C: return dsp_remain;
624 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
626 // unaligned long read-- !!! FIX !!!
630 return JaguarReadLong(offset, who);
633 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
635 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
636 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
638 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
640 offset -= DSP_WORK_RAM_BASE;
641 dsp_ram_8[offset] = data;
642 //This is rather stupid! !!! FIX !!!
643 /* if (dsp_in_exec == 0)
645 m68k_end_timeslice();
646 gpu_releaseTimeslice();
650 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
652 uint32 reg = offset & 0x1C;
653 int bytenum = offset & 0x03;
655 if ((reg >= 0x1C) && (reg <= 0x1F))
656 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
659 //This looks funky. !!! FIX !!!
660 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
661 bytenum = 3 - bytenum; // convention motorola !!!
662 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
663 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
667 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
668 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
669 JaguarWriteByte(offset, data, who);
672 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
674 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
675 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
676 offset &= 0xFFFFFFFE;
677 /*if (offset == 0xF1BCF4)
679 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
681 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
682 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
684 /*if (offset == 0xF1B2F4)
686 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
688 offset -= DSP_WORK_RAM_BASE;
689 dsp_ram_8[offset] = data >> 8;
690 dsp_ram_8[offset+1] = data & 0xFF;
691 //This is rather stupid! !!! FIX !!!
692 /* if (dsp_in_exec == 0)
694 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
695 m68k_end_timeslice();
696 gpu_releaseTimeslice();
700 SET16(ram1, offset, data),
701 SET16(ram2, offset, data);
706 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
708 if ((offset & 0x1C) == 0x1C)
711 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
713 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
717 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
719 old_data = (old_data&0xffff0000)|(data&0xffff);
721 old_data = (old_data&0xffff)|((data&0xffff)<<16);
722 DSPWriteLong(offset & 0xffffffc, old_data, who);
727 JaguarWriteWord(offset, data, who);
730 //bool badWrite = false;
731 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
733 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
734 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
736 offset &= 0xFFFFFFFC;
737 /*if (offset == 0xF1BCF4)
739 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
741 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
742 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
744 /*if (offset == 0xF1BE2C)
746 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
748 offset -= DSP_WORK_RAM_BASE;
749 SET32(dsp_ram_8, offset, data);
752 SET32(ram1, offset, data),
753 SET32(ram2, offset, data);
758 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
766 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
768 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
769 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
771 dsp_flag_z = dsp_flags & 0x01;
772 dsp_flag_c = (dsp_flags >> 1) & 0x01;
773 dsp_flag_n = (dsp_flags >> 2) & 0x01;
774 DSPUpdateRegisterBanks();
775 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
776 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
777 /* if (IMASKCleared) // If IMASK was cleared,
780 WriteLog("DSP: Finished interrupt.\n");
782 DSPHandleIRQs(); // see if any other interrupts need servicing!
787 if (/*4-8, 16*/data & 0x101F0)
788 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
789 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
790 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
791 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
792 /*if (data & 0x00020) // CD BIOS DSP code...
794 //001AC1BA: movea.l #$1AC200, A0
795 //001AC1C0: move.l #$1AC68C, D0
798 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
799 uint32 j = 0xF1B97C;//0x1AC200;
800 while (j <= 0xF1BE08)//0x1AC68C)
803 j += dasmjag(JAGUAR_DSP, buffer, j);
804 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
805 WriteLog("\t%08X: %s\n", oldj, buffer);
812 dsp_matrix_control = data;
815 // According to JTRM, only lines 2-11 are addressable, the rest being
816 // hardwired to $F1Bxxx.
817 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
820 dsp_data_organization = data;
825 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
830 ctrl1[0] = ctrl2[0] = data;
837 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
839 bool wasRunning = DSP_RUNNING;
840 // uint32 dsp_was_running = DSP_RUNNING;
841 // Check for DSP -> CPU interrupt
845 WriteLog("DSP: DSP -> CPU interrupt\n");
848 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
849 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
851 JERRYSetPendingIRQ(IRQ2_DSP);
852 dsp_releaseTimeslice();
853 m68k_set_irq(7); // Set 68000 NMI...
857 // Check for CPU -> DSP interrupt
861 WriteLog("DSP: CPU -> DSP interrupt\n");
863 m68k_end_timeslice();
864 gpu_releaseTimeslice();
865 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
869 if (data & SINGLE_STEP)
871 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
874 // Protect writes to VERSION and the interrupt latches...
875 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
876 dsp_control = (dsp_control & mask) | (data & ~mask);
880 ctrl1[8] = ctrl2[8] = dsp_control;
884 // if dsp wasn't running but is now running
885 // execute a few cycles
886 //This is just plain wrong, wrong, WRONG!
887 #ifndef DSP_SINGLE_STEPPING
888 /* if (!dsp_was_running && DSP_RUNNING)
893 //This is WRONG! !!! FIX !!!
894 if (dsp_control & 0x18)
899 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
901 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
904 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
905 // !!! FIX !!! [DONE]
909 m68k_end_timeslice();
911 gpu_releaseTimeslice();
915 //DSPDumpDisassembly();
923 dsp_div_control = data;
925 // default: // unaligned long read
931 //We don't have to break this up like this! We CAN do 32 bit writes!
932 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
933 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
934 //if (offset > 0xF1FFFF)
936 JaguarWriteLong(offset, data, who);
940 // Update the DSP register file pointers depending on REGPAGE bit
942 void DSPUpdateRegisterBanks(void)
944 int bank = (dsp_flags & REGPAGE);
946 if (dsp_flags & IMASK)
947 bank = 0; // IMASK forces main bank to be bank 0
950 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
952 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
956 // Check for and handle any asserted DSP IRQs
958 void DSPHandleIRQs(void)
960 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
963 // Get the active interrupt bits (latches) & interrupt mask (enables)
964 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
965 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
967 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
970 if (!bits) // Bail if nothing is enabled
973 int which = 0; // Determine which interrupt
988 WriteLog("DSP: Generating interrupt #%i...", which);
991 //if (which == 0) doDSPDis = true;
993 // NOTE: Since the actual Jaguar hardware injects the code sequence below
994 // directly into the pipeline, it has the side effect of ensuring that the
995 // instruction interrupted also gets to do its writeback. We simulate that
997 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
999 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1000 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1002 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1003 scoreboard[pipeline[plPtrWrite].operand2] = false;
1005 //This should be execute (or should it?--not sure now!)
1006 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1007 //and what just executed is now in the Write position...). So why didn't it do the
1008 //writeback into register 0?
1009 #ifdef DSP_DEBUG_IRQ
1010 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1011 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]);
1012 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]);
1013 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]);
1015 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1017 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1019 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1020 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1023 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1024 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1025 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1026 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1028 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1032 #ifndef NEW_SCOREBOARD
1033 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1034 scoreboard[pipeline[plPtrWrite].operand2] = false;
1036 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1037 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1038 if (scoreboard[pipeline[plPtrWrite].operand2])
1039 scoreboard[pipeline[plPtrWrite].operand2]--;
1046 ctrl2[4] = dsp_flags;
1049 DSPUpdateRegisterBanks();
1050 #ifdef DSP_DEBUG_IRQ
1051 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1052 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]);
1055 // subqt #4,r31 ; pre-decrement stack pointer
1056 // move pc,r30 ; address of interrupted code
1057 // store r30,(r31) ; store return address
1064 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1065 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1066 //It missed the place that it was supposed to come back to, so this is WRONG!
1068 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1070 // R -> baz (<- PC points here)
1071 // E -> bar (when it should point here!)
1074 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1075 // which means (assuming they're all 2 bytes long) that the code below will come back on
1076 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1077 // instruction stream...
1079 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1080 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1083 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1087 // movei #service_address,r30 ; pointer to ISR entry
1088 // jump (r30) ; jump to ISR
1090 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1093 ctrl2[0] = regs2[30] = dsp_pc;
1100 // Non-pipelined version...
1102 void DSPHandleIRQsNP(void)
1106 memcpy(dsp_ram_8, ram1, 0x2000);
1107 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1108 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1111 dsp_remain = ctrl1[2];
1112 dsp_modulo = ctrl1[3];
1113 dsp_flags = ctrl1[4];
1114 dsp_matrix_control = ctrl1[5];
1115 dsp_pointer_to_matrix = ctrl1[6];
1116 dsp_data_organization = ctrl1[7];
1117 dsp_control = ctrl1[8];
1118 dsp_div_control = ctrl1[9];
1119 IMASKCleared = ctrl1[10];
1120 dsp_flag_z = ctrl1[11];
1121 dsp_flag_n = ctrl1[12];
1122 dsp_flag_c = ctrl1[13];
1123 DSPUpdateRegisterBanks();
1126 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1129 // Get the active interrupt bits (latches) & interrupt mask (enables)
1130 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1131 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1133 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1136 if (!bits) // Bail if nothing is enabled
1139 int which = 0; // Determine which interrupt
1153 #ifdef DSP_DEBUG_IRQ
1154 WriteLog("DSP: Generating interrupt #%i...", which);
1160 ctrl1[4] = dsp_flags;
1163 DSPUpdateRegisterBanks();
1164 #ifdef DSP_DEBUG_IRQ
1165 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1168 // subqt #4,r31 ; pre-decrement stack pointer
1169 // move pc,r30 ; address of interrupted code
1170 // store r30,(r31) ; store return address
1177 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1180 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1184 // movei #service_address,r30 ; pointer to ISR entry
1185 // jump (r30) ; jump to ISR
1187 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1190 ctrl1[0] = regs1[30] = dsp_pc;
1196 // Set the specified DSP IRQ line to a given state
1198 void DSPSetIRQLine(int irqline, int state)
1200 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1201 uint32 mask = INT_LAT0 << irqline;
1202 dsp_control &= ~mask; // Clear the latch bit
1205 ctrl1[8] = ctrl2[8] = dsp_control;
1211 dsp_control |= mask; // Set the latch bit
1215 ctrl1[8] = ctrl2[8] = dsp_control;
1221 // Not sure if this is correct behavior, but according to JTRM,
1222 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1223 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1224 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1229 memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1230 memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1231 memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1233 dsp_build_branch_condition_table();
1239 dsp_pc = 0x00F1B000;
1240 dsp_acc = 0x00000000;
1241 dsp_remain = 0x00000000;
1242 dsp_modulo = 0xFFFFFFFF;
1243 dsp_flags = 0x00040000;
1244 dsp_matrix_control = 0x00000000;
1245 dsp_pointer_to_matrix = 0x00000000;
1246 dsp_data_organization = 0xFFFFFFFF;
1247 dsp_control = 0x00002000; // Report DSP version 2
1248 dsp_div_control = 0x00000000;
1251 dsp_reg = dsp_reg_bank_0;
1252 dsp_alternate_reg = dsp_reg_bank_1;
1254 for(int i=0; i<32; i++)
1255 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1258 IMASKCleared = false;
1261 memset(dsp_ram_8, 0xFF, 0x2000);
1264 void DSPDumpDisassembly(void)
1268 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1269 uint32 j = 0xF1B000;
1270 while (j <= 0xF1CFFF)
1273 j += dasmjag(JAGUAR_DSP, buffer, j);
1274 WriteLog("\t%08X: %s\n", oldj, buffer);
1278 void DSPDumpRegisters(void)
1280 //Shoud add modulus, etc to dump here...
1281 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1282 WriteLog("\nRegisters bank 0\n");
1283 for(int j=0; j<8; j++)
1285 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1286 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1287 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1288 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1289 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1291 WriteLog("Registers bank 1\n");
1292 for(int j=0; j<8; j++)
1294 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1295 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1296 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1297 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1298 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1305 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1306 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1308 // get the active interrupt bits
1309 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1310 // get the interrupt mask
1311 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1313 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1314 WriteLog("\nRegisters bank 0\n");
1315 for(int j=0; j<8; j++)
1317 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1318 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1319 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1320 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1321 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1323 WriteLog("\nRegisters bank 1\n");
1326 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1327 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1328 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1329 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1330 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1334 static char buffer[512];
1335 j = DSP_WORK_RAM_BASE;
1336 while (j <= 0xF1BFFF)
1339 j += dasmjag(JAGUAR_DSP, buffer, j);
1340 WriteLog("\t%08X: %s\n", oldj, buffer);
1343 WriteLog("DSP opcodes use:\n");
1346 if (dsp_opcode_use[i])
1347 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1350 memory_free(dsp_ram_8);
1351 memory_free(dsp_reg_bank_0);
1352 memory_free(dsp_reg_bank_1);
1358 // DSP comparison core...
1361 static uint16 lastExec;
1362 void DSPExecComp(int32 cycles)
1364 while (cycles > 0 && DSP_RUNNING)
1366 // Load up vars for non-pipelined core
1367 memcpy(dsp_ram_8, ram1, 0x2000);
1368 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1369 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1372 dsp_remain = ctrl1[2];
1373 dsp_modulo = ctrl1[3];
1374 dsp_flags = ctrl1[4];
1375 dsp_matrix_control = ctrl1[5];
1376 dsp_pointer_to_matrix = ctrl1[6];
1377 dsp_data_organization = ctrl1[7];
1378 dsp_control = ctrl1[8];
1379 dsp_div_control = ctrl1[9];
1380 IMASKCleared = ctrl1[10];
1381 dsp_flag_z = ctrl1[11];
1382 dsp_flag_n = ctrl1[12];
1383 dsp_flag_c = ctrl1[13];
1384 DSPUpdateRegisterBanks();
1386 // Decrement cycles based on non-pipelined core...
1387 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1388 cycles -= dsp_opcode_cycles[instr1 >> 10];
1390 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1391 DSPExec(1); // Do *one* instruction
1394 memcpy(ram1, dsp_ram_8, 0x2000);
1395 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1396 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1399 ctrl1[2] = dsp_remain;
1400 ctrl1[3] = dsp_modulo;
1401 ctrl1[4] = dsp_flags;
1402 ctrl1[5] = dsp_matrix_control;
1403 ctrl1[6] = dsp_pointer_to_matrix;
1404 ctrl1[7] = dsp_data_organization;
1405 ctrl1[8] = dsp_control;
1406 ctrl1[9] = dsp_div_control;
1407 ctrl1[10] = IMASKCleared;
1408 ctrl1[11] = dsp_flag_z;
1409 ctrl1[12] = dsp_flag_n;
1410 ctrl1[13] = dsp_flag_c;
1412 // Load up vars for pipelined core
1413 memcpy(dsp_ram_8, ram2, 0x2000);
1414 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1415 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1418 dsp_remain = ctrl2[2];
1419 dsp_modulo = ctrl2[3];
1420 dsp_flags = ctrl2[4];
1421 dsp_matrix_control = ctrl2[5];
1422 dsp_pointer_to_matrix = ctrl2[6];
1423 dsp_data_organization = ctrl2[7];
1424 dsp_control = ctrl2[8];
1425 dsp_div_control = ctrl2[9];
1426 IMASKCleared = ctrl2[10];
1427 dsp_flag_z = ctrl2[11];
1428 dsp_flag_n = ctrl2[12];
1429 dsp_flag_c = ctrl2[13];
1430 DSPUpdateRegisterBanks();
1432 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1433 DSPExecP2(1); // Do *one* instruction
1436 memcpy(ram2, dsp_ram_8, 0x2000);
1437 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1438 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1441 ctrl2[2] = dsp_remain;
1442 ctrl2[3] = dsp_modulo;
1443 ctrl2[4] = dsp_flags;
1444 ctrl2[5] = dsp_matrix_control;
1445 ctrl2[6] = dsp_pointer_to_matrix;
1446 ctrl2[7] = dsp_data_organization;
1447 ctrl2[8] = dsp_control;
1448 ctrl2[9] = dsp_div_control;
1449 ctrl2[10] = IMASKCleared;
1450 ctrl2[11] = dsp_flag_z;
1451 ctrl2[12] = dsp_flag_n;
1452 ctrl2[13] = dsp_flag_c;
1454 if (instr1 != lastExec)
1456 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1458 // 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));
1459 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1460 // if (ctrl1[0] < ppc) // P ran ahead of NP
1461 //How to test this crap???
1464 DSPExecP2(1); // Do one more instruction
1467 memcpy(ram2, dsp_ram_8, 0x2000);
1468 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1469 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1472 ctrl2[2] = dsp_remain;
1473 ctrl2[3] = dsp_modulo;
1474 ctrl2[4] = dsp_flags;
1475 ctrl2[5] = dsp_matrix_control;
1476 ctrl2[6] = dsp_pointer_to_matrix;
1477 ctrl2[7] = dsp_data_organization;
1478 ctrl2[8] = dsp_control;
1479 ctrl2[9] = dsp_div_control;
1480 ctrl2[10] = IMASKCleared;
1481 ctrl2[11] = dsp_flag_z;
1482 ctrl2[12] = dsp_flag_n;
1483 ctrl2[13] = dsp_flag_c;
1485 // else // NP ran ahead of P
1486 if (instr1 != lastExec) // Must be the other way...
1489 // Load up vars for non-pipelined core
1490 memcpy(dsp_ram_8, ram1, 0x2000);
1491 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1492 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1495 dsp_remain = ctrl1[2];
1496 dsp_modulo = ctrl1[3];
1497 dsp_flags = ctrl1[4];
1498 dsp_matrix_control = ctrl1[5];
1499 dsp_pointer_to_matrix = ctrl1[6];
1500 dsp_data_organization = ctrl1[7];
1501 dsp_control = ctrl1[8];
1502 dsp_div_control = ctrl1[9];
1503 IMASKCleared = ctrl1[10];
1504 dsp_flag_z = ctrl1[11];
1505 dsp_flag_n = ctrl1[12];
1506 dsp_flag_c = ctrl1[13];
1507 DSPUpdateRegisterBanks();
1509 for(int k=0; k<2; k++)
1511 // Decrement cycles based on non-pipelined core...
1512 instr1 = DSPReadWord(dsp_pc, DSP);
1513 cycles -= dsp_opcode_cycles[instr1 >> 10];
1515 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1516 DSPExec(1); // Do *one* instruction
1520 memcpy(ram1, dsp_ram_8, 0x2000);
1521 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1522 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1525 ctrl1[2] = dsp_remain;
1526 ctrl1[3] = dsp_modulo;
1527 ctrl1[4] = dsp_flags;
1528 ctrl1[5] = dsp_matrix_control;
1529 ctrl1[6] = dsp_pointer_to_matrix;
1530 ctrl1[7] = dsp_data_organization;
1531 ctrl1[8] = dsp_control;
1532 ctrl1[9] = dsp_div_control;
1533 ctrl1[10] = IMASKCleared;
1534 ctrl1[11] = dsp_flag_z;
1535 ctrl1[12] = dsp_flag_n;
1536 ctrl1[13] = dsp_flag_c;
1540 if (instr1 != lastExec)
1542 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1544 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1545 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1558 // DSP execution core
1560 //static bool R20Set = false, tripwire = false;
1561 //static uint32 pcQueue[32], ptrPCQ = 0;
1562 void DSPExec(int32 cycles)
1564 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1565 dsp_check_if_i2s_interrupt_needed();*/
1567 #ifdef DSP_SINGLE_STEPPING
1568 if (dsp_control & 0x18)
1571 dsp_control &= ~0x10;
1574 //There is *no* good reason to do this here!
1576 dsp_releaseTimeSlice_flag = 0;
1579 while (cycles > 0 && DSP_RUNNING)
1581 /*extern uint32 totalFrames;
1582 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1583 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1584 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1586 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1589 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1591 if (dsp_pc == 0xF1B092)
1592 doDSPDis = false;//*/
1593 /*if (dsp_pc == 0xF1B140)
1594 doDSPDis = true;//*/
1596 if (IMASKCleared) // If IMASK was cleared,
1598 #ifdef DSP_DEBUG_IRQ
1599 WriteLog("DSP: Finished interrupt.\n");
1601 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1602 IMASKCleared = false;
1607 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1608 for(int i=0; i<80; i+=4)
1609 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1612 /*if (dsp_pc == 0xF1B55E)
1614 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1616 /*if (dsp_pc == 0xF1B7D2) // Start here???
1618 pcQueue[ptrPCQ++] = dsp_pc;
1620 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1621 uint32 index = opcode >> 10;
1622 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1623 dsp_opcode_second_parameter = opcode & 0x1F;
1625 dsp_opcode[index]();
1626 dsp_opcode_use[index]++;
1627 cycles -= dsp_opcode_cycles[index];
1628 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1630 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1633 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1635 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1637 DSPDumpDisassembly();
1640 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1643 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1646 WriteLog("\nBacktrace:\n");
1647 for(int i=0; i<32; i++)
1649 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1650 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1660 // DSP opcode handlers
1663 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1664 // can cause trouble because an interrupt can occur *before* the instruction following the
1665 // jump can execute... !!! FIX !!!
1666 static void dsp_opcode_jump(void)
1669 char * condition[32] =
1670 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1671 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1672 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1673 "???", "???", "???", "F" };
1675 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);
1678 /* dsp_flag_c=dsp_flag_c?1:0;
1679 dsp_flag_z=dsp_flag_z?1:0;
1680 dsp_flag_n=dsp_flag_n?1:0;*/
1681 // KLUDGE: Used by BRANCH_CONDITION
1682 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1684 if (BRANCH_CONDITION(IMM_2))
1688 WriteLog("Branched!\n");
1690 uint32 delayed_pc = RM;
1692 dsp_pc = delayed_pc;
1697 WriteLog("Branch NOT taken.\n");
1701 static void dsp_opcode_jr(void)
1704 char * condition[32] =
1705 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1706 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1707 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1708 "???", "???", "???", "F" };
1710 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);
1713 /* dsp_flag_c=dsp_flag_c?1:0;
1714 dsp_flag_z=dsp_flag_z?1:0;
1715 dsp_flag_n=dsp_flag_n?1:0;*/
1716 // KLUDGE: Used by BRANCH_CONDITION
1717 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1719 if (BRANCH_CONDITION(IMM_2))
1723 WriteLog("Branched!\n");
1725 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1726 int32 delayed_pc = dsp_pc + (offset * 2);
1728 dsp_pc = delayed_pc;
1733 WriteLog("Branch NOT taken.\n");
1737 static void dsp_opcode_add(void)
1741 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);
1743 UINT32 res = RN + RM;
1744 SET_ZNC_ADD(RN, RM, res);
1748 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);
1752 static void dsp_opcode_addc(void)
1756 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);
1758 UINT32 res = RN + RM + dsp_flag_c;
1759 UINT32 carry = dsp_flag_c;
1760 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1761 SET_ZNC_ADD(RN + carry, RM, res);
1762 // SET_ZNC_ADD(RN, RM + carry, res);
1766 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);
1770 static void dsp_opcode_addq(void)
1774 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);
1776 UINT32 r1 = dsp_convert_zero[IMM_1];
1777 UINT32 res = RN + r1;
1778 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1782 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1786 static void dsp_opcode_sub(void)
1790 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);
1792 UINT32 res = RN - RM;
1793 SET_ZNC_SUB(RN, RM, res);
1797 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);
1801 static void dsp_opcode_subc(void)
1805 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);
1807 UINT32 res = RN - RM - dsp_flag_c;
1808 UINT32 borrow = dsp_flag_c;
1809 SET_ZNC_SUB(RN - borrow, RM, res);
1813 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);
1817 static void dsp_opcode_subq(void)
1821 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);
1823 UINT32 r1 = dsp_convert_zero[IMM_1];
1824 UINT32 res = RN - r1;
1825 SET_ZNC_SUB(RN, r1, res);
1829 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1833 static void dsp_opcode_cmp(void)
1837 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);
1839 UINT32 res = RN - RM;
1840 SET_ZNC_SUB(RN, RM, res);
1843 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1847 static void dsp_opcode_cmpq(void)
1849 static int32 sqtable[32] =
1850 { 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 };
1853 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);
1855 UINT32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1856 UINT32 res = RN - r1;
1857 SET_ZNC_SUB(RN, r1, res);
1860 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1864 static void dsp_opcode_and(void)
1868 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);
1874 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);
1878 static void dsp_opcode_or(void)
1882 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);
1888 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1892 static void dsp_opcode_xor(void)
1896 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);
1902 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1906 static void dsp_opcode_not(void)
1910 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1916 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1920 static void dsp_opcode_move_pc(void)
1925 static void dsp_opcode_store_r14_indexed(void)
1927 #ifdef DSP_DIS_STORE14I
1929 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));
1931 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1934 static void dsp_opcode_store_r15_indexed(void)
1936 #ifdef DSP_DIS_STORE15I
1938 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));
1940 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1943 static void dsp_opcode_load_r14_ri(void)
1945 #ifdef DSP_DIS_LOAD14R
1947 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);
1949 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1950 #ifdef DSP_DIS_LOAD14R
1952 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1956 static void dsp_opcode_load_r15_ri(void)
1958 #ifdef DSP_DIS_LOAD15R
1960 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);
1962 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1963 #ifdef DSP_DIS_LOAD15R
1965 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1969 static void dsp_opcode_store_r14_ri(void)
1971 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1974 static void dsp_opcode_store_r15_ri(void)
1976 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1979 static void dsp_opcode_nop(void)
1983 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1987 static void dsp_opcode_storeb(void)
1989 #ifdef DSP_DIS_STOREB
1991 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);
1993 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1994 DSPWriteLong(RM, RN & 0xFF, DSP);
1996 JaguarWriteByte(RM, RN, DSP);
1999 static void dsp_opcode_storew(void)
2001 #ifdef DSP_DIS_STOREW
2003 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);
2005 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2006 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2008 JaguarWriteWord(RM, RN, DSP);
2011 static void dsp_opcode_store(void)
2013 #ifdef DSP_DIS_STORE
2015 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);
2017 DSPWriteLong(RM, RN, DSP);
2020 static void dsp_opcode_loadb(void)
2022 #ifdef DSP_DIS_LOADB
2024 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);
2026 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2027 RN = DSPReadLong(RM, DSP) & 0xFF;
2029 RN = JaguarReadByte(RM, DSP);
2030 #ifdef DSP_DIS_LOADB
2032 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2036 static void dsp_opcode_loadw(void)
2038 #ifdef DSP_DIS_LOADW
2040 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);
2042 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2043 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2045 RN = JaguarReadWord(RM, DSP);
2046 #ifdef DSP_DIS_LOADW
2048 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2052 static void dsp_opcode_load(void)
2056 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);
2058 RN = DSPReadLong(RM, DSP);
2061 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2065 static void dsp_opcode_load_r14_indexed(void)
2067 #ifdef DSP_DIS_LOAD14I
2069 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);
2071 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2072 #ifdef DSP_DIS_LOAD14I
2074 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2078 static void dsp_opcode_load_r15_indexed(void)
2080 #ifdef DSP_DIS_LOAD15I
2082 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);
2084 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2085 #ifdef DSP_DIS_LOAD15I
2087 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2091 static void dsp_opcode_movei(void)
2093 #ifdef DSP_DIS_MOVEI
2095 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);
2097 // This instruction is followed by 32-bit value in LSW / MSW format...
2098 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2100 #ifdef DSP_DIS_MOVEI
2102 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2106 static void dsp_opcode_moveta(void)
2108 #ifdef DSP_DIS_MOVETA
2110 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);
2113 #ifdef DSP_DIS_MOVETA
2115 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);
2119 static void dsp_opcode_movefa(void)
2121 #ifdef DSP_DIS_MOVEFA
2123 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);
2126 #ifdef DSP_DIS_MOVEFA
2128 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);
2132 static void dsp_opcode_move(void)
2136 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);
2141 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);
2145 static void dsp_opcode_moveq(void)
2147 #ifdef DSP_DIS_MOVEQ
2149 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);
2152 #ifdef DSP_DIS_MOVEQ
2154 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2158 static void dsp_opcode_resmac(void)
2160 #ifdef DSP_DIS_RESMAC
2162 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));
2164 RN = (uint32)dsp_acc;
2165 #ifdef DSP_DIS_RESMAC
2167 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2171 static void dsp_opcode_imult(void)
2173 #ifdef DSP_DIS_IMULT
2175 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);
2177 RN = (int16)RN * (int16)RM;
2179 #ifdef DSP_DIS_IMULT
2181 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);
2185 static void dsp_opcode_mult(void)
2189 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);
2191 RN = (uint16)RM * (uint16)RN;
2195 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);
2199 static void dsp_opcode_bclr(void)
2203 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);
2205 UINT32 res = RN & ~(1 << IMM_1);
2210 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2214 static void dsp_opcode_btst(void)
2218 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);
2220 dsp_flag_z = (~RN >> IMM_1) & 1;
2223 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2227 static void dsp_opcode_bset(void)
2231 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);
2233 UINT32 res = RN | (1 << IMM_1);
2238 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2242 static void dsp_opcode_subqt(void)
2244 #ifdef DSP_DIS_SUBQT
2246 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);
2248 RN -= dsp_convert_zero[IMM_1];
2249 #ifdef DSP_DIS_SUBQT
2251 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2255 static void dsp_opcode_addqt(void)
2257 #ifdef DSP_DIS_ADDQT
2259 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);
2261 RN += dsp_convert_zero[IMM_1];
2262 #ifdef DSP_DIS_ADDQT
2264 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2268 static void dsp_opcode_imacn(void)
2270 #ifdef DSP_DIS_IMACN
2272 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);
2274 int32 res = (int16)RM * (int16)RN;
2275 dsp_acc += (int64)res;
2276 //Should we AND the result to fit into 40 bits here???
2277 #ifdef DSP_DIS_IMACN
2279 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));
2283 static void dsp_opcode_mtoi(void)
2285 RN = (((INT32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2289 static void dsp_opcode_normi(void)
2296 while ((_Rm & 0xffc00000) == 0)
2301 while ((_Rm & 0xff800000) != 0)
2311 static void dsp_opcode_mmult(void)
2313 int count = dsp_matrix_control&0x0f;
2314 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2318 if (!(dsp_matrix_control & 0x10))
2320 for (int i = 0; i < count; i++)
2324 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2326 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2327 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2334 for (int i = 0; i < count; i++)
2338 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2340 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2341 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2346 RN = res = (int32)accum;
2348 //NOTE: The flags are set based upon the last add/multiply done...
2352 static void dsp_opcode_abs(void)
2356 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);
2361 if (_Rn == 0x80000000)
2365 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2366 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2371 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2375 static void dsp_opcode_div(void)
2382 if (dsp_div_control & 1)
2384 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2385 if (dsp_remain&0x80000000)
2387 RN = (((uint64)_Rn) << 16) / _Rm;
2391 dsp_remain = _Rn % _Rm;
2392 if (dsp_remain&0x80000000)
2401 static void dsp_opcode_imultn(void)
2403 #ifdef DSP_DIS_IMULTN
2405 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);
2407 // This is OK, since this multiply won't overflow 32 bits...
2408 int32 res = (int32)((int16)RN * (int16)RM);
2409 dsp_acc = (int64)res;
2411 #ifdef DSP_DIS_IMULTN
2413 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8)(dsp_acc >> 32), (uint32)(dsp_acc & 0xFFFFFFFF));
2417 static void dsp_opcode_neg(void)
2421 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);
2424 SET_ZNC_SUB(0, RN, res);
2428 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2432 static void dsp_opcode_shlq(void)
2436 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);
2438 INT32 r1 = 32 - IMM_1;
2439 UINT32 res = RN << r1;
2440 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2444 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2448 static void dsp_opcode_shrq(void)
2452 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);
2454 INT32 r1 = dsp_convert_zero[IMM_1];
2455 UINT32 res = RN >> r1;
2456 SET_ZN(res); dsp_flag_c = RN & 1;
2460 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2464 static void dsp_opcode_ror(void)
2468 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);
2470 UINT32 r1 = RM & 0x1F;
2471 UINT32 res = (RN >> r1) | (RN << (32 - r1));
2472 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2476 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);
2480 static void dsp_opcode_rorq(void)
2484 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);
2486 UINT32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2488 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
2490 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2493 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2497 static void dsp_opcode_sha(void)
2499 int32 sRm=(int32)RM;
2505 if (shift>=32) shift=32;
2506 dsp_flag_c=(_Rn&0x80000000)>>31;
2516 if (shift>=32) shift=32;
2520 _Rn=((int32)_Rn)>>1;
2528 static void dsp_opcode_sharq(void)
2530 #ifdef DSP_DIS_SHARQ
2532 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);
2534 UINT32 res = (INT32)RN >> dsp_convert_zero[IMM_1];
2535 SET_ZN(res); dsp_flag_c = RN & 0x01;
2537 #ifdef DSP_DIS_SHARQ
2539 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2543 static void dsp_opcode_sh(void)
2545 int32 sRm=(int32)RM;
2550 uint32 shift=(-sRm);
2551 if (shift>=32) shift=32;
2552 dsp_flag_c=(_Rn&0x80000000)>>31;
2562 if (shift>=32) shift=32;
2574 void dsp_opcode_addqmod(void)
2576 #ifdef DSP_DIS_ADDQMOD
2578 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);
2580 UINT32 r1 = dsp_convert_zero[IMM_1];
2582 UINT32 res = r2 + r1;
2583 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2585 SET_ZNC_ADD(r2, r1, res);
2586 #ifdef DSP_DIS_ADDQMOD
2588 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2592 void dsp_opcode_subqmod(void)
2594 UINT32 r1 = dsp_convert_zero[IMM_1];
2596 UINT32 res = r2 - r1;
2597 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2600 SET_ZNC_SUB(r2, r1, res);
2603 void dsp_opcode_mirror(void)
2606 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2610 void dsp_opcode_sat32s(void)
2612 INT32 r2 = (UINT32)RN;
2613 INT32 temp = dsp_acc >> 32;
2614 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
2619 void dsp_opcode_sat16s(void)
2622 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2628 // New pipelined DSP core
2631 static void DSP_abs(void);
2632 static void DSP_add(void);
2633 static void DSP_addc(void);
2634 static void DSP_addq(void);
2635 static void DSP_addqmod(void);
2636 static void DSP_addqt(void);
2637 static void DSP_and(void);
2638 static void DSP_bclr(void);
2639 static void DSP_bset(void);
2640 static void DSP_btst(void);
2641 static void DSP_cmp(void);
2642 static void DSP_cmpq(void);
2643 static void DSP_div(void);
2644 static void DSP_imacn(void);
2645 static void DSP_imult(void);
2646 static void DSP_imultn(void);
2647 static void DSP_illegal(void);
2648 static void DSP_jr(void);
2649 static void DSP_jump(void);
2650 static void DSP_load(void);
2651 static void DSP_loadb(void);
2652 static void DSP_loadw(void);
2653 static void DSP_load_r14_i(void);
2654 static void DSP_load_r14_r(void);
2655 static void DSP_load_r15_i(void);
2656 static void DSP_load_r15_r(void);
2657 static void DSP_mirror(void);
2658 static void DSP_mmult(void);
2659 static void DSP_move(void);
2660 static void DSP_movefa(void);
2661 static void DSP_movei(void);
2662 static void DSP_movepc(void);
2663 static void DSP_moveq(void);
2664 static void DSP_moveta(void);
2665 static void DSP_mtoi(void);
2666 static void DSP_mult(void);
2667 static void DSP_neg(void);
2668 static void DSP_nop(void);
2669 static void DSP_normi(void);
2670 static void DSP_not(void);
2671 static void DSP_or(void);
2672 static void DSP_resmac(void);
2673 static void DSP_ror(void);
2674 static void DSP_rorq(void);
2675 static void DSP_sat16s(void);
2676 static void DSP_sat32s(void);
2677 static void DSP_sh(void);
2678 static void DSP_sha(void);
2679 static void DSP_sharq(void);
2680 static void DSP_shlq(void);
2681 static void DSP_shrq(void);
2682 static void DSP_store(void);
2683 static void DSP_storeb(void);
2684 static void DSP_storew(void);
2685 static void DSP_store_r14_i(void);
2686 static void DSP_store_r14_r(void);
2687 static void DSP_store_r15_i(void);
2688 static void DSP_store_r15_r(void);
2689 static void DSP_sub(void);
2690 static void DSP_subc(void);
2691 static void DSP_subq(void);
2692 static void DSP_subqmod(void);
2693 static void DSP_subqt(void);
2694 static void DSP_xor(void);
2696 void (* DSPOpcode[64])() =
2698 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2699 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2700 DSP_neg, DSP_and, DSP_or, DSP_xor,
2701 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2703 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2704 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2705 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2706 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2708 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2709 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2710 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2711 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2713 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2714 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2715 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2716 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2719 bool readAffected[64][2] =
2721 { true, true}, { true, true}, {false, true}, {false, true},
2722 { true, true}, { true, true}, {false, true}, {false, true},
2723 {false, true}, { true, true}, { true, true}, { true, true},
2724 {false, true}, {false, true}, {false, true}, {false, true},
2726 { true, true}, { true, true}, { true, true}, {false, true},
2727 { true, true}, { true, true}, {false, true}, { true, true},
2728 {false, true}, {false, true}, { true, true}, {false, true},
2729 { true, true}, {false, true}, { true, true}, {false, true},
2731 {false, true}, {false, true}, { true, false}, {false, false},
2732 { true, false}, {false, false}, {false, false}, { true, false},
2733 { true, false}, { true, false}, {false, true}, { true, false},
2734 { true, false}, { true, true}, { true, true}, { true, true},
2736 {false, true}, { true, true}, { true, true}, {false, true},
2737 { true, false}, { true, false}, { true, true}, { true, false},
2738 { true, false}, {false, false}, { true, false}, { true, false},
2739 { true, true}, { true, true}, {false, false}, {false, true}
2742 bool isLoadStore[65] =
2744 false, false, false, false, false, false, false, false,
2745 false, false, false, false, false, false, false, false,
2747 false, false, false, false, false, false, false, false,
2748 false, false, false, false, false, false, false, false,
2750 false, false, false, false, false, false, false, true,
2751 true, true, false, true, true, true, true, true,
2753 false, true, true, false, false, false, false, false,
2754 false, false, true, true, true, true, false, false, false
2757 void FlushDSPPipeline(void)
2759 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2761 for(int i=0; i<4; i++)
2762 pipeline[i].opcode = PIPELINE_STALL;
2764 for(int i=0; i<32; i++)
2769 // New pipelined DSP execution core
2771 /*void DSPExecP(int32 cycles)
2773 // bool inhibitFetch = false;
2775 dsp_releaseTimeSlice_flag = 0;
2778 while (cycles > 0 && DSP_RUNNING)
2780 WriteLog("DSPExecP: Pipeline status...\n");
2781 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);
2782 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);
2783 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);
2784 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);
2785 WriteLog(" --> Scoreboard: ");
2786 for(int i=0; i<32; i++)
2787 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2789 // Stage 1: Instruction fetch
2790 // if (!inhibitFetch)
2792 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2793 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2794 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2795 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2796 if (pipeline[plPtrFetch].opcode == 38)
2797 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2798 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2801 // inhibitFetch = false;
2802 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2804 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2805 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);
2806 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);
2807 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);
2808 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);
2809 // Stage 2: Read registers
2810 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2811 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2812 if (scoreboard[pipeline[plPtrRead].operand2])
2813 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2814 // We have a hit in the scoreboard, so we have to stall the pipeline...
2816 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2817 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2818 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2819 pipeline[plPtrFetch] = pipeline[plPtrRead];
2820 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2824 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2825 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2826 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2828 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2829 // Shouldn't we be more selective with the register scoreboarding?
2830 // Yes, we should. !!! FIX !!!
2831 scoreboard[pipeline[plPtrRead].operand2] = true;
2832 //Advance PC here??? Yes.
2833 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2834 //This is a mangling of the pipeline stages, but what else to do???
2835 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2838 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2839 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);
2840 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);
2841 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);
2842 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);
2844 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2846 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2847 DSPOpcode[pipeline[plPtrExec].opcode]();
2848 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2849 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2854 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2855 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);
2856 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);
2857 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);
2858 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);
2859 // Stage 4: Write back register
2860 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2862 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2863 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2865 scoreboard[pipeline[plPtrWrite].operand1]
2866 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2869 // Push instructions through the pipeline...
2870 plPtrFetch = (++plPtrFetch) & 0x03;
2871 plPtrRead = (++plPtrRead) & 0x03;
2872 plPtrExec = (++plPtrExec) & 0x03;
2873 plPtrWrite = (++plPtrWrite) & 0x03;
2880 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2882 // Should be fixed now. Another problem is figuring how to do the sequence following
2883 // a branch followed with the JR & JUMP instructions...
2885 // There are two conflicting problems:
2888 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2889 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2890 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2891 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2892 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2893 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2894 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2895 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2896 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2897 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2898 DSP: Finished interrupt.
2899 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2900 ; bank 0 (where is was prepared)!
2901 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2902 F1B252: NOP [NCZ:001]
2905 // The other is when you see this at the end of an IRQ:
2908 JUMP T, (R29) ; R29 = Previous stack + 2
2909 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2911 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2912 ; 1) The STORE goes through the pipeline and is executed/written back
2913 ; 2) The pipeline is flushed
2914 ; 3) The DSP_PC is set to the new address
2915 ; 4) Execution resumes
2917 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2918 ; bank 0 instead of the current bank 1 and so goes astray!
2921 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2922 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2926 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2927 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2928 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2929 If it were done properly, the STORE write back would occur *after* (well, technically,
2930 during) the execution of the the JUMP that follows it.
2934 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2935 F1B08A: NOP [NCZ:001]
2937 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2940 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2943 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2944 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2945 F1B08A: NOP [NCZ:001]
2947 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2950 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2951 DSP: CPU -> DSP interrupt
2952 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2953 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2955 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2958 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2959 F1B006: NOP [NCZ:001]
2961 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2964 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2965 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2968 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2969 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2972 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2973 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2976 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2977 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
2980 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
2983 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
2986 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
2987 F1B0FE: NOP [NCZ:000]
2989 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
2992 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
2995 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
2996 F1B138: NOP [NCZ:000]
2998 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3001 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3002 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3003 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3006 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3007 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3010 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3011 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3012 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3014 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3015 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3018 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3019 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3020 DSP: Finished interrupt.
3021 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3023 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3026 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3027 F1B016: NOP [NCZ:001]
3029 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3032 uint32 pcQueue1[0x400];
3034 static uint32 prevR1;
3035 //Let's try a 3 stage pipeline....
3036 //Looks like 3 stage is correct, otherwise bad things happen...
3037 void DSPExecP2(int32 cycles)
3039 dsp_releaseTimeSlice_flag = 0;
3042 while (cycles > 0 && DSP_RUNNING)
3044 /*extern uint32 totalFrames;
3045 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3046 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3047 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3049 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3052 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3054 if (dsp_pc == 0xF1B092)
3055 doDSPDis = false;//*/
3056 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3057 doDSPDis = true;//*/
3058 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3059 doDSPDis = true;//*/
3060 /*if (dsp_pc == 0xF1B0A0)
3061 doDSPDis = true;//*/
3062 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3063 doDSPDis = true;//*/
3064 //Two parter... (not sure how to write this)
3065 //if (dsp_pc == 0xF1B0D2)
3066 // prevR1 = dsp_reg[1];
3068 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3069 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3072 pcQueue1[pcQPtr1++] = dsp_pc;
3075 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3077 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3082 for(int i=0; i<0x400; i++)
3084 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3085 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3089 if (IMASKCleared) // If IMASK was cleared,
3091 #ifdef DSP_DEBUG_IRQ
3092 WriteLog("DSP: Finished interrupt.\n");
3094 DSPHandleIRQs(); // See if any other interrupts are pending!
3095 IMASKCleared = false;
3098 //if (dsp_flags & REGPAGE)
3099 // WriteLog(" --> REGPAGE has just been set!\n");
3100 #ifdef DSP_DEBUG_PL2
3103 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3104 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]);
3105 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]);
3106 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]);
3107 WriteLog(" --> Scoreboard: ");
3108 for(int i=0; i<32; i++)
3109 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3113 // Stage 1a: Instruction fetch
3114 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3115 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3116 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3117 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3118 if (pipeline[plPtrRead].opcode == 38)
3119 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3120 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3121 #ifdef DSP_DEBUG_PL2
3124 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3125 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3126 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]);
3127 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]);
3128 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]);
3131 // Stage 1b: Read registers
3132 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3133 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3135 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3136 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3137 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3138 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3139 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3140 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3141 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3143 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3144 // We have a hit in the scoreboard, so we have to stall the pipeline...
3145 #ifdef DSP_DEBUG_PL2
3149 WriteLog(" --> Stalling pipeline: ");
3150 if (readAffected[pipeline[plPtrRead].opcode][0])
3151 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3152 if (readAffected[pipeline[plPtrRead].opcode][1])
3153 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3157 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3158 #ifdef DSP_DEBUG_PL2
3163 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3164 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3165 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3167 // Shouldn't we be more selective with the register scoreboarding?
3168 // Yes, we should. !!! FIX !!! Kinda [DONE]
3169 #ifndef NEW_SCOREBOARD
3170 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3172 //Hopefully this will fix the dual MOVEQ # problem...
3173 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3176 //Advance PC here??? Yes.
3177 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3180 #ifdef DSP_DEBUG_PL2
3183 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3184 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]);
3185 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]);
3186 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]);
3190 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3193 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"));
3194 #ifdef DSP_DEBUG_PL2
3197 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3202 lastExec = pipeline[plPtrExec].instruction;
3203 //WriteLog("[lastExec = %04X]\n", lastExec);
3205 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3206 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3207 DSPOpcode[pipeline[plPtrExec].opcode]();
3208 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3212 //Let's not, until we do the stalling correctly...
3213 //But, we gotta while we're doing the comparison core...!
3214 //Or do we? cycles--;
3215 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3216 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3217 //to model this clock cycle behavior correctly...
3218 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3219 //don't affect the reads at stage 1...
3220 #ifdef DSP_DEBUG_STALL
3222 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3226 #ifdef DSP_DEBUG_PL2
3229 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3230 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]);
3231 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]);
3232 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]);
3236 // Stage 3: Write back register/memory address
3237 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3239 /*if (pipeline[plPtrWrite].writebackRegister == 3
3240 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3243 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3246 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3248 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3249 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3252 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3253 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3254 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3255 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3257 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3261 #ifndef NEW_SCOREBOARD
3262 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3263 scoreboard[pipeline[plPtrWrite].operand2] = false;
3265 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3266 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3267 if (scoreboard[pipeline[plPtrWrite].operand2])
3268 scoreboard[pipeline[plPtrWrite].operand2]--;
3272 // Push instructions through the pipeline...
3273 plPtrRead = (++plPtrRead) & 0x03;
3274 plPtrExec = (++plPtrExec) & 0x03;
3275 plPtrWrite = (++plPtrWrite) & 0x03;
3284 //#define DSP_DEBUG_PL3
3285 //Let's try a 2 stage pipeline....
3286 void DSPExecP3(int32 cycles)
3288 dsp_releaseTimeSlice_flag = 0;
3291 while (cycles > 0 && DSP_RUNNING)
3293 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3295 #ifdef DSP_DEBUG_PL3
3296 WriteLog("DSPExecP: Pipeline status...\n");
3297 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]);
3298 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]);
3299 WriteLog(" --> Scoreboard: ");
3300 for(int i=0; i<32; i++)
3301 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3304 // Stage 1a: Instruction fetch
3305 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3306 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3307 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3308 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3309 if (pipeline[plPtrRead].opcode == 38)
3310 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3311 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3312 #ifdef DSP_DEBUG_PL3
3313 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3314 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3315 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]);
3316 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]);
3318 // Stage 1b: Read registers
3319 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3320 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3321 // We have a hit in the scoreboard, so we have to stall the pipeline...
3322 #ifdef DSP_DEBUG_PL3
3324 WriteLog(" --> Stalling pipeline: ");
3325 if (readAffected[pipeline[plPtrRead].opcode][0])
3326 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3327 if (readAffected[pipeline[plPtrRead].opcode][1])
3328 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3331 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3332 #ifdef DSP_DEBUG_PL3
3337 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3338 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3339 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3341 // Shouldn't we be more selective with the register scoreboarding?
3342 // Yes, we should. !!! FIX !!! [Kinda DONE]
3343 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3345 //Advance PC here??? Yes.
3346 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3349 #ifdef DSP_DEBUG_PL3
3350 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3351 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]);
3352 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]);
3354 // Stage 2a: Execute
3355 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3357 #ifdef DSP_DEBUG_PL3
3358 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3360 DSPOpcode[pipeline[plPtrExec].opcode]();
3361 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3362 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3367 #ifdef DSP_DEBUG_PL3
3368 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3369 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]);
3370 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]);
3373 // Stage 2b: Write back register
3374 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3376 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3377 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3379 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3380 scoreboard[pipeline[plPtrExec].operand2] = false;
3383 // Push instructions through the pipeline...
3384 plPtrRead = (++plPtrRead) & 0x03;
3385 plPtrExec = (++plPtrExec) & 0x03;
3392 // DSP pipelined opcode handlers
3395 #define PRM pipeline[plPtrExec].reg1
3396 #define PRN pipeline[plPtrExec].reg2
3397 #define PIMM1 pipeline[plPtrExec].operand1
3398 #define PIMM2 pipeline[plPtrExec].operand2
3399 #define PRES pipeline[plPtrExec].result
3400 #define PWBR pipeline[plPtrExec].writebackRegister
3401 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3402 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3403 #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))
3404 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3406 static void DSP_abs(void)
3410 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);
3414 if (_Rn == 0x80000000)
3418 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3419 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3420 CLR_ZN; SET_Z(PRES);
3424 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3428 static void DSP_add(void)
3432 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);
3434 UINT32 res = PRN + PRM;
3435 SET_ZNC_ADD(PRN, PRM, res);
3439 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);
3443 static void DSP_addc(void)
3447 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);
3449 UINT32 res = PRN + PRM + dsp_flag_c;
3450 UINT32 carry = dsp_flag_c;
3451 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3452 SET_ZNC_ADD(PRN + carry, PRM, res);
3453 // SET_ZNC_ADD(PRN, PRM + carry, res);
3457 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);
3461 static void DSP_addq(void)
3465 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);
3467 UINT32 r1 = dsp_convert_zero[PIMM1];
3468 UINT32 res = PRN + r1;
3469 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3473 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3477 static void DSP_addqmod(void)
3479 #ifdef DSP_DIS_ADDQMOD
3481 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);
3483 UINT32 r1 = dsp_convert_zero[PIMM1];
3485 UINT32 res = r2 + r1;
3486 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3488 SET_ZNC_ADD(r2, r1, res);
3489 #ifdef DSP_DIS_ADDQMOD
3491 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3495 static void DSP_addqt(void)
3497 #ifdef DSP_DIS_ADDQT
3499 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);
3501 PRES = PRN + dsp_convert_zero[PIMM1];
3502 #ifdef DSP_DIS_ADDQT
3504 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3508 static void DSP_and(void)
3512 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);
3518 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);
3522 static void DSP_bclr(void)
3526 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);
3528 PRES = PRN & ~(1 << PIMM1);
3532 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3536 static void DSP_bset(void)
3540 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);
3542 PRES = PRN | (1 << PIMM1);
3546 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3550 static void DSP_btst(void)
3554 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);
3556 dsp_flag_z = (~PRN >> PIMM1) & 1;
3560 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3564 static void DSP_cmp(void)
3568 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);
3570 UINT32 res = PRN - PRM;
3571 SET_ZNC_SUB(PRN, PRM, res);
3575 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3579 static void DSP_cmpq(void)
3581 static int32 sqtable[32] =
3582 { 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 };
3585 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);
3587 UINT32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3588 UINT32 res = PRN - r1;
3589 SET_ZNC_SUB(PRN, r1, res);
3593 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3597 static void DSP_div(void)
3599 uint32 _Rm = PRM, _Rn = PRN;
3603 if (dsp_div_control & 1)
3605 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3606 if (dsp_remain & 0x80000000)
3608 PRES = (((uint64)_Rn) << 16) / _Rm;
3612 dsp_remain = _Rn % _Rm;
3613 if (dsp_remain & 0x80000000)
3622 static void DSP_imacn(void)
3624 #ifdef DSP_DIS_IMACN
3626 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);
3628 int32 res = (int16)PRM * (int16)PRN;
3629 dsp_acc += (int64)res;
3630 //Should we AND the result to fit into 40 bits here???
3632 #ifdef DSP_DIS_IMACN
3634 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));
3638 static void DSP_imult(void)
3640 #ifdef DSP_DIS_IMULT
3642 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);
3644 PRES = (int16)PRN * (int16)PRM;
3646 #ifdef DSP_DIS_IMULT
3648 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);
3652 static void DSP_imultn(void)
3654 #ifdef DSP_DIS_IMULTN
3656 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);
3658 // This is OK, since this multiply won't overflow 32 bits...
3659 int32 res = (int32)((int16)PRN * (int16)PRM);
3660 dsp_acc = (int64)res;
3663 #ifdef DSP_DIS_IMULTN
3665 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));
3669 static void DSP_illegal(void)
3671 #ifdef DSP_DIS_ILLEGAL
3673 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3678 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3679 // can cause trouble because an interrupt can occur *before* the instruction following the
3680 // jump can execute... !!! FIX !!!
3681 // This can probably be solved by judicious coding in the pipeline execution core...
3682 // And should be fixed now...
3683 static void DSP_jr(void)
3686 char * condition[32] =
3687 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3688 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3689 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3690 "???", "???", "???", "F" };
3692 //How come this is always off by 2???
3693 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);
3695 // KLUDGE: Used by BRANCH_CONDITION macro
3696 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3698 if (BRANCH_CONDITION(PIMM2))
3702 WriteLog("Branched!\n");
3704 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3705 //Account for pipeline effects...
3706 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3707 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3709 // Now that we've branched, we have to make sure that the following instruction
3710 // is executed atomically with this one and then flush the pipeline before setting
3713 // Step 1: Handle writebacks at stage 3 of pipeline
3714 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3716 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3717 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3719 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3720 scoreboard[pipeline[plPtrWrite].operand2] = false;
3722 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3724 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3726 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3727 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3730 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3731 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3732 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3733 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3735 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3739 #ifndef NEW_SCOREBOARD
3740 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3741 scoreboard[pipeline[plPtrWrite].operand2] = false;
3743 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3744 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3745 if (scoreboard[pipeline[plPtrWrite].operand2])
3746 scoreboard[pipeline[plPtrWrite].operand2]--;
3750 // Step 2: Push instruction through pipeline & execute following instruction
3751 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3752 // we effectively handle the final push of the instruction through the
3753 // pipeline when the new PC takes effect (since when we return, the
3754 // pipeline code will be executing the writeback stage. If we reverse
3755 // the execution order of the pipeline stages, this will no longer be
3757 pipeline[plPtrExec] = pipeline[plPtrRead];
3758 //This is BAD. We need to get that next opcode and execute it!
3759 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3760 // remove this crap.
3761 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3763 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3764 pipeline[plPtrExec].opcode = instruction >> 10;
3765 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3766 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3767 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3768 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3769 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3771 dsp_pc += 2; // For DSP_DIS_* accuracy
3772 DSPOpcode[pipeline[plPtrExec].opcode]();
3773 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3774 pipeline[plPtrWrite] = pipeline[plPtrExec];
3776 // Step 3: Flush pipeline & set new PC
3777 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3784 WriteLog("Branch NOT taken.\n");
3790 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3793 static void DSP_jump(void)
3796 char * condition[32] =
3797 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3798 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3799 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3800 "???", "???", "???", "F" };
3802 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);
3804 // KLUDGE: Used by BRANCH_CONDITION macro
3805 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3807 if (BRANCH_CONDITION(PIMM2))
3811 WriteLog("Branched!\n");
3813 uint32 PCSave = PRM;
3814 // Now that we've branched, we have to make sure that the following instruction
3815 // is executed atomically with this one and then flush the pipeline before setting
3818 // Step 1: Handle writebacks at stage 3 of pipeline
3819 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3821 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3822 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3824 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3825 scoreboard[pipeline[plPtrWrite].operand2] = false;
3827 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3829 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3831 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3832 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3835 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3836 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3837 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3838 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3840 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3844 #ifndef NEW_SCOREBOARD
3845 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3846 scoreboard[pipeline[plPtrWrite].operand2] = false;
3848 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3849 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3850 if (scoreboard[pipeline[plPtrWrite].operand2])
3851 scoreboard[pipeline[plPtrWrite].operand2]--;
3855 // Step 2: Push instruction through pipeline & execute following instruction
3856 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3857 // we effectively handle the final push of the instruction through the
3858 // pipeline when the new PC takes effect (since when we return, the
3859 // pipeline code will be executing the writeback stage. If we reverse
3860 // the execution order of the pipeline stages, this will no longer be
3862 pipeline[plPtrExec] = pipeline[plPtrRead];
3863 //This is BAD. We need to get that next opcode and execute it!
3864 //Also, same problem in JR!
3865 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3866 // remove this crap.
3867 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3869 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3870 pipeline[plPtrExec].opcode = instruction >> 10;
3871 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3872 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3873 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3874 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3875 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3877 dsp_pc += 2; // For DSP_DIS_* accuracy
3878 DSPOpcode[pipeline[plPtrExec].opcode]();
3879 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3880 pipeline[plPtrWrite] = pipeline[plPtrExec];
3882 // Step 3: Flush pipeline & set new PC
3883 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3890 WriteLog("Branch NOT taken.\n");
3898 static void DSP_load(void)
3902 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);
3904 PRES = DSPReadLong(PRM, DSP);
3907 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3911 static void DSP_loadb(void)
3913 #ifdef DSP_DIS_LOADB
3915 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);
3917 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3918 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3920 PRES = JaguarReadByte(PRM, DSP);
3921 #ifdef DSP_DIS_LOADB
3923 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3927 static void DSP_loadw(void)
3929 #ifdef DSP_DIS_LOADW
3931 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);
3933 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3934 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3936 PRES = JaguarReadWord(PRM, DSP);
3937 #ifdef DSP_DIS_LOADW
3939 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3943 static void DSP_load_r14_i(void)
3945 #ifdef DSP_DIS_LOAD14I
3947 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);
3949 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3950 #ifdef DSP_DIS_LOAD14I
3952 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3956 static void DSP_load_r14_r(void)
3958 #ifdef DSP_DIS_LOAD14R
3960 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);
3962 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3963 #ifdef DSP_DIS_LOAD14R
3965 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3969 static void DSP_load_r15_i(void)
3971 #ifdef DSP_DIS_LOAD15I
3973 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);
3975 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3976 #ifdef DSP_DIS_LOAD15I
3978 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3982 static void DSP_load_r15_r(void)
3984 #ifdef DSP_DIS_LOAD15R
3986 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);
3988 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
3989 #ifdef DSP_DIS_LOAD15R
3991 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3995 static void DSP_mirror(void)
3998 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4002 static void DSP_mmult(void)
4004 int count = dsp_matrix_control&0x0f;
4005 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4009 if (!(dsp_matrix_control & 0x10))
4011 for (int i = 0; i < count; i++)
4015 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4017 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4018 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4025 for (int i = 0; i < count; i++)
4029 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4031 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4032 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4038 PRES = res = (int32)accum;
4040 //NOTE: The flags are set based upon the last add/multiply done...
4044 static void DSP_move(void)
4048 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);
4053 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);
4057 static void DSP_movefa(void)
4059 #ifdef DSP_DIS_MOVEFA
4061 // 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);
4062 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);
4064 // PRES = ALTERNATE_RM;
4065 PRES = dsp_alternate_reg[PIMM1];
4066 #ifdef DSP_DIS_MOVEFA
4068 // 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);
4069 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);
4073 static void DSP_movei(void)
4075 #ifdef DSP_DIS_MOVEI
4077 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);
4079 // // This instruction is followed by 32-bit value in LSW / MSW format...
4080 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4082 #ifdef DSP_DIS_MOVEI
4084 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4088 static void DSP_movepc(void)
4090 #ifdef DSP_DIS_MOVEPC
4092 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);
4094 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4095 // PRES = dsp_pc - 2;
4096 //Account for pipeline effects...
4097 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4098 #ifdef DSP_DIS_MOVEPC
4100 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4104 static void DSP_moveq(void)
4106 #ifdef DSP_DIS_MOVEQ
4108 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);
4111 #ifdef DSP_DIS_MOVEQ
4113 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4117 static void DSP_moveta(void)
4119 #ifdef DSP_DIS_MOVETA
4121 // 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);
4122 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]);
4124 // ALTERNATE_RN = PRM;
4125 dsp_alternate_reg[PIMM2] = PRM;
4127 #ifdef DSP_DIS_MOVETA
4129 // 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);
4130 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]);
4134 static void DSP_mtoi(void)
4136 PRES = (((INT32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4140 static void DSP_mult(void)
4144 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);
4146 PRES = (uint16)PRM * (uint16)PRN;
4150 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);
4154 static void DSP_neg(void)
4158 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);
4161 SET_ZNC_SUB(0, PRN, res);
4165 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4169 static void DSP_nop(void)
4173 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4178 static void DSP_normi(void)
4185 while ((_Rm & 0xffc00000) == 0)
4190 while ((_Rm & 0xff800000) != 0)
4200 static void DSP_not(void)
4204 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4210 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4214 static void DSP_or(void)
4218 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);
4224 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);
4228 static void DSP_resmac(void)
4230 #ifdef DSP_DIS_RESMAC
4232 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));
4234 PRES = (uint32)dsp_acc;
4235 #ifdef DSP_DIS_RESMAC
4237 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4241 static void DSP_ror(void)
4245 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);
4247 UINT32 r1 = PRM & 0x1F;
4248 UINT32 res = (PRN >> r1) | (PRN << (32 - r1));
4249 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4253 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);
4257 static void DSP_rorq(void)
4261 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);
4263 UINT32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4265 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
4267 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4270 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4274 static void DSP_sat16s(void)
4277 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4282 static void DSP_sat32s(void)
4284 INT32 r2 = (UINT32)PRN;
4285 INT32 temp = dsp_acc >> 32;
4286 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
4291 static void DSP_sh(void)
4293 int32 sRm = (int32)PRM;
4298 uint32 shift = -sRm;
4303 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4318 dsp_flag_c = _Rn & 0x1;
4331 static void DSP_sha(void)
4333 int32 sRm = (int32)PRM;
4338 uint32 shift = -sRm;
4343 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4358 dsp_flag_c = _Rn & 0x1;
4362 _Rn = ((int32)_Rn) >> 1;
4371 static void DSP_sharq(void)
4373 #ifdef DSP_DIS_SHARQ
4375 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);
4377 UINT32 res = (INT32)PRN >> dsp_convert_zero[PIMM1];
4378 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4380 #ifdef DSP_DIS_SHARQ
4382 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4386 static void DSP_shlq(void)
4390 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);
4392 INT32 r1 = 32 - PIMM1;
4393 UINT32 res = PRN << r1;
4394 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4398 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4402 static void DSP_shrq(void)
4406 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);
4408 INT32 r1 = dsp_convert_zero[PIMM1];
4409 UINT32 res = PRN >> r1;
4410 SET_ZN(res); dsp_flag_c = PRN & 1;
4414 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4418 static void DSP_store(void)
4420 #ifdef DSP_DIS_STORE
4422 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);
4424 // DSPWriteLong(PRM, PRN, DSP);
4426 pipeline[plPtrExec].address = PRM;
4427 pipeline[plPtrExec].value = PRN;
4428 pipeline[plPtrExec].type = TYPE_DWORD;
4432 static void DSP_storeb(void)
4434 #ifdef DSP_DIS_STOREB
4436 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);
4438 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4439 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4441 // JaguarWriteByte(PRM, PRN, DSP);
4444 pipeline[plPtrExec].address = PRM;
4446 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4448 pipeline[plPtrExec].value = PRN & 0xFF;
4449 pipeline[plPtrExec].type = TYPE_DWORD;
4453 pipeline[plPtrExec].value = PRN;
4454 pipeline[plPtrExec].type = TYPE_BYTE;
4460 static void DSP_storew(void)
4462 #ifdef DSP_DIS_STOREW
4464 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);
4466 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4467 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4469 // JaguarWriteWord(PRM, PRN, DSP);
4472 pipeline[plPtrExec].address = PRM;
4474 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4476 pipeline[plPtrExec].value = PRN & 0xFFFF;
4477 pipeline[plPtrExec].type = TYPE_DWORD;
4481 pipeline[plPtrExec].value = PRN;
4482 pipeline[plPtrExec].type = TYPE_WORD;
4487 static void DSP_store_r14_i(void)
4489 #ifdef DSP_DIS_STORE14I
4491 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));
4493 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4495 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4496 pipeline[plPtrExec].value = PRN;
4497 pipeline[plPtrExec].type = TYPE_DWORD;
4501 static void DSP_store_r14_r(void)
4503 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4505 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4506 pipeline[plPtrExec].value = PRN;
4507 pipeline[plPtrExec].type = TYPE_DWORD;
4511 static void DSP_store_r15_i(void)
4513 #ifdef DSP_DIS_STORE15I
4515 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));
4517 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4519 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4520 pipeline[plPtrExec].value = PRN;
4521 pipeline[plPtrExec].type = TYPE_DWORD;
4525 static void DSP_store_r15_r(void)
4527 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4529 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4530 pipeline[plPtrExec].value = PRN;
4531 pipeline[plPtrExec].type = TYPE_DWORD;
4535 static void DSP_sub(void)
4539 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);
4541 UINT32 res = PRN - PRM;
4542 SET_ZNC_SUB(PRN, PRM, res);
4546 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);
4550 static void DSP_subc(void)
4554 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);
4556 UINT32 res = PRN - PRM - dsp_flag_c;
4557 UINT32 borrow = dsp_flag_c;
4558 SET_ZNC_SUB(PRN - borrow, PRM, res);
4562 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);
4566 static void DSP_subq(void)
4570 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);
4572 UINT32 r1 = dsp_convert_zero[PIMM1];
4573 UINT32 res = PRN - r1;
4574 SET_ZNC_SUB(PRN, r1, res);
4578 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4582 static void DSP_subqmod(void)
4584 UINT32 r1 = dsp_convert_zero[PIMM1];
4586 UINT32 res = r2 - r1;
4587 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4589 SET_ZNC_SUB(r2, r1, res);
4592 static void DSP_subqt(void)
4594 #ifdef DSP_DIS_SUBQT
4596 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);
4598 PRES = PRN - dsp_convert_zero[PIMM1];
4599 #ifdef DSP_DIS_SUBQT
4601 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4605 static void DSP_xor(void)
4609 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);
4615 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);