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
9 #include <SDL.h> // Used only for SDL_GetTicks...
13 //#define DSP_DEBUG_IRQ
14 //#define DSP_DEBUG_PL2
15 //#define DSP_DEBUG_STALL
16 //#define DSP_DEBUG_CC
17 #define NEW_SCOREBOARD
19 // Disassembly definitions
25 #define DSP_DIS_ADDQMOD
35 #define DSP_DIS_IMULTN
36 #define DSP_DIS_ILLEGAL
40 #define DSP_DIS_LOAD14I
41 #define DSP_DIS_LOAD14R
42 #define DSP_DIS_LOAD15I
43 #define DSP_DIS_LOAD15R
49 #define DSP_DIS_MOVEFA
50 #define DSP_DIS_MOVEPC // Pipeline only!
51 #define DSP_DIS_MOVETA
57 #define DSP_DIS_RESMAC
64 #define DSP_DIS_STORE14I
65 #define DSP_DIS_STORE15I
66 #define DSP_DIS_STOREB
67 #define DSP_DIS_STOREW
74 bool doDSPDis = false;
75 //bool doDSPDis = true;
110 + load_r15_indexed 284500
112 + store_r15_indexed 47416
116 + load_r14_ri 1229448
119 // Pipeline structures
121 const bool affectsScoreboard[64] =
123 true, true, true, true,
124 true, true, true, true,
125 true, true, true, true,
126 true, false, true, true,
128 true, true, false, true,
129 false, true, true, true,
130 true, true, true, true,
131 true, true, false, false,
133 true, true, true, true,
134 false, true, true, true,
135 true, true, true, true,
136 true, false, false, false,
138 true, false, false, true,
139 false, false, true, true,
140 true, false, true, true,
141 false, false, false, true
147 uint8 opcode, operand1, operand2;
148 uint32 reg1, reg2, areg1, areg2;
150 uint8 writebackRegister;
151 // General memory store...
160 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
161 #ifndef NEW_SCOREBOARD
164 uint8 scoreboard[32];
166 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
167 PipelineStage pipeline[4];
168 bool IMASKCleared = false;
170 // DSP flags (old--have to get rid of this crap)
172 #define CINT0FLAG 0x00200
173 #define CINT1FLAG 0x00400
174 #define CINT2FLAG 0x00800
175 #define CINT3FLAG 0x01000
176 #define CINT4FLAG 0x02000
177 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
178 #define CINT5FLAG 0x20000 /* DSP only */
182 #define ZERO_FLAG 0x00001
183 #define CARRY_FLAG 0x00002
184 #define NEGA_FLAG 0x00004
185 #define IMASK 0x00008
186 #define INT_ENA0 0x00010
187 #define INT_ENA1 0x00020
188 #define INT_ENA2 0x00040
189 #define INT_ENA3 0x00080
190 #define INT_ENA4 0x00100
191 #define INT_CLR0 0x00200
192 #define INT_CLR1 0x00400
193 #define INT_CLR2 0x00800
194 #define INT_CLR3 0x01000
195 #define INT_CLR4 0x02000
196 #define REGPAGE 0x04000
197 #define DMAEN 0x08000
198 #define INT_ENA5 0x10000
199 #define INT_CLR5 0x20000
203 #define DSPGO 0x00001
204 #define CPUINT 0x00002
205 #define DSPINT0 0x00004
206 #define SINGLE_STEP 0x00008
207 #define SINGLE_GO 0x00010
209 #define INT_LAT0 0x00040
210 #define INT_LAT1 0x00080
211 #define INT_LAT2 0x00100
212 #define INT_LAT3 0x00200
213 #define INT_LAT4 0x00400
214 #define BUS_HOG 0x00800
215 #define VERSION 0x0F000
216 #define INT_LAT5 0x10000
218 extern uint32 jaguar_mainRom_crc32;
220 // Is opcode 62 *really* a NOP? Seems like it...
221 static void dsp_opcode_abs(void);
222 static void dsp_opcode_add(void);
223 static void dsp_opcode_addc(void);
224 static void dsp_opcode_addq(void);
225 static void dsp_opcode_addqmod(void);
226 static void dsp_opcode_addqt(void);
227 static void dsp_opcode_and(void);
228 static void dsp_opcode_bclr(void);
229 static void dsp_opcode_bset(void);
230 static void dsp_opcode_btst(void);
231 static void dsp_opcode_cmp(void);
232 static void dsp_opcode_cmpq(void);
233 static void dsp_opcode_div(void);
234 static void dsp_opcode_imacn(void);
235 static void dsp_opcode_imult(void);
236 static void dsp_opcode_imultn(void);
237 static void dsp_opcode_jr(void);
238 static void dsp_opcode_jump(void);
239 static void dsp_opcode_load(void);
240 static void dsp_opcode_loadb(void);
241 static void dsp_opcode_loadw(void);
242 static void dsp_opcode_load_r14_indexed(void);
243 static void dsp_opcode_load_r14_ri(void);
244 static void dsp_opcode_load_r15_indexed(void);
245 static void dsp_opcode_load_r15_ri(void);
246 static void dsp_opcode_mirror(void);
247 static void dsp_opcode_mmult(void);
248 static void dsp_opcode_move(void);
249 static void dsp_opcode_movei(void);
250 static void dsp_opcode_movefa(void);
251 static void dsp_opcode_move_pc(void);
252 static void dsp_opcode_moveq(void);
253 static void dsp_opcode_moveta(void);
254 static void dsp_opcode_mtoi(void);
255 static void dsp_opcode_mult(void);
256 static void dsp_opcode_neg(void);
257 static void dsp_opcode_nop(void);
258 static void dsp_opcode_normi(void);
259 static void dsp_opcode_not(void);
260 static void dsp_opcode_or(void);
261 static void dsp_opcode_resmac(void);
262 static void dsp_opcode_ror(void);
263 static void dsp_opcode_rorq(void);
264 static void dsp_opcode_xor(void);
265 static void dsp_opcode_sat16s(void);
266 static void dsp_opcode_sat32s(void);
267 static void dsp_opcode_sh(void);
268 static void dsp_opcode_sha(void);
269 static void dsp_opcode_sharq(void);
270 static void dsp_opcode_shlq(void);
271 static void dsp_opcode_shrq(void);
272 static void dsp_opcode_store(void);
273 static void dsp_opcode_storeb(void);
274 static void dsp_opcode_storew(void);
275 static void dsp_opcode_store_r14_indexed(void);
276 static void dsp_opcode_store_r14_ri(void);
277 static void dsp_opcode_store_r15_indexed(void);
278 static void dsp_opcode_store_r15_ri(void);
279 static void dsp_opcode_sub(void);
280 static void dsp_opcode_subc(void);
281 static void dsp_opcode_subq(void);
282 static void dsp_opcode_subqmod(void);
283 static void dsp_opcode_subqt(void);
285 uint8 dsp_opcode_cycles[64] =
287 3, 3, 3, 3, 3, 3, 3, 3,
288 3, 3, 3, 3, 3, 3, 3, 3,
289 3, 3, 1, 3, 1, 18, 3, 3,
290 3, 3, 3, 3, 3, 3, 3, 3,
291 3, 3, 2, 2, 2, 2, 3, 4,
292 5, 4, 5, 6, 6, 1, 1, 1,
293 1, 2, 2, 2, 1, 1, 9, 3,
294 3, 1, 6, 6, 2, 2, 3, 3
296 //Here's a QnD kludge...
297 //This is wrong, wrong, WRONG, but it seems to work for the time being...
298 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
299 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
300 /*uint8 dsp_opcode_cycles[64] =
302 1, 1, 1, 1, 1, 1, 1, 1,
303 1, 1, 1, 1, 1, 1, 1, 1,
304 1, 1, 1, 1, 1, 9, 1, 1,
305 1, 1, 1, 1, 1, 1, 1, 1,
306 1, 1, 1, 1, 1, 1, 1, 2,
307 2, 2, 2, 3, 3, 1, 1, 1,
308 1, 1, 1, 1, 1, 1, 4, 1,
309 1, 1, 3, 3, 1, 1, 1, 1
312 void (* dsp_opcode[64])() =
314 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
315 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
316 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
317 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
318 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
319 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
320 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
321 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
322 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
323 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
324 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
325 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
326 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
327 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
328 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
329 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
332 uint32 dsp_opcode_use[65];
334 char * dsp_opcode_str[65]=
336 "add", "addc", "addq", "addqt",
337 "sub", "subc", "subq", "subqt",
338 "neg", "and", "or", "xor",
339 "not", "btst", "bset", "bclr",
340 "mult", "imult", "imultn", "resmac",
341 "imacn", "div", "abs", "sh",
342 "shlq", "shrq", "sha", "sharq",
343 "ror", "rorq", "cmp", "cmpq",
344 "subqmod", "sat16s", "move", "moveq",
345 "moveta", "movefa", "movei", "loadb",
346 "loadw", "load", "sat32s", "load_r14_indexed",
347 "load_r15_indexed", "storeb", "storew", "store",
348 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
349 "jump", "jr", "mmult", "mtoi",
350 "normi", "nop", "load_r14_ri", "load_r15_ri",
351 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
356 static uint64 dsp_acc; // 40 bit register, NOT 32!
357 static uint32 dsp_remain;
358 static uint32 dsp_modulo;
359 static uint32 dsp_flags;
360 static uint32 dsp_matrix_control;
361 static uint32 dsp_pointer_to_matrix;
362 static uint32 dsp_data_organization;
364 static uint32 dsp_div_control;
365 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
366 static uint32 * dsp_reg, * dsp_alternate_reg;
367 static uint32 * dsp_reg_bank_0, * dsp_reg_bank_1;
369 static uint32 dsp_opcode_first_parameter;
370 static uint32 dsp_opcode_second_parameter;
372 #define DSP_RUNNING (dsp_control & 0x01)
374 #define RM dsp_reg[dsp_opcode_first_parameter]
375 #define RN dsp_reg[dsp_opcode_second_parameter]
376 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
377 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
378 #define IMM_1 dsp_opcode_first_parameter
379 #define IMM_2 dsp_opcode_second_parameter
381 #define CLR_Z (dsp_flag_z = 0)
382 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
383 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
384 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
385 #define SET_N(r) (dsp_flag_n = (((UINT32)(r) >> 31) & 0x01))
386 #define SET_C_ADD(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(~(a))))
387 #define SET_C_SUB(a,b) (dsp_flag_c = ((UINT32)(b) > (UINT32)(a)))
388 #define SET_ZN(r) SET_N(r); SET_Z(r)
389 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
390 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
392 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 };
393 uint8 * dsp_branch_condition_table = NULL;
394 static uint16 * mirror_table = NULL;
395 static uint8 * dsp_ram_8 = NULL;
397 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
399 static uint32 dsp_in_exec = 0;
400 static uint32 dsp_releaseTimeSlice_flag = 0;
405 // Comparison core vars (used only for core comparison! :-)
406 static uint64 count = 0;
407 static uint8 ram1[0x2000], ram2[0x2000];
408 static uint32 regs1[64], regs2[64];
409 static uint32 ctrl1[14], ctrl2[14];
412 // Private function prototypes
414 void DSPDumpRegisters(void);
415 void DSPDumpDisassembly(void);
416 void FlushDSPPipeline(void);
419 void dsp_reset_stats(void)
421 for(int i=0; i<65; i++)
422 dsp_opcode_use[i] = 0;
425 void dsp_releaseTimeslice(void)
427 //This does absolutely nothing!!! !!! FIX !!!
428 dsp_releaseTimeSlice_flag = 1;
431 void dsp_build_branch_condition_table(void)
433 // Allocate the mirror table
435 mirror_table = (uint16 *)malloc(65536 * sizeof(mirror_table[0]));
437 // Fill in the mirror table
439 for(int i=0; i<65536; i++)
440 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
441 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
442 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
443 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
444 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
445 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
446 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
447 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
449 if (!dsp_branch_condition_table)
451 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(dsp_branch_condition_table[0]));
453 // Fill in the condition table
454 if (dsp_branch_condition_table)
456 for(int i=0; i<8; i++)
458 for(int j=0; j<32; j++)
465 if (!(i & ZERO_FLAG))
468 if (i & (CARRY_FLAG << (j >> 4)))
471 if (!(i & (CARRY_FLAG << (j >> 4))))
473 dsp_branch_condition_table[i * 32 + j] = result;
480 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
482 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
483 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
485 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
488 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
490 if (offset==0xF1CFE0)
493 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
494 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
496 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
498 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
500 if ((offset&0x03)==0)
503 if ((offset&0x03)==1)
504 return((data>>16)&0xff);
506 if ((offset&0x03)==2)
507 return((data>>8)&0xff);
509 if ((offset&0x03)==3)
513 return JaguarReadByte(offset, who);
516 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
518 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
519 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
521 offset &= 0xFFFFFFFE;
523 /* if (jaguar_mainRom_crc32==0xa74a97cd)
525 if (offset==0xF1A114) return(0x0000);
526 if (offset==0xF1A116) return(0x0000);
527 if (offset==0xF1B000) return(0x1234);
528 if (offset==0xF1B002) return(0x5678);
531 if (jaguar_mainRom_crc32==0x7ae20823)
533 if (offset==0xF1B9D8) return(0x0000);
534 if (offset==0xF1B9Da) return(0x0000);
535 if (offset==0xF1B2C0) return(0x0000);
536 if (offset==0xF1B2C2) return(0x0000);
539 // pour permettre à wolfenstein 3d de tourner sans le dsp
540 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
544 // pour permettre à nba jam de tourner sans le dsp
545 /* if (jaguar_mainRom_crc32==0x4faddb18)
547 if (offset==0xf1b2c0) return(0);
548 if (offset==0xf1b2c2) return(0);
549 if (offset==0xf1b240) return(0);
550 if (offset==0xf1b242) return(0);
551 if (offset==0xF1B340) return(0);
552 if (offset==0xF1B342) return(0);
553 if (offset==0xF1BAD8) return(0);
554 if (offset==0xF1BADA) return(0);
555 if (offset==0xF1B040) return(0);
556 if (offset==0xF1B042) return(0);
557 if (offset==0xF1B0C0) return(0);
558 if (offset==0xF1B0C2) return(0);
559 if (offset==0xF1B140) return(0);
560 if (offset==0xF1B142) return(0);
561 if (offset==0xF1B1C0) return(0);
562 if (offset==0xF1B1C2) return(0);
565 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
567 offset -= DSP_WORK_RAM_BASE;
568 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
570 return GET16(dsp_ram_8, offset);
572 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
574 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
577 return data & 0xFFFF;
582 return JaguarReadWord(offset, who);
585 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
587 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
588 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
591 offset &= 0xFFFFFFFC;
592 /*if (offset == 0xF1BCF4)
594 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));
595 DSPDumpDisassembly();
597 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
599 offset -= DSP_WORK_RAM_BASE;
600 return GET32(dsp_ram_8, offset);
602 //NOTE: Didn't return DSP_ACCUM!!!
603 //Mebbe it's not 'spose to! Yes, it is!
604 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
609 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
610 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
611 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
613 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
614 return dsp_flags & 0xFFFFC1FF;
615 case 0x04: return dsp_matrix_control;
616 case 0x08: return dsp_pointer_to_matrix;
617 case 0x0C: return dsp_data_organization;
618 case 0x10: return dsp_pc;
619 case 0x14: return dsp_control;
620 case 0x18: return dsp_modulo;
621 case 0x1C: return dsp_remain;
623 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
625 // unaligned long read-- !!! FIX !!!
629 return JaguarReadLong(offset, who);
632 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
634 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
635 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
637 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
639 offset -= DSP_WORK_RAM_BASE;
640 dsp_ram_8[offset] = data;
641 //This is rather stupid! !!! FIX !!!
642 /* if (dsp_in_exec == 0)
644 m68k_end_timeslice();
645 gpu_releaseTimeslice();
649 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
651 uint32 reg = offset & 0x1C;
652 int bytenum = offset & 0x03;
654 if ((reg >= 0x1C) && (reg <= 0x1F))
655 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
658 //This looks funky. !!! FIX !!!
659 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
660 bytenum = 3 - bytenum; // convention motorola !!!
661 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
662 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
666 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
667 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
668 JaguarWriteByte(offset, data, who);
671 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
673 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
674 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
675 offset &= 0xFFFFFFFE;
676 /*if (offset == 0xF1BCF4)
678 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
680 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
681 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
683 /*if (offset == 0xF1B2F4)
685 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
687 offset -= DSP_WORK_RAM_BASE;
688 dsp_ram_8[offset] = data >> 8;
689 dsp_ram_8[offset+1] = data & 0xFF;
690 //This is rather stupid! !!! FIX !!!
691 /* if (dsp_in_exec == 0)
693 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
694 m68k_end_timeslice();
695 gpu_releaseTimeslice();
699 SET16(ram1, offset, data),
700 SET16(ram2, offset, data);
705 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
707 if ((offset & 0x1C) == 0x1C)
710 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
712 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
716 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
718 old_data = (old_data&0xffff0000)|(data&0xffff);
720 old_data = (old_data&0xffff)|((data&0xffff)<<16);
721 DSPWriteLong(offset & 0xffffffc, old_data, who);
726 JaguarWriteWord(offset, data, who);
729 //bool badWrite = false;
730 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
732 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
733 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
735 offset &= 0xFFFFFFFC;
736 /*if (offset == 0xF1BCF4)
738 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
740 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
741 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
743 /*if (offset == 0xF1BE2C)
745 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
747 offset -= DSP_WORK_RAM_BASE;
748 SET32(dsp_ram_8, offset, data);
751 SET32(ram1, offset, data),
752 SET32(ram2, offset, data);
757 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
765 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
767 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
768 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
770 dsp_flag_z = dsp_flags & 0x01;
771 dsp_flag_c = (dsp_flags >> 1) & 0x01;
772 dsp_flag_n = (dsp_flags >> 2) & 0x01;
773 DSPUpdateRegisterBanks();
774 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
775 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
776 /* if (IMASKCleared) // If IMASK was cleared,
779 WriteLog("DSP: Finished interrupt.\n");
781 DSPHandleIRQs(); // see if any other interrupts need servicing!
786 if (/*4-8, 16*/data & 0x101F0)
787 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
788 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
789 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
790 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
791 /*if (data & 0x00020) // CD BIOS DSP code...
793 //001AC1BA: movea.l #$1AC200, A0
794 //001AC1C0: move.l #$1AC68C, D0
797 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
798 uint32 j = 0xF1B97C;//0x1AC200;
799 while (j <= 0xF1BE08)//0x1AC68C)
802 j += dasmjag(JAGUAR_DSP, buffer, j);
803 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
804 WriteLog("\t%08X: %s\n", oldj, buffer);
811 dsp_matrix_control = data;
814 // According to JTRM, only lines 2-11 are addressable, the rest being
815 // hardwired to $F1Bxxx.
816 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
819 dsp_data_organization = data;
824 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
829 ctrl1[0] = ctrl2[0] = data;
836 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
838 bool wasRunning = DSP_RUNNING;
839 // uint32 dsp_was_running = DSP_RUNNING;
840 // Check for DSP -> CPU interrupt
844 WriteLog("DSP: DSP -> CPU interrupt\n");
847 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
848 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
850 JERRYSetPendingIRQ(IRQ2_DSP);
851 dsp_releaseTimeslice();
852 m68k_set_irq(7); // Set 68000 NMI...
856 // Check for CPU -> DSP interrupt
860 WriteLog("DSP: CPU -> DSP interrupt\n");
862 m68k_end_timeslice();
863 gpu_releaseTimeslice();
864 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
868 if (data & SINGLE_STEP)
870 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
873 // Protect writes to VERSION and the interrupt latches...
874 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
875 dsp_control = (dsp_control & mask) | (data & ~mask);
879 ctrl1[8] = ctrl2[8] = dsp_control;
883 // if dsp wasn't running but is now running
884 // execute a few cycles
885 //This is just plain wrong, wrong, WRONG!
886 #ifndef DSP_SINGLE_STEPPING
887 /* if (!dsp_was_running && DSP_RUNNING)
892 //This is WRONG! !!! FIX !!!
893 if (dsp_control & 0x18)
898 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
900 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
903 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
904 // !!! FIX !!! [DONE]
908 m68k_end_timeslice();
910 gpu_releaseTimeslice();
914 //DSPDumpDisassembly();
922 dsp_div_control = data;
924 // default: // unaligned long read
930 //We don't have to break this up like this! We CAN do 32 bit writes!
931 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
932 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
933 //if (offset > 0xF1FFFF)
935 JaguarWriteLong(offset, data, who);
939 // Update the DSP register file pointers depending on REGPAGE bit
941 void DSPUpdateRegisterBanks(void)
943 int bank = (dsp_flags & REGPAGE);
945 if (dsp_flags & IMASK)
946 bank = 0; // IMASK forces main bank to be bank 0
949 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
951 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
955 // Check for and handle any asserted DSP IRQs
957 void DSPHandleIRQs(void)
959 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
962 // Get the active interrupt bits (latches) & interrupt mask (enables)
963 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
964 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
966 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
969 if (!bits) // Bail if nothing is enabled
972 int which = 0; // Determine which interrupt
987 WriteLog("DSP: Generating interrupt #%i...", which);
990 //if (which == 0) doDSPDis = true;
992 // NOTE: Since the actual Jaguar hardware injects the code sequence below
993 // directly into the pipeline, it has the side effect of ensuring that the
994 // instruction interrupted also gets to do its writeback. We simulate that
996 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
998 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
999 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1001 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1002 scoreboard[pipeline[plPtrWrite].operand2] = false;
1004 //This should be execute (or should it?--not sure now!)
1005 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1006 //and what just executed is now in the Write position...). So why didn't it do the
1007 //writeback into register 0?
1008 #ifdef DSP_DEBUG_IRQ
1009 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1010 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]);
1011 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]);
1012 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]);
1014 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1016 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1018 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1019 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1022 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1023 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1024 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1025 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1027 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1031 #ifndef NEW_SCOREBOARD
1032 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1033 scoreboard[pipeline[plPtrWrite].operand2] = false;
1035 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1036 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1037 if (scoreboard[pipeline[plPtrWrite].operand2])
1038 scoreboard[pipeline[plPtrWrite].operand2]--;
1045 ctrl2[4] = dsp_flags;
1048 DSPUpdateRegisterBanks();
1049 #ifdef DSP_DEBUG_IRQ
1050 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1051 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]);
1054 // subqt #4,r31 ; pre-decrement stack pointer
1055 // move pc,r30 ; address of interrupted code
1056 // store r30,(r31) ; store return address
1063 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1064 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1065 //It missed the place that it was supposed to come back to, so this is WRONG!
1067 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1069 // R -> baz (<- PC points here)
1070 // E -> bar (when it should point here!)
1073 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1074 // which means (assuming they're all 2 bytes long) that the code below will come back on
1075 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1076 // instruction stream...
1078 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1079 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1082 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1086 // movei #service_address,r30 ; pointer to ISR entry
1087 // jump (r30) ; jump to ISR
1089 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1092 ctrl2[0] = regs2[30] = dsp_pc;
1099 // Non-pipelined version...
1101 void DSPHandleIRQsNP(void)
1105 memcpy(dsp_ram_8, ram1, 0x2000);
1106 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1107 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1110 dsp_remain = ctrl1[2];
1111 dsp_modulo = ctrl1[3];
1112 dsp_flags = ctrl1[4];
1113 dsp_matrix_control = ctrl1[5];
1114 dsp_pointer_to_matrix = ctrl1[6];
1115 dsp_data_organization = ctrl1[7];
1116 dsp_control = ctrl1[8];
1117 dsp_div_control = ctrl1[9];
1118 IMASKCleared = ctrl1[10];
1119 dsp_flag_z = ctrl1[11];
1120 dsp_flag_n = ctrl1[12];
1121 dsp_flag_c = ctrl1[13];
1122 DSPUpdateRegisterBanks();
1125 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1128 // Get the active interrupt bits (latches) & interrupt mask (enables)
1129 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1130 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1132 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1135 if (!bits) // Bail if nothing is enabled
1138 int which = 0; // Determine which interrupt
1152 #ifdef DSP_DEBUG_IRQ
1153 WriteLog("DSP: Generating interrupt #%i...", which);
1159 ctrl1[4] = dsp_flags;
1162 DSPUpdateRegisterBanks();
1163 #ifdef DSP_DEBUG_IRQ
1164 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1167 // subqt #4,r31 ; pre-decrement stack pointer
1168 // move pc,r30 ; address of interrupted code
1169 // store r30,(r31) ; store return address
1176 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1179 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1183 // movei #service_address,r30 ; pointer to ISR entry
1184 // jump (r30) ; jump to ISR
1186 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1189 ctrl1[0] = regs1[30] = dsp_pc;
1195 // Set the specified DSP IRQ line to a given state
1197 void DSPSetIRQLine(int irqline, int state)
1199 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1200 uint32 mask = INT_LAT0 << irqline;
1201 dsp_control &= ~mask; // Clear the latch bit
1204 ctrl1[8] = ctrl2[8] = dsp_control;
1210 dsp_control |= mask; // Set the latch bit
1214 ctrl1[8] = ctrl2[8] = dsp_control;
1220 // Not sure if this is correct behavior, but according to JTRM,
1221 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1222 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1223 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1228 memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1229 memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1230 memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1232 dsp_build_branch_condition_table();
1238 dsp_pc = 0x00F1B000;
1239 dsp_acc = 0x00000000;
1240 dsp_remain = 0x00000000;
1241 dsp_modulo = 0xFFFFFFFF;
1242 dsp_flags = 0x00040000;
1243 dsp_matrix_control = 0x00000000;
1244 dsp_pointer_to_matrix = 0x00000000;
1245 dsp_data_organization = 0xFFFFFFFF;
1246 dsp_control = 0x00002000; // Report DSP version 2
1247 dsp_div_control = 0x00000000;
1250 dsp_reg = dsp_reg_bank_0;
1251 dsp_alternate_reg = dsp_reg_bank_1;
1253 for(int i=0; i<32; i++)
1254 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1257 IMASKCleared = false;
1260 memset(dsp_ram_8, 0xFF, 0x2000);
1263 void DSPDumpDisassembly(void)
1267 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1268 uint32 j = 0xF1B000;
1269 while (j <= 0xF1CFFF)
1272 j += dasmjag(JAGUAR_DSP, buffer, j);
1273 WriteLog("\t%08X: %s\n", oldj, buffer);
1277 void DSPDumpRegisters(void)
1279 //Shoud add modulus, etc to dump here...
1280 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1281 WriteLog("\nRegisters bank 0\n");
1282 for(int j=0; j<8; j++)
1284 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1285 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1286 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1287 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1288 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1290 WriteLog("Registers bank 1\n");
1291 for(int j=0; j<8; j++)
1293 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1294 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1295 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1296 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1297 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1304 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1305 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1307 // get the active interrupt bits
1308 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1309 // get the interrupt mask
1310 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1312 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1313 WriteLog("\nRegisters bank 0\n");
1314 for(int j=0; j<8; j++)
1316 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1317 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1318 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1319 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1320 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1322 WriteLog("\nRegisters bank 1\n");
1325 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1326 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1327 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1328 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1329 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1333 static char buffer[512];
1334 j = DSP_WORK_RAM_BASE;
1335 while (j <= 0xF1BFFF)
1338 j += dasmjag(JAGUAR_DSP, buffer, j);
1339 WriteLog("\t%08X: %s\n", oldj, buffer);
1342 WriteLog("DSP opcodes use:\n");
1345 if (dsp_opcode_use[i])
1346 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1349 memory_free(dsp_ram_8);
1350 memory_free(dsp_reg_bank_0);
1351 memory_free(dsp_reg_bank_1);
1357 // DSP comparison core...
1360 static uint16 lastExec;
1361 void DSPExecComp(int32 cycles)
1363 while (cycles > 0 && DSP_RUNNING)
1365 // Load up vars for non-pipelined core
1366 memcpy(dsp_ram_8, ram1, 0x2000);
1367 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1368 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1371 dsp_remain = ctrl1[2];
1372 dsp_modulo = ctrl1[3];
1373 dsp_flags = ctrl1[4];
1374 dsp_matrix_control = ctrl1[5];
1375 dsp_pointer_to_matrix = ctrl1[6];
1376 dsp_data_organization = ctrl1[7];
1377 dsp_control = ctrl1[8];
1378 dsp_div_control = ctrl1[9];
1379 IMASKCleared = ctrl1[10];
1380 dsp_flag_z = ctrl1[11];
1381 dsp_flag_n = ctrl1[12];
1382 dsp_flag_c = ctrl1[13];
1383 DSPUpdateRegisterBanks();
1385 // Decrement cycles based on non-pipelined core...
1386 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1387 cycles -= dsp_opcode_cycles[instr1 >> 10];
1389 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1390 DSPExec(1); // Do *one* instruction
1393 memcpy(ram1, dsp_ram_8, 0x2000);
1394 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1395 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1398 ctrl1[2] = dsp_remain;
1399 ctrl1[3] = dsp_modulo;
1400 ctrl1[4] = dsp_flags;
1401 ctrl1[5] = dsp_matrix_control;
1402 ctrl1[6] = dsp_pointer_to_matrix;
1403 ctrl1[7] = dsp_data_organization;
1404 ctrl1[8] = dsp_control;
1405 ctrl1[9] = dsp_div_control;
1406 ctrl1[10] = IMASKCleared;
1407 ctrl1[11] = dsp_flag_z;
1408 ctrl1[12] = dsp_flag_n;
1409 ctrl1[13] = dsp_flag_c;
1411 // Load up vars for pipelined core
1412 memcpy(dsp_ram_8, ram2, 0x2000);
1413 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1414 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1417 dsp_remain = ctrl2[2];
1418 dsp_modulo = ctrl2[3];
1419 dsp_flags = ctrl2[4];
1420 dsp_matrix_control = ctrl2[5];
1421 dsp_pointer_to_matrix = ctrl2[6];
1422 dsp_data_organization = ctrl2[7];
1423 dsp_control = ctrl2[8];
1424 dsp_div_control = ctrl2[9];
1425 IMASKCleared = ctrl2[10];
1426 dsp_flag_z = ctrl2[11];
1427 dsp_flag_n = ctrl2[12];
1428 dsp_flag_c = ctrl2[13];
1429 DSPUpdateRegisterBanks();
1431 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1432 DSPExecP2(1); // Do *one* instruction
1435 memcpy(ram2, dsp_ram_8, 0x2000);
1436 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1437 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1440 ctrl2[2] = dsp_remain;
1441 ctrl2[3] = dsp_modulo;
1442 ctrl2[4] = dsp_flags;
1443 ctrl2[5] = dsp_matrix_control;
1444 ctrl2[6] = dsp_pointer_to_matrix;
1445 ctrl2[7] = dsp_data_organization;
1446 ctrl2[8] = dsp_control;
1447 ctrl2[9] = dsp_div_control;
1448 ctrl2[10] = IMASKCleared;
1449 ctrl2[11] = dsp_flag_z;
1450 ctrl2[12] = dsp_flag_n;
1451 ctrl2[13] = dsp_flag_c;
1453 if (instr1 != lastExec)
1455 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1457 // 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));
1458 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1459 // if (ctrl1[0] < ppc) // P ran ahead of NP
1460 //How to test this crap???
1463 DSPExecP2(1); // Do one more instruction
1466 memcpy(ram2, dsp_ram_8, 0x2000);
1467 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1468 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1471 ctrl2[2] = dsp_remain;
1472 ctrl2[3] = dsp_modulo;
1473 ctrl2[4] = dsp_flags;
1474 ctrl2[5] = dsp_matrix_control;
1475 ctrl2[6] = dsp_pointer_to_matrix;
1476 ctrl2[7] = dsp_data_organization;
1477 ctrl2[8] = dsp_control;
1478 ctrl2[9] = dsp_div_control;
1479 ctrl2[10] = IMASKCleared;
1480 ctrl2[11] = dsp_flag_z;
1481 ctrl2[12] = dsp_flag_n;
1482 ctrl2[13] = dsp_flag_c;
1484 // else // NP ran ahead of P
1485 if (instr1 != lastExec) // Must be the other way...
1488 // Load up vars for non-pipelined core
1489 memcpy(dsp_ram_8, ram1, 0x2000);
1490 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1491 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1494 dsp_remain = ctrl1[2];
1495 dsp_modulo = ctrl1[3];
1496 dsp_flags = ctrl1[4];
1497 dsp_matrix_control = ctrl1[5];
1498 dsp_pointer_to_matrix = ctrl1[6];
1499 dsp_data_organization = ctrl1[7];
1500 dsp_control = ctrl1[8];
1501 dsp_div_control = ctrl1[9];
1502 IMASKCleared = ctrl1[10];
1503 dsp_flag_z = ctrl1[11];
1504 dsp_flag_n = ctrl1[12];
1505 dsp_flag_c = ctrl1[13];
1506 DSPUpdateRegisterBanks();
1508 for(int k=0; k<2; k++)
1510 // Decrement cycles based on non-pipelined core...
1511 instr1 = DSPReadWord(dsp_pc, DSP);
1512 cycles -= dsp_opcode_cycles[instr1 >> 10];
1514 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1515 DSPExec(1); // Do *one* instruction
1519 memcpy(ram1, dsp_ram_8, 0x2000);
1520 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1521 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1524 ctrl1[2] = dsp_remain;
1525 ctrl1[3] = dsp_modulo;
1526 ctrl1[4] = dsp_flags;
1527 ctrl1[5] = dsp_matrix_control;
1528 ctrl1[6] = dsp_pointer_to_matrix;
1529 ctrl1[7] = dsp_data_organization;
1530 ctrl1[8] = dsp_control;
1531 ctrl1[9] = dsp_div_control;
1532 ctrl1[10] = IMASKCleared;
1533 ctrl1[11] = dsp_flag_z;
1534 ctrl1[12] = dsp_flag_n;
1535 ctrl1[13] = dsp_flag_c;
1539 if (instr1 != lastExec)
1541 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1543 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1544 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1557 // DSP execution core
1559 //static bool R20Set = false, tripwire = false;
1560 //static uint32 pcQueue[32], ptrPCQ = 0;
1561 void DSPExec(int32 cycles)
1563 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1564 dsp_check_if_i2s_interrupt_needed();*/
1566 #ifdef DSP_SINGLE_STEPPING
1567 if (dsp_control & 0x18)
1570 dsp_control &= ~0x10;
1573 //There is *no* good reason to do this here!
1575 dsp_releaseTimeSlice_flag = 0;
1578 while (cycles > 0 && DSP_RUNNING)
1580 /*extern uint32 totalFrames;
1581 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1582 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1583 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1585 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1588 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1590 if (dsp_pc == 0xF1B092)
1591 doDSPDis = false;//*/
1592 /*if (dsp_pc == 0xF1B140)
1593 doDSPDis = true;//*/
1595 if (IMASKCleared) // If IMASK was cleared,
1597 #ifdef DSP_DEBUG_IRQ
1598 WriteLog("DSP: Finished interrupt.\n");
1600 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1601 IMASKCleared = false;
1606 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1607 for(int i=0; i<80; i+=4)
1608 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1611 /*if (dsp_pc == 0xF1B55E)
1613 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1615 /*if (dsp_pc == 0xF1B7D2) // Start here???
1617 pcQueue[ptrPCQ++] = dsp_pc;
1619 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1620 uint32 index = opcode >> 10;
1621 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1622 dsp_opcode_second_parameter = opcode & 0x1F;
1624 dsp_opcode[index]();
1625 dsp_opcode_use[index]++;
1626 cycles -= dsp_opcode_cycles[index];
1627 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1629 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1632 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1634 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1636 DSPDumpDisassembly();
1639 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1642 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1645 WriteLog("\nBacktrace:\n");
1646 for(int i=0; i<32; i++)
1648 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1649 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1659 // DSP opcode handlers
1662 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1663 // can cause trouble because an interrupt can occur *before* the instruction following the
1664 // jump can execute... !!! FIX !!!
1665 static void dsp_opcode_jump(void)
1668 char * condition[32] =
1669 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1670 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1671 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1672 "???", "???", "???", "F" };
1674 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);
1677 /* dsp_flag_c=dsp_flag_c?1:0;
1678 dsp_flag_z=dsp_flag_z?1:0;
1679 dsp_flag_n=dsp_flag_n?1:0;*/
1680 // KLUDGE: Used by BRANCH_CONDITION
1681 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1683 if (BRANCH_CONDITION(IMM_2))
1687 WriteLog("Branched!\n");
1689 uint32 delayed_pc = RM;
1691 dsp_pc = delayed_pc;
1696 WriteLog("Branch NOT taken.\n");
1700 static void dsp_opcode_jr(void)
1703 char * condition[32] =
1704 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1705 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1706 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1707 "???", "???", "???", "F" };
1709 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);
1712 /* dsp_flag_c=dsp_flag_c?1:0;
1713 dsp_flag_z=dsp_flag_z?1:0;
1714 dsp_flag_n=dsp_flag_n?1:0;*/
1715 // KLUDGE: Used by BRANCH_CONDITION
1716 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1718 if (BRANCH_CONDITION(IMM_2))
1722 WriteLog("Branched!\n");
1724 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1725 int32 delayed_pc = dsp_pc + (offset * 2);
1727 dsp_pc = delayed_pc;
1732 WriteLog("Branch NOT taken.\n");
1736 static void dsp_opcode_add(void)
1740 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);
1742 UINT32 res = RN + RM;
1743 SET_ZNC_ADD(RN, RM, res);
1747 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);
1751 static void dsp_opcode_addc(void)
1755 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);
1757 UINT32 res = RN + RM + dsp_flag_c;
1758 UINT32 carry = dsp_flag_c;
1759 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1760 SET_ZNC_ADD(RN + carry, RM, res);
1761 // SET_ZNC_ADD(RN, RM + carry, res);
1765 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);
1769 static void dsp_opcode_addq(void)
1773 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);
1775 UINT32 r1 = dsp_convert_zero[IMM_1];
1776 UINT32 res = RN + r1;
1777 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1781 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1785 static void dsp_opcode_sub(void)
1789 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);
1791 UINT32 res = RN - RM;
1792 SET_ZNC_SUB(RN, RM, res);
1796 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);
1800 static void dsp_opcode_subc(void)
1804 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);
1806 UINT32 res = RN - RM - dsp_flag_c;
1807 UINT32 borrow = dsp_flag_c;
1808 SET_ZNC_SUB(RN - borrow, RM, res);
1812 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);
1816 static void dsp_opcode_subq(void)
1820 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);
1822 UINT32 r1 = dsp_convert_zero[IMM_1];
1823 UINT32 res = RN - r1;
1824 SET_ZNC_SUB(RN, r1, res);
1828 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1832 static void dsp_opcode_cmp(void)
1836 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);
1838 UINT32 res = RN - RM;
1839 SET_ZNC_SUB(RN, RM, res);
1842 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1846 static void dsp_opcode_cmpq(void)
1848 static int32 sqtable[32] =
1849 { 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 };
1852 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);
1854 UINT32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1855 UINT32 res = RN - r1;
1856 SET_ZNC_SUB(RN, r1, res);
1859 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1863 static void dsp_opcode_and(void)
1867 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);
1873 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);
1877 static void dsp_opcode_or(void)
1881 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);
1887 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);
1891 static void dsp_opcode_xor(void)
1895 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);
1901 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1905 static void dsp_opcode_not(void)
1909 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);
1915 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1919 static void dsp_opcode_move_pc(void)
1924 static void dsp_opcode_store_r14_indexed(void)
1926 #ifdef DSP_DIS_STORE14I
1928 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));
1930 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1933 static void dsp_opcode_store_r15_indexed(void)
1935 #ifdef DSP_DIS_STORE15I
1937 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));
1939 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1942 static void dsp_opcode_load_r14_ri(void)
1944 #ifdef DSP_DIS_LOAD14R
1946 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);
1948 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1949 #ifdef DSP_DIS_LOAD14R
1951 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1955 static void dsp_opcode_load_r15_ri(void)
1957 #ifdef DSP_DIS_LOAD15R
1959 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);
1961 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1962 #ifdef DSP_DIS_LOAD15R
1964 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1968 static void dsp_opcode_store_r14_ri(void)
1970 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1973 static void dsp_opcode_store_r15_ri(void)
1975 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1978 static void dsp_opcode_nop(void)
1982 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1986 static void dsp_opcode_storeb(void)
1988 #ifdef DSP_DIS_STOREB
1990 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);
1992 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1993 DSPWriteLong(RM, RN & 0xFF, DSP);
1995 JaguarWriteByte(RM, RN, DSP);
1998 static void dsp_opcode_storew(void)
2000 #ifdef DSP_DIS_STOREW
2002 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);
2004 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2005 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2007 JaguarWriteWord(RM, RN, DSP);
2010 static void dsp_opcode_store(void)
2012 #ifdef DSP_DIS_STORE
2014 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);
2016 DSPWriteLong(RM, RN, DSP);
2019 static void dsp_opcode_loadb(void)
2021 #ifdef DSP_DIS_LOADB
2023 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);
2025 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2026 RN = DSPReadLong(RM, DSP) & 0xFF;
2028 RN = JaguarReadByte(RM, DSP);
2029 #ifdef DSP_DIS_LOADB
2031 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2035 static void dsp_opcode_loadw(void)
2037 #ifdef DSP_DIS_LOADW
2039 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);
2041 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2042 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2044 RN = JaguarReadWord(RM, DSP);
2045 #ifdef DSP_DIS_LOADW
2047 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2051 static void dsp_opcode_load(void)
2055 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);
2057 RN = DSPReadLong(RM, DSP);
2060 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2064 static void dsp_opcode_load_r14_indexed(void)
2066 #ifdef DSP_DIS_LOAD14I
2068 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);
2070 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2071 #ifdef DSP_DIS_LOAD14I
2073 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2077 static void dsp_opcode_load_r15_indexed(void)
2079 #ifdef DSP_DIS_LOAD15I
2081 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);
2083 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2084 #ifdef DSP_DIS_LOAD15I
2086 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2090 static void dsp_opcode_movei(void)
2092 #ifdef DSP_DIS_MOVEI
2094 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);
2096 // This instruction is followed by 32-bit value in LSW / MSW format...
2097 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2099 #ifdef DSP_DIS_MOVEI
2101 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2105 static void dsp_opcode_moveta(void)
2107 #ifdef DSP_DIS_MOVETA
2109 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);
2112 #ifdef DSP_DIS_MOVETA
2114 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);
2118 static void dsp_opcode_movefa(void)
2120 #ifdef DSP_DIS_MOVEFA
2122 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);
2125 #ifdef DSP_DIS_MOVEFA
2127 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);
2131 static void dsp_opcode_move(void)
2135 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);
2140 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);
2144 static void dsp_opcode_moveq(void)
2146 #ifdef DSP_DIS_MOVEQ
2148 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);
2151 #ifdef DSP_DIS_MOVEQ
2153 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2157 static void dsp_opcode_resmac(void)
2159 #ifdef DSP_DIS_RESMAC
2161 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));
2163 RN = (uint32)dsp_acc;
2164 #ifdef DSP_DIS_RESMAC
2166 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2170 static void dsp_opcode_imult(void)
2172 #ifdef DSP_DIS_IMULT
2174 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);
2176 RN = (int16)RN * (int16)RM;
2178 #ifdef DSP_DIS_IMULT
2180 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);
2184 static void dsp_opcode_mult(void)
2188 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);
2190 RN = (uint16)RM * (uint16)RN;
2194 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);
2198 static void dsp_opcode_bclr(void)
2202 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);
2204 UINT32 res = RN & ~(1 << IMM_1);
2209 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2213 static void dsp_opcode_btst(void)
2217 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);
2219 dsp_flag_z = (~RN >> IMM_1) & 1;
2222 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2226 static void dsp_opcode_bset(void)
2230 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);
2232 UINT32 res = RN | (1 << IMM_1);
2237 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2241 static void dsp_opcode_subqt(void)
2243 #ifdef DSP_DIS_SUBQT
2245 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);
2247 RN -= dsp_convert_zero[IMM_1];
2248 #ifdef DSP_DIS_SUBQT
2250 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2254 static void dsp_opcode_addqt(void)
2256 #ifdef DSP_DIS_ADDQT
2258 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);
2260 RN += dsp_convert_zero[IMM_1];
2261 #ifdef DSP_DIS_ADDQT
2263 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2267 static void dsp_opcode_imacn(void)
2269 #ifdef DSP_DIS_IMACN
2271 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);
2273 int32 res = (int16)RM * (int16)RN;
2274 dsp_acc += (int64)res;
2275 //Should we AND the result to fit into 40 bits here???
2276 #ifdef DSP_DIS_IMACN
2278 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));
2282 static void dsp_opcode_mtoi(void)
2284 RN = (((INT32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2288 static void dsp_opcode_normi(void)
2295 while ((_Rm & 0xffc00000) == 0)
2300 while ((_Rm & 0xff800000) != 0)
2310 static void dsp_opcode_mmult(void)
2312 int count = dsp_matrix_control&0x0f;
2313 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2317 if (!(dsp_matrix_control & 0x10))
2319 for (int i = 0; i < count; i++)
2323 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2325 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2326 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2333 for (int i = 0; i < count; i++)
2337 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2339 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2340 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2345 RN = res = (int32)accum;
2347 //NOTE: The flags are set based upon the last add/multiply done...
2351 static void dsp_opcode_abs(void)
2355 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);
2360 if (_Rn == 0x80000000)
2364 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2365 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2370 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2374 static void dsp_opcode_div(void)
2381 if (dsp_div_control & 1)
2383 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2384 if (dsp_remain&0x80000000)
2386 RN = (((uint64)_Rn) << 16) / _Rm;
2390 dsp_remain = _Rn % _Rm;
2391 if (dsp_remain&0x80000000)
2400 static void dsp_opcode_imultn(void)
2402 #ifdef DSP_DIS_IMULTN
2404 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);
2406 // This is OK, since this multiply won't overflow 32 bits...
2407 int32 res = (int32)((int16)RN * (int16)RM);
2408 dsp_acc = (int64)res;
2410 #ifdef DSP_DIS_IMULTN
2412 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));
2416 static void dsp_opcode_neg(void)
2420 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);
2423 SET_ZNC_SUB(0, RN, res);
2427 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2431 static void dsp_opcode_shlq(void)
2435 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);
2437 INT32 r1 = 32 - IMM_1;
2438 UINT32 res = RN << r1;
2439 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2443 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2447 static void dsp_opcode_shrq(void)
2451 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);
2453 INT32 r1 = dsp_convert_zero[IMM_1];
2454 UINT32 res = RN >> r1;
2455 SET_ZN(res); dsp_flag_c = RN & 1;
2459 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2463 static void dsp_opcode_ror(void)
2467 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);
2469 UINT32 r1 = RM & 0x1F;
2470 UINT32 res = (RN >> r1) | (RN << (32 - r1));
2471 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2475 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);
2479 static void dsp_opcode_rorq(void)
2483 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);
2485 UINT32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2487 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
2489 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2492 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2496 static void dsp_opcode_sha(void)
2498 int32 sRm=(int32)RM;
2504 if (shift>=32) shift=32;
2505 dsp_flag_c=(_Rn&0x80000000)>>31;
2515 if (shift>=32) shift=32;
2519 _Rn=((int32)_Rn)>>1;
2527 static void dsp_opcode_sharq(void)
2529 #ifdef DSP_DIS_SHARQ
2531 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);
2533 UINT32 res = (INT32)RN >> dsp_convert_zero[IMM_1];
2534 SET_ZN(res); dsp_flag_c = RN & 0x01;
2536 #ifdef DSP_DIS_SHARQ
2538 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2542 static void dsp_opcode_sh(void)
2544 int32 sRm=(int32)RM;
2549 uint32 shift=(-sRm);
2550 if (shift>=32) shift=32;
2551 dsp_flag_c=(_Rn&0x80000000)>>31;
2561 if (shift>=32) shift=32;
2573 void dsp_opcode_addqmod(void)
2575 #ifdef DSP_DIS_ADDQMOD
2577 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);
2579 UINT32 r1 = dsp_convert_zero[IMM_1];
2581 UINT32 res = r2 + r1;
2582 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2584 SET_ZNC_ADD(r2, r1, res);
2585 #ifdef DSP_DIS_ADDQMOD
2587 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2591 void dsp_opcode_subqmod(void)
2593 UINT32 r1 = dsp_convert_zero[IMM_1];
2595 UINT32 res = r2 - r1;
2596 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2599 SET_ZNC_SUB(r2, r1, res);
2602 void dsp_opcode_mirror(void)
2605 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2609 void dsp_opcode_sat32s(void)
2611 INT32 r2 = (UINT32)RN;
2612 INT32 temp = dsp_acc >> 32;
2613 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
2618 void dsp_opcode_sat16s(void)
2621 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2627 // New pipelined DSP core
2630 static void DSP_abs(void);
2631 static void DSP_add(void);
2632 static void DSP_addc(void);
2633 static void DSP_addq(void);
2634 static void DSP_addqmod(void);
2635 static void DSP_addqt(void);
2636 static void DSP_and(void);
2637 static void DSP_bclr(void);
2638 static void DSP_bset(void);
2639 static void DSP_btst(void);
2640 static void DSP_cmp(void);
2641 static void DSP_cmpq(void);
2642 static void DSP_div(void);
2643 static void DSP_imacn(void);
2644 static void DSP_imult(void);
2645 static void DSP_imultn(void);
2646 static void DSP_illegal(void);
2647 static void DSP_jr(void);
2648 static void DSP_jump(void);
2649 static void DSP_load(void);
2650 static void DSP_loadb(void);
2651 static void DSP_loadw(void);
2652 static void DSP_load_r14_i(void);
2653 static void DSP_load_r14_r(void);
2654 static void DSP_load_r15_i(void);
2655 static void DSP_load_r15_r(void);
2656 static void DSP_mirror(void);
2657 static void DSP_mmult(void);
2658 static void DSP_move(void);
2659 static void DSP_movefa(void);
2660 static void DSP_movei(void);
2661 static void DSP_movepc(void);
2662 static void DSP_moveq(void);
2663 static void DSP_moveta(void);
2664 static void DSP_mtoi(void);
2665 static void DSP_mult(void);
2666 static void DSP_neg(void);
2667 static void DSP_nop(void);
2668 static void DSP_normi(void);
2669 static void DSP_not(void);
2670 static void DSP_or(void);
2671 static void DSP_resmac(void);
2672 static void DSP_ror(void);
2673 static void DSP_rorq(void);
2674 static void DSP_sat16s(void);
2675 static void DSP_sat32s(void);
2676 static void DSP_sh(void);
2677 static void DSP_sha(void);
2678 static void DSP_sharq(void);
2679 static void DSP_shlq(void);
2680 static void DSP_shrq(void);
2681 static void DSP_store(void);
2682 static void DSP_storeb(void);
2683 static void DSP_storew(void);
2684 static void DSP_store_r14_i(void);
2685 static void DSP_store_r14_r(void);
2686 static void DSP_store_r15_i(void);
2687 static void DSP_store_r15_r(void);
2688 static void DSP_sub(void);
2689 static void DSP_subc(void);
2690 static void DSP_subq(void);
2691 static void DSP_subqmod(void);
2692 static void DSP_subqt(void);
2693 static void DSP_xor(void);
2695 void (* DSPOpcode[64])() =
2697 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2698 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2699 DSP_neg, DSP_and, DSP_or, DSP_xor,
2700 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2702 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2703 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2704 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2705 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2707 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2708 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2709 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2710 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2712 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2713 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2714 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2715 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2718 bool readAffected[64][2] =
2720 { true, true}, { true, true}, {false, true}, {false, true},
2721 { true, true}, { true, true}, {false, true}, {false, true},
2722 {false, true}, { true, true}, { true, true}, { true, true},
2723 {false, true}, {false, true}, {false, true}, {false, true},
2725 { true, true}, { true, true}, { true, true}, {false, true},
2726 { true, true}, { true, true}, {false, true}, { true, true},
2727 {false, true}, {false, true}, { true, true}, {false, true},
2728 { true, true}, {false, true}, { true, true}, {false, true},
2730 {false, true}, {false, true}, { true, false}, {false, false},
2731 { true, false}, {false, false}, {false, false}, { true, false},
2732 { true, false}, { true, false}, {false, true}, { true, false},
2733 { true, false}, { true, true}, { true, true}, { true, true},
2735 {false, true}, { true, true}, { true, true}, {false, true},
2736 { true, false}, { true, false}, { true, true}, { true, false},
2737 { true, false}, {false, false}, { true, false}, { true, false},
2738 { true, true}, { true, true}, {false, false}, {false, true}
2741 bool isLoadStore[65] =
2743 false, false, false, false, false, false, false, false,
2744 false, false, false, false, false, false, false, false,
2746 false, false, false, false, false, false, false, false,
2747 false, false, false, false, false, false, false, false,
2749 false, false, false, false, false, false, false, true,
2750 true, true, false, true, true, true, true, true,
2752 false, true, true, false, false, false, false, false,
2753 false, false, true, true, true, true, false, false, false
2756 void FlushDSPPipeline(void)
2758 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2760 for(int i=0; i<4; i++)
2761 pipeline[i].opcode = PIPELINE_STALL;
2763 for(int i=0; i<32; i++)
2768 // New pipelined DSP execution core
2770 /*void DSPExecP(int32 cycles)
2772 // bool inhibitFetch = false;
2774 dsp_releaseTimeSlice_flag = 0;
2777 while (cycles > 0 && DSP_RUNNING)
2779 WriteLog("DSPExecP: Pipeline status...\n");
2780 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);
2781 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);
2782 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);
2783 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);
2784 WriteLog(" --> Scoreboard: ");
2785 for(int i=0; i<32; i++)
2786 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2788 // Stage 1: Instruction fetch
2789 // if (!inhibitFetch)
2791 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2792 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2793 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2794 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2795 if (pipeline[plPtrFetch].opcode == 38)
2796 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2797 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2800 // inhibitFetch = false;
2801 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2803 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2804 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);
2805 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);
2806 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);
2807 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);
2808 // Stage 2: Read registers
2809 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2810 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2811 if (scoreboard[pipeline[plPtrRead].operand2])
2812 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2813 // We have a hit in the scoreboard, so we have to stall the pipeline...
2815 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2816 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2817 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2818 pipeline[plPtrFetch] = pipeline[plPtrRead];
2819 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2823 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2824 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2825 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2827 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2828 // Shouldn't we be more selective with the register scoreboarding?
2829 // Yes, we should. !!! FIX !!!
2830 scoreboard[pipeline[plPtrRead].operand2] = true;
2831 //Advance PC here??? Yes.
2832 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2833 //This is a mangling of the pipeline stages, but what else to do???
2834 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2837 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2838 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);
2839 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);
2840 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);
2841 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);
2843 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2845 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2846 DSPOpcode[pipeline[plPtrExec].opcode]();
2847 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2848 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2853 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2854 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);
2855 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);
2856 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);
2857 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);
2858 // Stage 4: Write back register
2859 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2861 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2862 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2864 scoreboard[pipeline[plPtrWrite].operand1]
2865 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2868 // Push instructions through the pipeline...
2869 plPtrFetch = (++plPtrFetch) & 0x03;
2870 plPtrRead = (++plPtrRead) & 0x03;
2871 plPtrExec = (++plPtrExec) & 0x03;
2872 plPtrWrite = (++plPtrWrite) & 0x03;
2879 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2881 // Should be fixed now. Another problem is figuring how to do the sequence following
2882 // a branch followed with the JR & JUMP instructions...
2884 // There are two conflicting problems:
2887 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2888 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2889 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2890 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2891 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2892 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2893 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2894 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2895 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2896 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2897 DSP: Finished interrupt.
2898 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2899 ; bank 0 (where is was prepared)!
2900 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2901 F1B252: NOP [NCZ:001]
2904 // The other is when you see this at the end of an IRQ:
2907 JUMP T, (R29) ; R29 = Previous stack + 2
2908 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2910 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2911 ; 1) The STORE goes through the pipeline and is executed/written back
2912 ; 2) The pipeline is flushed
2913 ; 3) The DSP_PC is set to the new address
2914 ; 4) Execution resumes
2916 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2917 ; bank 0 instead of the current bank 1 and so goes astray!
2920 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2921 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2925 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2926 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2927 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2928 If it were done properly, the STORE write back would occur *after* (well, technically,
2929 during) the execution of the the JUMP that follows it.
2933 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2934 F1B08A: NOP [NCZ:001]
2936 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2939 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2942 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2943 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2944 F1B08A: NOP [NCZ:001]
2946 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2949 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2950 DSP: CPU -> DSP interrupt
2951 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2952 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2954 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2957 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2958 F1B006: NOP [NCZ:001]
2960 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2963 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2964 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2967 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2968 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2971 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2972 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2975 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2976 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
2979 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
2982 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
2985 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
2986 F1B0FE: NOP [NCZ:000]
2988 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
2991 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
2994 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
2995 F1B138: NOP [NCZ:000]
2997 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3000 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3001 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3002 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3005 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3006 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3009 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3010 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3011 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3013 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3014 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3017 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3018 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3019 DSP: Finished interrupt.
3020 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3022 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3025 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3026 F1B016: NOP [NCZ:001]
3028 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3031 uint32 pcQueue1[0x400];
3033 static uint32 prevR1;
3034 //Let's try a 3 stage pipeline....
3035 //Looks like 3 stage is correct, otherwise bad things happen...
3036 void DSPExecP2(int32 cycles)
3038 dsp_releaseTimeSlice_flag = 0;
3041 while (cycles > 0 && DSP_RUNNING)
3043 /*extern uint32 totalFrames;
3044 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3045 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3046 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3048 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3051 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3053 if (dsp_pc == 0xF1B092)
3054 doDSPDis = false;//*/
3055 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3056 doDSPDis = true;//*/
3057 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3058 doDSPDis = true;//*/
3059 /*if (dsp_pc == 0xF1B0A0)
3060 doDSPDis = true;//*/
3061 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3062 doDSPDis = true;//*/
3063 //Two parter... (not sure how to write this)
3064 //if (dsp_pc == 0xF1B0D2)
3065 // prevR1 = dsp_reg[1];
3067 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3068 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3071 pcQueue1[pcQPtr1++] = dsp_pc;
3074 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3076 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3081 for(int i=0; i<0x400; i++)
3083 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3084 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3088 if (IMASKCleared) // If IMASK was cleared,
3090 #ifdef DSP_DEBUG_IRQ
3091 WriteLog("DSP: Finished interrupt.\n");
3093 DSPHandleIRQs(); // See if any other interrupts are pending!
3094 IMASKCleared = false;
3097 //if (dsp_flags & REGPAGE)
3098 // WriteLog(" --> REGPAGE has just been set!\n");
3099 #ifdef DSP_DEBUG_PL2
3102 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3103 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]);
3104 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]);
3105 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]);
3106 WriteLog(" --> Scoreboard: ");
3107 for(int i=0; i<32; i++)
3108 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3112 // Stage 1a: Instruction fetch
3113 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3114 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3115 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3116 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3117 if (pipeline[plPtrRead].opcode == 38)
3118 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3119 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3120 #ifdef DSP_DEBUG_PL2
3123 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3124 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3125 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]);
3126 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]);
3127 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]);
3130 // Stage 1b: Read registers
3131 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3132 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3134 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3135 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3136 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3137 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3138 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3139 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3140 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3142 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3143 // We have a hit in the scoreboard, so we have to stall the pipeline...
3144 #ifdef DSP_DEBUG_PL2
3148 WriteLog(" --> Stalling pipeline: ");
3149 if (readAffected[pipeline[plPtrRead].opcode][0])
3150 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3151 if (readAffected[pipeline[plPtrRead].opcode][1])
3152 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3156 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3157 #ifdef DSP_DEBUG_PL2
3162 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3163 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3164 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3166 // Shouldn't we be more selective with the register scoreboarding?
3167 // Yes, we should. !!! FIX !!! Kinda [DONE]
3168 #ifndef NEW_SCOREBOARD
3169 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3171 //Hopefully this will fix the dual MOVEQ # problem...
3172 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3175 //Advance PC here??? Yes.
3176 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3179 #ifdef DSP_DEBUG_PL2
3182 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3183 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]);
3184 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]);
3185 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]);
3189 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3192 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"));
3193 #ifdef DSP_DEBUG_PL2
3196 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3201 lastExec = pipeline[plPtrExec].instruction;
3202 //WriteLog("[lastExec = %04X]\n", lastExec);
3204 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3205 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3206 DSPOpcode[pipeline[plPtrExec].opcode]();
3207 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3211 //Let's not, until we do the stalling correctly...
3212 //But, we gotta while we're doing the comparison core...!
3213 //Or do we? cycles--;
3214 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3215 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3216 //to model this clock cycle behavior correctly...
3217 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3218 //don't affect the reads at stage 1...
3219 #ifdef DSP_DEBUG_STALL
3221 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3225 #ifdef DSP_DEBUG_PL2
3228 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3229 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]);
3230 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]);
3231 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]);
3235 // Stage 3: Write back register/memory address
3236 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3238 /*if (pipeline[plPtrWrite].writebackRegister == 3
3239 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3242 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3245 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3247 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3248 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3251 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3252 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3253 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3254 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3256 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3260 #ifndef NEW_SCOREBOARD
3261 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3262 scoreboard[pipeline[plPtrWrite].operand2] = false;
3264 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3265 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3266 if (scoreboard[pipeline[plPtrWrite].operand2])
3267 scoreboard[pipeline[plPtrWrite].operand2]--;
3271 // Push instructions through the pipeline...
3272 plPtrRead = (++plPtrRead) & 0x03;
3273 plPtrExec = (++plPtrExec) & 0x03;
3274 plPtrWrite = (++plPtrWrite) & 0x03;
3283 //#define DSP_DEBUG_PL3
3284 //Let's try a 2 stage pipeline....
3285 void DSPExecP3(int32 cycles)
3287 dsp_releaseTimeSlice_flag = 0;
3290 while (cycles > 0 && DSP_RUNNING)
3292 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3294 #ifdef DSP_DEBUG_PL3
3295 WriteLog("DSPExecP: Pipeline status...\n");
3296 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]);
3297 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]);
3298 WriteLog(" --> Scoreboard: ");
3299 for(int i=0; i<32; i++)
3300 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3303 // Stage 1a: Instruction fetch
3304 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3305 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3306 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3307 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3308 if (pipeline[plPtrRead].opcode == 38)
3309 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3310 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3311 #ifdef DSP_DEBUG_PL3
3312 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3313 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3314 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]);
3315 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]);
3317 // Stage 1b: Read registers
3318 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3319 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3320 // We have a hit in the scoreboard, so we have to stall the pipeline...
3321 #ifdef DSP_DEBUG_PL3
3323 WriteLog(" --> Stalling pipeline: ");
3324 if (readAffected[pipeline[plPtrRead].opcode][0])
3325 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3326 if (readAffected[pipeline[plPtrRead].opcode][1])
3327 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3330 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3331 #ifdef DSP_DEBUG_PL3
3336 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3337 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3338 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3340 // Shouldn't we be more selective with the register scoreboarding?
3341 // Yes, we should. !!! FIX !!! [Kinda DONE]
3342 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3344 //Advance PC here??? Yes.
3345 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3348 #ifdef DSP_DEBUG_PL3
3349 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3350 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]);
3351 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]);
3353 // Stage 2a: Execute
3354 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3356 #ifdef DSP_DEBUG_PL3
3357 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3359 DSPOpcode[pipeline[plPtrExec].opcode]();
3360 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3361 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3366 #ifdef DSP_DEBUG_PL3
3367 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3368 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]);
3369 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]);
3372 // Stage 2b: Write back register
3373 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3375 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3376 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3378 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3379 scoreboard[pipeline[plPtrExec].operand2] = false;
3382 // Push instructions through the pipeline...
3383 plPtrRead = (++plPtrRead) & 0x03;
3384 plPtrExec = (++plPtrExec) & 0x03;
3391 // DSP pipelined opcode handlers
3394 #define PRM pipeline[plPtrExec].reg1
3395 #define PRN pipeline[plPtrExec].reg2
3396 #define PIMM1 pipeline[plPtrExec].operand1
3397 #define PIMM2 pipeline[plPtrExec].operand2
3398 #define PRES pipeline[plPtrExec].result
3399 #define PWBR pipeline[plPtrExec].writebackRegister
3400 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3401 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3402 #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))
3403 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3405 static void DSP_abs(void)
3409 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);
3413 if (_Rn == 0x80000000)
3417 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3418 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3419 CLR_ZN; SET_Z(PRES);
3423 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3427 static void DSP_add(void)
3431 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);
3433 UINT32 res = PRN + PRM;
3434 SET_ZNC_ADD(PRN, PRM, res);
3438 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);
3442 static void DSP_addc(void)
3446 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);
3448 UINT32 res = PRN + PRM + dsp_flag_c;
3449 UINT32 carry = dsp_flag_c;
3450 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3451 SET_ZNC_ADD(PRN + carry, PRM, res);
3452 // SET_ZNC_ADD(PRN, PRM + carry, res);
3456 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);
3460 static void DSP_addq(void)
3464 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);
3466 UINT32 r1 = dsp_convert_zero[PIMM1];
3467 UINT32 res = PRN + r1;
3468 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3472 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3476 static void DSP_addqmod(void)
3478 #ifdef DSP_DIS_ADDQMOD
3480 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);
3482 UINT32 r1 = dsp_convert_zero[PIMM1];
3484 UINT32 res = r2 + r1;
3485 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3487 SET_ZNC_ADD(r2, r1, res);
3488 #ifdef DSP_DIS_ADDQMOD
3490 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3494 static void DSP_addqt(void)
3496 #ifdef DSP_DIS_ADDQT
3498 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);
3500 PRES = PRN + dsp_convert_zero[PIMM1];
3501 #ifdef DSP_DIS_ADDQT
3503 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3507 static void DSP_and(void)
3511 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);
3517 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);
3521 static void DSP_bclr(void)
3525 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);
3527 PRES = PRN & ~(1 << PIMM1);
3531 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3535 static void DSP_bset(void)
3539 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);
3541 PRES = PRN | (1 << PIMM1);
3545 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3549 static void DSP_btst(void)
3553 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);
3555 dsp_flag_z = (~PRN >> PIMM1) & 1;
3559 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3563 static void DSP_cmp(void)
3567 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);
3569 UINT32 res = PRN - PRM;
3570 SET_ZNC_SUB(PRN, PRM, res);
3574 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3578 static void DSP_cmpq(void)
3580 static int32 sqtable[32] =
3581 { 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 };
3584 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);
3586 UINT32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3587 UINT32 res = PRN - r1;
3588 SET_ZNC_SUB(PRN, r1, res);
3592 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3596 static void DSP_div(void)
3598 uint32 _Rm = PRM, _Rn = PRN;
3602 if (dsp_div_control & 1)
3604 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3605 if (dsp_remain & 0x80000000)
3607 PRES = (((uint64)_Rn) << 16) / _Rm;
3611 dsp_remain = _Rn % _Rm;
3612 if (dsp_remain & 0x80000000)
3621 static void DSP_imacn(void)
3623 #ifdef DSP_DIS_IMACN
3625 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);
3627 int32 res = (int16)PRM * (int16)PRN;
3628 dsp_acc += (int64)res;
3629 //Should we AND the result to fit into 40 bits here???
3631 #ifdef DSP_DIS_IMACN
3633 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));
3637 static void DSP_imult(void)
3639 #ifdef DSP_DIS_IMULT
3641 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);
3643 PRES = (int16)PRN * (int16)PRM;
3645 #ifdef DSP_DIS_IMULT
3647 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);
3651 static void DSP_imultn(void)
3653 #ifdef DSP_DIS_IMULTN
3655 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);
3657 // This is OK, since this multiply won't overflow 32 bits...
3658 int32 res = (int32)((int16)PRN * (int16)PRM);
3659 dsp_acc = (int64)res;
3662 #ifdef DSP_DIS_IMULTN
3664 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));
3668 static void DSP_illegal(void)
3670 #ifdef DSP_DIS_ILLEGAL
3672 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3677 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3678 // can cause trouble because an interrupt can occur *before* the instruction following the
3679 // jump can execute... !!! FIX !!!
3680 // This can probably be solved by judicious coding in the pipeline execution core...
3681 // And should be fixed now...
3682 static void DSP_jr(void)
3685 char * condition[32] =
3686 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3687 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3688 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3689 "???", "???", "???", "F" };
3691 //How come this is always off by 2???
3692 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);
3694 // KLUDGE: Used by BRANCH_CONDITION macro
3695 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3697 if (BRANCH_CONDITION(PIMM2))
3701 WriteLog("Branched!\n");
3703 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3704 //Account for pipeline effects...
3705 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3706 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3708 // Now that we've branched, we have to make sure that the following instruction
3709 // is executed atomically with this one and then flush the pipeline before setting
3712 // Step 1: Handle writebacks at stage 3 of pipeline
3713 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3715 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3716 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3718 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3719 scoreboard[pipeline[plPtrWrite].operand2] = false;
3721 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3723 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3725 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3726 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3729 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3730 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3731 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3732 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3734 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3738 #ifndef NEW_SCOREBOARD
3739 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3740 scoreboard[pipeline[plPtrWrite].operand2] = false;
3742 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3743 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3744 if (scoreboard[pipeline[plPtrWrite].operand2])
3745 scoreboard[pipeline[plPtrWrite].operand2]--;
3749 // Step 2: Push instruction through pipeline & execute following instruction
3750 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3751 // we effectively handle the final push of the instruction through the
3752 // pipeline when the new PC takes effect (since when we return, the
3753 // pipeline code will be executing the writeback stage. If we reverse
3754 // the execution order of the pipeline stages, this will no longer be
3756 pipeline[plPtrExec] = pipeline[plPtrRead];
3757 //This is BAD. We need to get that next opcode and execute it!
3758 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3759 // remove this crap.
3760 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3762 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3763 pipeline[plPtrExec].opcode = instruction >> 10;
3764 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3765 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3766 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3767 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3768 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3770 dsp_pc += 2; // For DSP_DIS_* accuracy
3771 DSPOpcode[pipeline[plPtrExec].opcode]();
3772 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3773 pipeline[plPtrWrite] = pipeline[plPtrExec];
3775 // Step 3: Flush pipeline & set new PC
3776 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3783 WriteLog("Branch NOT taken.\n");
3789 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3792 static void DSP_jump(void)
3795 char * condition[32] =
3796 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3797 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3798 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3799 "???", "???", "???", "F" };
3801 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);
3803 // KLUDGE: Used by BRANCH_CONDITION macro
3804 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3806 if (BRANCH_CONDITION(PIMM2))
3810 WriteLog("Branched!\n");
3812 uint32 PCSave = PRM;
3813 // Now that we've branched, we have to make sure that the following instruction
3814 // is executed atomically with this one and then flush the pipeline before setting
3817 // Step 1: Handle writebacks at stage 3 of pipeline
3818 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3820 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3821 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3823 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3824 scoreboard[pipeline[plPtrWrite].operand2] = false;
3826 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3828 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3830 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3831 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3834 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3835 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3836 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3837 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3839 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3843 #ifndef NEW_SCOREBOARD
3844 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3845 scoreboard[pipeline[plPtrWrite].operand2] = false;
3847 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3848 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3849 if (scoreboard[pipeline[plPtrWrite].operand2])
3850 scoreboard[pipeline[plPtrWrite].operand2]--;
3854 // Step 2: Push instruction through pipeline & execute following instruction
3855 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3856 // we effectively handle the final push of the instruction through the
3857 // pipeline when the new PC takes effect (since when we return, the
3858 // pipeline code will be executing the writeback stage. If we reverse
3859 // the execution order of the pipeline stages, this will no longer be
3861 pipeline[plPtrExec] = pipeline[plPtrRead];
3862 //This is BAD. We need to get that next opcode and execute it!
3863 //Also, same problem in JR!
3864 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3865 // remove this crap.
3866 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3868 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3869 pipeline[plPtrExec].opcode = instruction >> 10;
3870 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3871 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3872 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3873 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3874 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3876 dsp_pc += 2; // For DSP_DIS_* accuracy
3877 DSPOpcode[pipeline[plPtrExec].opcode]();
3878 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3879 pipeline[plPtrWrite] = pipeline[plPtrExec];
3881 // Step 3: Flush pipeline & set new PC
3882 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3889 WriteLog("Branch NOT taken.\n");
3897 static void DSP_load(void)
3901 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);
3903 PRES = DSPReadLong(PRM, DSP);
3906 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3910 static void DSP_loadb(void)
3912 #ifdef DSP_DIS_LOADB
3914 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);
3916 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3917 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3919 PRES = JaguarReadByte(PRM, DSP);
3920 #ifdef DSP_DIS_LOADB
3922 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3926 static void DSP_loadw(void)
3928 #ifdef DSP_DIS_LOADW
3930 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);
3932 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3933 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3935 PRES = JaguarReadWord(PRM, DSP);
3936 #ifdef DSP_DIS_LOADW
3938 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3942 static void DSP_load_r14_i(void)
3944 #ifdef DSP_DIS_LOAD14I
3946 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);
3948 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3949 #ifdef DSP_DIS_LOAD14I
3951 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3955 static void DSP_load_r14_r(void)
3957 #ifdef DSP_DIS_LOAD14R
3959 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);
3961 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3962 #ifdef DSP_DIS_LOAD14R
3964 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3968 static void DSP_load_r15_i(void)
3970 #ifdef DSP_DIS_LOAD15I
3972 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);
3974 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3975 #ifdef DSP_DIS_LOAD15I
3977 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3981 static void DSP_load_r15_r(void)
3983 #ifdef DSP_DIS_LOAD15R
3985 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);
3987 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
3988 #ifdef DSP_DIS_LOAD15R
3990 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3994 static void DSP_mirror(void)
3997 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4001 static void DSP_mmult(void)
4003 int count = dsp_matrix_control&0x0f;
4004 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4008 if (!(dsp_matrix_control & 0x10))
4010 for (int i = 0; i < count; i++)
4014 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4016 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4017 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4024 for (int i = 0; i < count; i++)
4028 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4030 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4031 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4037 PRES = res = (int32)accum;
4039 //NOTE: The flags are set based upon the last add/multiply done...
4043 static void DSP_move(void)
4047 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);
4052 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);
4056 static void DSP_movefa(void)
4058 #ifdef DSP_DIS_MOVEFA
4060 // 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);
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, dsp_alternate_reg[PIMM1], PIMM2, PRN);
4063 // PRES = ALTERNATE_RM;
4064 PRES = dsp_alternate_reg[PIMM1];
4065 #ifdef DSP_DIS_MOVEFA
4067 // 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);
4068 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);
4072 static void DSP_movei(void)
4074 #ifdef DSP_DIS_MOVEI
4076 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);
4078 // // This instruction is followed by 32-bit value in LSW / MSW format...
4079 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4081 #ifdef DSP_DIS_MOVEI
4083 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4087 static void DSP_movepc(void)
4089 #ifdef DSP_DIS_MOVEPC
4091 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);
4093 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4094 // PRES = dsp_pc - 2;
4095 //Account for pipeline effects...
4096 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4097 #ifdef DSP_DIS_MOVEPC
4099 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4103 static void DSP_moveq(void)
4105 #ifdef DSP_DIS_MOVEQ
4107 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);
4110 #ifdef DSP_DIS_MOVEQ
4112 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4116 static void DSP_moveta(void)
4118 #ifdef DSP_DIS_MOVETA
4120 // 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);
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, dsp_alternate_reg[PIMM2]);
4123 // ALTERNATE_RN = PRM;
4124 dsp_alternate_reg[PIMM2] = PRM;
4126 #ifdef DSP_DIS_MOVETA
4128 // 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);
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, dsp_alternate_reg[PIMM2]);
4133 static void DSP_mtoi(void)
4135 PRES = (((INT32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4139 static void DSP_mult(void)
4143 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);
4145 PRES = (uint16)PRM * (uint16)PRN;
4149 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);
4153 static void DSP_neg(void)
4157 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);
4160 SET_ZNC_SUB(0, PRN, res);
4164 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4168 static void DSP_nop(void)
4172 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4177 static void DSP_normi(void)
4184 while ((_Rm & 0xffc00000) == 0)
4189 while ((_Rm & 0xff800000) != 0)
4199 static void DSP_not(void)
4203 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);
4209 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4213 static void DSP_or(void)
4217 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);
4223 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);
4227 static void DSP_resmac(void)
4229 #ifdef DSP_DIS_RESMAC
4231 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));
4233 PRES = (uint32)dsp_acc;
4234 #ifdef DSP_DIS_RESMAC
4236 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4240 static void DSP_ror(void)
4244 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);
4246 UINT32 r1 = PRM & 0x1F;
4247 UINT32 res = (PRN >> r1) | (PRN << (32 - r1));
4248 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4252 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);
4256 static void DSP_rorq(void)
4260 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);
4262 UINT32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4264 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
4266 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4269 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4273 static void DSP_sat16s(void)
4276 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4281 static void DSP_sat32s(void)
4283 INT32 r2 = (UINT32)PRN;
4284 INT32 temp = dsp_acc >> 32;
4285 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
4290 static void DSP_sh(void)
4292 int32 sRm = (int32)PRM;
4297 uint32 shift = -sRm;
4302 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4317 dsp_flag_c = _Rn & 0x1;
4330 static void DSP_sha(void)
4332 int32 sRm = (int32)PRM;
4337 uint32 shift = -sRm;
4342 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4357 dsp_flag_c = _Rn & 0x1;
4361 _Rn = ((int32)_Rn) >> 1;
4370 static void DSP_sharq(void)
4372 #ifdef DSP_DIS_SHARQ
4374 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);
4376 UINT32 res = (INT32)PRN >> dsp_convert_zero[PIMM1];
4377 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4379 #ifdef DSP_DIS_SHARQ
4381 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4385 static void DSP_shlq(void)
4389 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);
4391 INT32 r1 = 32 - PIMM1;
4392 UINT32 res = PRN << r1;
4393 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4397 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4401 static void DSP_shrq(void)
4405 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);
4407 INT32 r1 = dsp_convert_zero[PIMM1];
4408 UINT32 res = PRN >> r1;
4409 SET_ZN(res); dsp_flag_c = PRN & 1;
4413 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4417 static void DSP_store(void)
4419 #ifdef DSP_DIS_STORE
4421 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);
4423 // DSPWriteLong(PRM, PRN, DSP);
4425 pipeline[plPtrExec].address = PRM;
4426 pipeline[plPtrExec].value = PRN;
4427 pipeline[plPtrExec].type = TYPE_DWORD;
4431 static void DSP_storeb(void)
4433 #ifdef DSP_DIS_STOREB
4435 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);
4437 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4438 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4440 // JaguarWriteByte(PRM, PRN, DSP);
4443 pipeline[plPtrExec].address = PRM;
4445 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4447 pipeline[plPtrExec].value = PRN & 0xFF;
4448 pipeline[plPtrExec].type = TYPE_DWORD;
4452 pipeline[plPtrExec].value = PRN;
4453 pipeline[plPtrExec].type = TYPE_BYTE;
4459 static void DSP_storew(void)
4461 #ifdef DSP_DIS_STOREW
4463 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);
4465 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4466 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4468 // JaguarWriteWord(PRM, PRN, DSP);
4471 pipeline[plPtrExec].address = PRM;
4473 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4475 pipeline[plPtrExec].value = PRN & 0xFFFF;
4476 pipeline[plPtrExec].type = TYPE_DWORD;
4480 pipeline[plPtrExec].value = PRN;
4481 pipeline[plPtrExec].type = TYPE_WORD;
4486 static void DSP_store_r14_i(void)
4488 #ifdef DSP_DIS_STORE14I
4490 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));
4492 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4494 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4495 pipeline[plPtrExec].value = PRN;
4496 pipeline[plPtrExec].type = TYPE_DWORD;
4500 static void DSP_store_r14_r(void)
4502 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4504 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4505 pipeline[plPtrExec].value = PRN;
4506 pipeline[plPtrExec].type = TYPE_DWORD;
4510 static void DSP_store_r15_i(void)
4512 #ifdef DSP_DIS_STORE15I
4514 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));
4516 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4518 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4519 pipeline[plPtrExec].value = PRN;
4520 pipeline[plPtrExec].type = TYPE_DWORD;
4524 static void DSP_store_r15_r(void)
4526 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4528 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4529 pipeline[plPtrExec].value = PRN;
4530 pipeline[plPtrExec].type = TYPE_DWORD;
4534 static void DSP_sub(void)
4538 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);
4540 UINT32 res = PRN - PRM;
4541 SET_ZNC_SUB(PRN, PRM, res);
4545 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);
4549 static void DSP_subc(void)
4553 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);
4555 UINT32 res = PRN - PRM - dsp_flag_c;
4556 UINT32 borrow = dsp_flag_c;
4557 SET_ZNC_SUB(PRN - borrow, PRM, res);
4561 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);
4565 static void DSP_subq(void)
4569 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);
4571 UINT32 r1 = dsp_convert_zero[PIMM1];
4572 UINT32 res = PRN - r1;
4573 SET_ZNC_SUB(PRN, r1, res);
4577 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4581 static void DSP_subqmod(void)
4583 UINT32 r1 = dsp_convert_zero[PIMM1];
4585 UINT32 res = r2 - r1;
4586 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4588 SET_ZNC_SUB(r2, r1, res);
4591 static void DSP_subqt(void)
4593 #ifdef DSP_DIS_SUBQT
4595 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);
4597 PRES = PRN - dsp_convert_zero[PIMM1];
4598 #ifdef DSP_DIS_SUBQT
4600 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4604 static void DSP_xor(void)
4608 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);
4614 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);