4 // Original source 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!
788 dsp_matrix_control = data;
791 // According to JTRM, only lines 2-11 are addressable, the rest being
792 // hardwired to $F1Bxxx.
793 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
796 dsp_data_organization = data;
801 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
806 ctrl1[0] = ctrl2[0] = data;
813 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
815 bool wasRunning = DSP_RUNNING;
816 // uint32 dsp_was_running = DSP_RUNNING;
817 // Check for DSP -> CPU interrupt
821 WriteLog("DSP: DSP -> CPU interrupt\n");
824 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
825 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
827 JERRYSetPendingIRQ(IRQ2_DSP);
828 dsp_releaseTimeslice();
829 m68k_set_irq(7); // Set 68000 NMI...
833 // Check for CPU -> DSP interrupt
837 WriteLog("DSP: CPU -> DSP interrupt\n");
839 m68k_end_timeslice();
840 gpu_releaseTimeslice();
841 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
845 if (data & SINGLE_STEP)
847 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
850 // Protect writes to VERSION and the interrupt latches...
851 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
852 dsp_control = (dsp_control & mask) | (data & ~mask);
856 ctrl1[8] = ctrl2[8] = dsp_control;
860 // if dsp wasn't running but is now running
861 // execute a few cycles
862 //This is just plain wrong, wrong, WRONG!
863 #ifndef DSP_SINGLE_STEPPING
864 /* if (!dsp_was_running && DSP_RUNNING)
869 //This is WRONG! !!! FIX !!!
870 if (dsp_control & 0x18)
875 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
877 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
880 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
881 // !!! FIX !!! [DONE]
885 m68k_end_timeslice();
887 gpu_releaseTimeslice();
891 //DSPDumpDisassembly();
899 dsp_div_control = data;
901 // default: // unaligned long read
907 //We don't have to break this up like this! We CAN do 32 bit writes!
908 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
909 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
910 //if (offset > 0xF1FFFF)
912 JaguarWriteLong(offset, data, who);
916 // Update the DSP register file pointers depending on REGPAGE bit
918 void DSPUpdateRegisterBanks(void)
920 int bank = (dsp_flags & REGPAGE);
922 if (dsp_flags & IMASK)
923 bank = 0; // IMASK forces main bank to be bank 0
926 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
928 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
932 // Check for and handle any asserted DSP IRQs
934 void DSPHandleIRQs(void)
936 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
939 // Get the active interrupt bits (latches) & interrupt mask (enables)
940 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
941 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
943 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
946 if (!bits) // Bail if nothing is enabled
949 int which = 0; // Determine which interrupt
964 WriteLog("DSP: Generating interrupt #%i...", which);
967 //if (which == 0) doDSPDis = true;
969 // NOTE: Since the actual Jaguar hardware injects the code sequence below
970 // directly into the pipeline, it has the side effect of ensuring that the
971 // instruction interrupted also gets to do its writeback. We simulate that
973 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
975 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
976 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
978 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
979 scoreboard[pipeline[plPtrWrite].operand2] = false;
981 //This should be execute (or should it?--not sure now!)
982 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
983 //and what just executed is now in the Write position...). So why didn't it do the
984 //writeback into register 0?
986 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
987 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]);
988 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]);
989 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]);
991 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
993 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
995 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
996 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
999 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1000 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1001 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1002 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1004 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1008 #ifndef NEW_SCOREBOARD
1009 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1010 scoreboard[pipeline[plPtrWrite].operand2] = false;
1012 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1013 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1014 if (scoreboard[pipeline[plPtrWrite].operand2])
1015 scoreboard[pipeline[plPtrWrite].operand2]--;
1022 ctrl2[4] = dsp_flags;
1025 DSPUpdateRegisterBanks();
1026 #ifdef DSP_DEBUG_IRQ
1027 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1028 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]);
1031 // subqt #4,r31 ; pre-decrement stack pointer
1032 // move pc,r30 ; address of interrupted code
1033 // store r30,(r31) ; store return address
1040 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1041 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1042 //It missed the place that it was supposed to come back to, so this is WRONG!
1044 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1046 // R -> baz (<- PC points here)
1047 // E -> bar (when it should point here!)
1050 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1051 // which means (assuming they're all 2 bytes long) that the code below will come back on
1052 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1053 // instruction stream...
1055 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1056 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1059 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1063 // movei #service_address,r30 ; pointer to ISR entry
1064 // jump (r30) ; jump to ISR
1066 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1069 ctrl2[0] = regs2[30] = dsp_pc;
1076 // Non-pipelined version...
1078 void DSPHandleIRQsNP(void)
1082 memcpy(dsp_ram_8, ram1, 0x2000);
1083 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1084 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1087 dsp_remain = ctrl1[2];
1088 dsp_modulo = ctrl1[3];
1089 dsp_flags = ctrl1[4];
1090 dsp_matrix_control = ctrl1[5];
1091 dsp_pointer_to_matrix = ctrl1[6];
1092 dsp_data_organization = ctrl1[7];
1093 dsp_control = ctrl1[8];
1094 dsp_div_control = ctrl1[9];
1095 IMASKCleared = ctrl1[10];
1096 dsp_flag_z = ctrl1[11];
1097 dsp_flag_n = ctrl1[12];
1098 dsp_flag_c = ctrl1[13];
1099 DSPUpdateRegisterBanks();
1102 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1105 // Get the active interrupt bits (latches) & interrupt mask (enables)
1106 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1107 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1109 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1112 if (!bits) // Bail if nothing is enabled
1115 int which = 0; // Determine which interrupt
1129 #ifdef DSP_DEBUG_IRQ
1130 WriteLog("DSP: Generating interrupt #%i...", which);
1136 ctrl1[4] = dsp_flags;
1139 DSPUpdateRegisterBanks();
1140 #ifdef DSP_DEBUG_IRQ
1141 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1144 // subqt #4,r31 ; pre-decrement stack pointer
1145 // move pc,r30 ; address of interrupted code
1146 // store r30,(r31) ; store return address
1153 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1156 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1160 // movei #service_address,r30 ; pointer to ISR entry
1161 // jump (r30) ; jump to ISR
1163 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1166 ctrl1[0] = regs1[30] = dsp_pc;
1172 // Set the specified DSP IRQ line to a given state
1174 void DSPSetIRQLine(int irqline, int state)
1176 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1177 uint32 mask = INT_LAT0 << irqline;
1178 dsp_control &= ~mask; // Clear the latch bit
1181 ctrl1[8] = ctrl2[8] = dsp_control;
1187 dsp_control |= mask; // Set the latch bit
1191 ctrl1[8] = ctrl2[8] = dsp_control;
1200 memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1201 memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1202 memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1204 dsp_build_branch_condition_table();
1210 dsp_pc = 0x00F1B000;
1211 dsp_acc = 0x00000000;
1212 dsp_remain = 0x00000000;
1213 dsp_modulo = 0xFFFFFFFF;
1214 dsp_flags = 0x00040000;
1215 dsp_matrix_control = 0x00000000;
1216 dsp_pointer_to_matrix = 0x00000000;
1217 dsp_data_organization = 0xFFFFFFFF;
1218 dsp_control = 0x00002000; // Report DSP version 2
1219 dsp_div_control = 0x00000000;
1222 dsp_reg = dsp_reg_bank_0;
1223 dsp_alternate_reg = dsp_reg_bank_1;
1225 for(int i=0; i<32; i++)
1226 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1229 IMASKCleared = false;
1232 memset(dsp_ram_8, 0xFF, 0x2000);
1235 void DSPDumpDisassembly(void)
1239 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1240 uint32 j = 0xF1B000;
1241 while (j <= 0xF1CFFF)
1244 j += dasmjag(JAGUAR_DSP, buffer, j);
1245 WriteLog("\t%08X: %s\n", oldj, buffer);
1249 void DSPDumpRegisters(void)
1251 //Shoud add modulus, etc to dump here...
1252 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1253 WriteLog("\nRegisters bank 0\n");
1254 for(int j=0; j<8; j++)
1256 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1257 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1258 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1259 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1260 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1262 WriteLog("Registers bank 1\n");
1263 for(int j=0; j<8; j++)
1265 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1266 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1267 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1268 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1269 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1276 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1277 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1279 // get the active interrupt bits
1280 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1281 // get the interrupt mask
1282 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1284 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1285 WriteLog("\nRegisters bank 0\n");
1286 for(int j=0; j<8; j++)
1288 WriteLog("\tr%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x\n",
1289 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1290 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1291 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1292 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1294 WriteLog("\nRegisters bank 1\n");
1297 WriteLog("\tr%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x r%2i=0x%.8x\n",
1298 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1299 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1300 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1301 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1305 static char buffer[512];
1306 j = DSP_WORK_RAM_BASE;
1307 while (j <= 0xF1BFFF)
1310 j += dasmjag(JAGUAR_DSP, buffer, j);
1311 WriteLog("\t%08X: %s\n", oldj, buffer);
1314 WriteLog("DSP opcodes use:\n");
1317 if (dsp_opcode_use[i])
1318 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1321 memory_free(dsp_ram_8);
1322 memory_free(dsp_reg_bank_0);
1323 memory_free(dsp_reg_bank_1);
1329 // DSP comparison core...
1332 static uint16 lastExec;
1333 void DSPExecComp(int32 cycles)
1335 while (cycles > 0 && DSP_RUNNING)
1337 // Load up vars for non-pipelined core
1338 memcpy(dsp_ram_8, ram1, 0x2000);
1339 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1340 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1343 dsp_remain = ctrl1[2];
1344 dsp_modulo = ctrl1[3];
1345 dsp_flags = ctrl1[4];
1346 dsp_matrix_control = ctrl1[5];
1347 dsp_pointer_to_matrix = ctrl1[6];
1348 dsp_data_organization = ctrl1[7];
1349 dsp_control = ctrl1[8];
1350 dsp_div_control = ctrl1[9];
1351 IMASKCleared = ctrl1[10];
1352 dsp_flag_z = ctrl1[11];
1353 dsp_flag_n = ctrl1[12];
1354 dsp_flag_c = ctrl1[13];
1355 DSPUpdateRegisterBanks();
1357 // Decrement cycles based on non-pipelined core...
1358 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1359 cycles -= dsp_opcode_cycles[instr1 >> 10];
1361 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1362 DSPExec(1); // Do *one* instruction
1365 memcpy(ram1, dsp_ram_8, 0x2000);
1366 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1367 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1370 ctrl1[2] = dsp_remain;
1371 ctrl1[3] = dsp_modulo;
1372 ctrl1[4] = dsp_flags;
1373 ctrl1[5] = dsp_matrix_control;
1374 ctrl1[6] = dsp_pointer_to_matrix;
1375 ctrl1[7] = dsp_data_organization;
1376 ctrl1[8] = dsp_control;
1377 ctrl1[9] = dsp_div_control;
1378 ctrl1[10] = IMASKCleared;
1379 ctrl1[11] = dsp_flag_z;
1380 ctrl1[12] = dsp_flag_n;
1381 ctrl1[13] = dsp_flag_c;
1383 // Load up vars for pipelined core
1384 memcpy(dsp_ram_8, ram2, 0x2000);
1385 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1386 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1389 dsp_remain = ctrl2[2];
1390 dsp_modulo = ctrl2[3];
1391 dsp_flags = ctrl2[4];
1392 dsp_matrix_control = ctrl2[5];
1393 dsp_pointer_to_matrix = ctrl2[6];
1394 dsp_data_organization = ctrl2[7];
1395 dsp_control = ctrl2[8];
1396 dsp_div_control = ctrl2[9];
1397 IMASKCleared = ctrl2[10];
1398 dsp_flag_z = ctrl2[11];
1399 dsp_flag_n = ctrl2[12];
1400 dsp_flag_c = ctrl2[13];
1401 DSPUpdateRegisterBanks();
1403 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1404 DSPExecP2(1); // Do *one* instruction
1407 memcpy(ram2, dsp_ram_8, 0x2000);
1408 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1409 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1412 ctrl2[2] = dsp_remain;
1413 ctrl2[3] = dsp_modulo;
1414 ctrl2[4] = dsp_flags;
1415 ctrl2[5] = dsp_matrix_control;
1416 ctrl2[6] = dsp_pointer_to_matrix;
1417 ctrl2[7] = dsp_data_organization;
1418 ctrl2[8] = dsp_control;
1419 ctrl2[9] = dsp_div_control;
1420 ctrl2[10] = IMASKCleared;
1421 ctrl2[11] = dsp_flag_z;
1422 ctrl2[12] = dsp_flag_n;
1423 ctrl2[13] = dsp_flag_c;
1425 if (instr1 != lastExec)
1427 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1429 // 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));
1430 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1431 // if (ctrl1[0] < ppc) // P ran ahead of NP
1432 //How to test this crap???
1435 DSPExecP2(1); // Do one more instruction
1438 memcpy(ram2, dsp_ram_8, 0x2000);
1439 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1440 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1443 ctrl2[2] = dsp_remain;
1444 ctrl2[3] = dsp_modulo;
1445 ctrl2[4] = dsp_flags;
1446 ctrl2[5] = dsp_matrix_control;
1447 ctrl2[6] = dsp_pointer_to_matrix;
1448 ctrl2[7] = dsp_data_organization;
1449 ctrl2[8] = dsp_control;
1450 ctrl2[9] = dsp_div_control;
1451 ctrl2[10] = IMASKCleared;
1452 ctrl2[11] = dsp_flag_z;
1453 ctrl2[12] = dsp_flag_n;
1454 ctrl2[13] = dsp_flag_c;
1456 // else // NP ran ahead of P
1457 if (instr1 != lastExec) // Must be the other way...
1460 // Load up vars for non-pipelined core
1461 memcpy(dsp_ram_8, ram1, 0x2000);
1462 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1463 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1466 dsp_remain = ctrl1[2];
1467 dsp_modulo = ctrl1[3];
1468 dsp_flags = ctrl1[4];
1469 dsp_matrix_control = ctrl1[5];
1470 dsp_pointer_to_matrix = ctrl1[6];
1471 dsp_data_organization = ctrl1[7];
1472 dsp_control = ctrl1[8];
1473 dsp_div_control = ctrl1[9];
1474 IMASKCleared = ctrl1[10];
1475 dsp_flag_z = ctrl1[11];
1476 dsp_flag_n = ctrl1[12];
1477 dsp_flag_c = ctrl1[13];
1478 DSPUpdateRegisterBanks();
1480 for(int k=0; k<2; k++)
1482 // Decrement cycles based on non-pipelined core...
1483 instr1 = DSPReadWord(dsp_pc, DSP);
1484 cycles -= dsp_opcode_cycles[instr1 >> 10];
1486 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1487 DSPExec(1); // Do *one* instruction
1491 memcpy(ram1, dsp_ram_8, 0x2000);
1492 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1493 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1496 ctrl1[2] = dsp_remain;
1497 ctrl1[3] = dsp_modulo;
1498 ctrl1[4] = dsp_flags;
1499 ctrl1[5] = dsp_matrix_control;
1500 ctrl1[6] = dsp_pointer_to_matrix;
1501 ctrl1[7] = dsp_data_organization;
1502 ctrl1[8] = dsp_control;
1503 ctrl1[9] = dsp_div_control;
1504 ctrl1[10] = IMASKCleared;
1505 ctrl1[11] = dsp_flag_z;
1506 ctrl1[12] = dsp_flag_n;
1507 ctrl1[13] = dsp_flag_c;
1511 if (instr1 != lastExec)
1513 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1515 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1516 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1529 // DSP execution core
1531 //static bool R20Set = false, tripwire = false;
1532 //static uint32 pcQueue[32], ptrPCQ = 0;
1533 void DSPExec(int32 cycles)
1535 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1536 dsp_check_if_i2s_interrupt_needed();*/
1538 #ifdef DSP_SINGLE_STEPPING
1539 if (dsp_control & 0x18)
1542 dsp_control &= ~0x10;
1545 //There is *no* good reason to do this here!
1547 dsp_releaseTimeSlice_flag = 0;
1550 while (cycles > 0 && DSP_RUNNING)
1552 /*extern uint32 totalFrames;
1553 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1554 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1555 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1557 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1560 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1562 if (dsp_pc == 0xF1B092)
1563 doDSPDis = false;//*/
1564 /*if (dsp_pc == 0xF1B140)
1565 doDSPDis = true;//*/
1567 if (IMASKCleared) // If IMASK was cleared,
1569 #ifdef DSP_DEBUG_IRQ
1570 WriteLog("DSP: Finished interrupt.\n");
1572 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1573 IMASKCleared = false;
1578 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1579 for(int i=0; i<80; i+=4)
1580 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1583 /*if (dsp_pc == 0xF1B55E)
1585 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1587 /*if (dsp_pc == 0xF1B7D2) // Start here???
1589 pcQueue[ptrPCQ++] = dsp_pc;
1591 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1592 uint32 index = opcode >> 10;
1593 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1594 dsp_opcode_second_parameter = opcode & 0x1F;
1596 dsp_opcode[index]();
1597 dsp_opcode_use[index]++;
1598 cycles -= dsp_opcode_cycles[index];
1599 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1601 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1604 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1606 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1608 DSPDumpDisassembly();
1611 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1614 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1617 WriteLog("\nBacktrace:\n");
1618 for(int i=0; i<32; i++)
1620 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1621 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1631 // DSP opcode handlers
1634 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1635 // can cause trouble because an interrupt can occur *before* the instruction following the
1636 // jump can execute... !!! FIX !!!
1637 static void dsp_opcode_jump(void)
1640 char * condition[32] =
1641 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1642 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1643 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1644 "???", "???", "???", "F" };
1646 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);
1649 /* dsp_flag_c=dsp_flag_c?1:0;
1650 dsp_flag_z=dsp_flag_z?1:0;
1651 dsp_flag_n=dsp_flag_n?1:0;*/
1652 // KLUDGE: Used by BRANCH_CONDITION
1653 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1655 if (BRANCH_CONDITION(IMM_2))
1659 WriteLog("Branched!\n");
1661 uint32 delayed_pc = RM;
1663 dsp_pc = delayed_pc;
1668 WriteLog("Branch NOT taken.\n");
1672 static void dsp_opcode_jr(void)
1675 char * condition[32] =
1676 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1677 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1678 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1679 "???", "???", "???", "F" };
1681 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);
1684 /* dsp_flag_c=dsp_flag_c?1:0;
1685 dsp_flag_z=dsp_flag_z?1:0;
1686 dsp_flag_n=dsp_flag_n?1:0;*/
1687 // KLUDGE: Used by BRANCH_CONDITION
1688 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1690 if (BRANCH_CONDITION(IMM_2))
1694 WriteLog("Branched!\n");
1696 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1697 int32 delayed_pc = dsp_pc + (offset * 2);
1699 dsp_pc = delayed_pc;
1704 WriteLog("Branch NOT taken.\n");
1708 static void dsp_opcode_add(void)
1712 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);
1714 UINT32 res = RN + RM;
1715 SET_ZNC_ADD(RN, RM, res);
1719 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1723 static void dsp_opcode_addc(void)
1727 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);
1729 UINT32 res = RN + RM + dsp_flag_c;
1730 UINT32 carry = dsp_flag_c;
1731 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1732 SET_ZNC_ADD(RN + carry, RM, res);
1733 // SET_ZNC_ADD(RN, RM + carry, res);
1737 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);
1741 static void dsp_opcode_addq(void)
1745 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);
1747 UINT32 r1 = dsp_convert_zero[IMM_1];
1748 UINT32 res = RN + r1;
1749 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1753 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1757 static void dsp_opcode_sub(void)
1761 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);
1763 UINT32 res = RN - RM;
1764 SET_ZNC_SUB(RN, RM, res);
1768 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);
1772 static void dsp_opcode_subc(void)
1776 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);
1778 UINT32 res = RN - RM - dsp_flag_c;
1779 UINT32 borrow = dsp_flag_c;
1780 SET_ZNC_SUB(RN - borrow, RM, res);
1784 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);
1788 static void dsp_opcode_subq(void)
1792 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);
1794 UINT32 r1 = dsp_convert_zero[IMM_1];
1795 UINT32 res = RN - r1;
1796 SET_ZNC_SUB(RN, r1, res);
1800 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1804 static void dsp_opcode_cmp(void)
1808 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);
1810 UINT32 res = RN - RM;
1811 SET_ZNC_SUB(RN, RM, res);
1814 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1818 static void dsp_opcode_cmpq(void)
1820 static int32 sqtable[32] =
1821 { 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 };
1824 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);
1826 UINT32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1827 UINT32 res = RN - r1;
1828 SET_ZNC_SUB(RN, r1, res);
1831 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1835 static void dsp_opcode_and(void)
1839 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);
1845 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);
1849 static void dsp_opcode_or(void)
1853 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);
1859 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);
1863 static void dsp_opcode_xor(void)
1867 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);
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_not(void)
1881 WriteLog("%06X: NOT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
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_move_pc(void)
1896 static void dsp_opcode_store_r14_indexed(void)
1898 #ifdef DSP_DIS_STORE14I
1900 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));
1902 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1905 static void dsp_opcode_store_r15_indexed(void)
1907 #ifdef DSP_DIS_STORE15I
1909 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));
1911 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1914 static void dsp_opcode_load_r14_ri(void)
1916 #ifdef DSP_DIS_LOAD14R
1918 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);
1920 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1921 #ifdef DSP_DIS_LOAD14R
1923 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1927 static void dsp_opcode_load_r15_ri(void)
1929 #ifdef DSP_DIS_LOAD15R
1931 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);
1933 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1934 #ifdef DSP_DIS_LOAD15R
1936 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1940 static void dsp_opcode_store_r14_ri(void)
1942 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1945 static void dsp_opcode_store_r15_ri(void)
1947 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1950 static void dsp_opcode_nop(void)
1954 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1958 static void dsp_opcode_storeb(void)
1960 #ifdef DSP_DIS_STOREB
1962 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);
1964 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1965 DSPWriteLong(RM, RN & 0xFF, DSP);
1967 JaguarWriteByte(RM, RN, DSP);
1970 static void dsp_opcode_storew(void)
1972 #ifdef DSP_DIS_STOREW
1974 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);
1976 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1977 DSPWriteLong(RM, RN & 0xFFFF, DSP);
1979 JaguarWriteWord(RM, RN, DSP);
1982 static void dsp_opcode_store(void)
1984 #ifdef DSP_DIS_STORE
1986 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);
1988 DSPWriteLong(RM, RN, DSP);
1991 static void dsp_opcode_loadb(void)
1993 #ifdef DSP_DIS_LOADB
1995 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);
1997 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1998 RN = DSPReadLong(RM, DSP) & 0xFF;
2000 RN = JaguarReadByte(RM, DSP);
2001 #ifdef DSP_DIS_LOADB
2003 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2007 static void dsp_opcode_loadw(void)
2009 #ifdef DSP_DIS_LOADW
2011 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);
2013 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2014 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2016 RN = JaguarReadWord(RM, DSP);
2017 #ifdef DSP_DIS_LOADW
2019 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2023 static void dsp_opcode_load(void)
2027 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);
2029 RN = DSPReadLong(RM, DSP);
2032 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2036 static void dsp_opcode_load_r14_indexed(void)
2038 #ifdef DSP_DIS_LOAD14I
2040 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);
2042 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2043 #ifdef DSP_DIS_LOAD14I
2045 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2049 static void dsp_opcode_load_r15_indexed(void)
2051 #ifdef DSP_DIS_LOAD15I
2053 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);
2055 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2056 #ifdef DSP_DIS_LOAD15I
2058 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2062 static void dsp_opcode_movei(void)
2064 #ifdef DSP_DIS_MOVEI
2066 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);
2068 // This instruction is followed by 32-bit value in LSW / MSW format...
2069 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2071 #ifdef DSP_DIS_MOVEI
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_moveta(void)
2079 #ifdef DSP_DIS_MOVETA
2081 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);
2084 #ifdef DSP_DIS_MOVETA
2086 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);
2090 static void dsp_opcode_movefa(void)
2092 #ifdef DSP_DIS_MOVEFA
2094 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);
2097 #ifdef DSP_DIS_MOVEFA
2099 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);
2103 static void dsp_opcode_move(void)
2107 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);
2112 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);
2116 static void dsp_opcode_moveq(void)
2118 #ifdef DSP_DIS_MOVEQ
2120 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);
2123 #ifdef DSP_DIS_MOVEQ
2125 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2129 static void dsp_opcode_resmac(void)
2131 #ifdef DSP_DIS_RESMAC
2133 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));
2135 RN = (uint32)dsp_acc;
2136 #ifdef DSP_DIS_RESMAC
2138 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2142 static void dsp_opcode_imult(void)
2144 #ifdef DSP_DIS_IMULT
2146 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);
2148 RN = (int16)RN * (int16)RM;
2150 #ifdef DSP_DIS_IMULT
2152 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);
2156 static void dsp_opcode_mult(void)
2160 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);
2162 RN = (uint16)RM * (uint16)RN;
2166 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);
2170 static void dsp_opcode_bclr(void)
2174 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);
2176 UINT32 res = RN & ~(1 << IMM_1);
2181 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2185 static void dsp_opcode_btst(void)
2189 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);
2191 dsp_flag_z = (~RN >> IMM_1) & 1;
2194 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2198 static void dsp_opcode_bset(void)
2202 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);
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_subqt(void)
2215 #ifdef DSP_DIS_SUBQT
2217 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);
2219 RN -= dsp_convert_zero[IMM_1];
2220 #ifdef DSP_DIS_SUBQT
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_addqt(void)
2228 #ifdef DSP_DIS_ADDQT
2230 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);
2232 RN += dsp_convert_zero[IMM_1];
2233 #ifdef DSP_DIS_ADDQT
2235 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2239 static void dsp_opcode_imacn(void)
2241 #ifdef DSP_DIS_IMACN
2243 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);
2245 int32 res = (int16)RM * (int16)RN;
2246 dsp_acc += (int64)res;
2247 //Should we AND the result to fit into 40 bits here???
2248 #ifdef DSP_DIS_IMACN
2250 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));
2254 static void dsp_opcode_mtoi(void)
2256 RN = (((INT32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2260 static void dsp_opcode_normi(void)
2267 while ((_Rm & 0xffc00000) == 0)
2272 while ((_Rm & 0xff800000) != 0)
2282 static void dsp_opcode_mmult(void)
2284 int count = dsp_matrix_control&0x0f;
2285 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2289 if (!(dsp_matrix_control & 0x10))
2291 for (int i = 0; i < count; i++)
2295 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2297 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2298 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2305 for (int i = 0; i < count; i++)
2309 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2311 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2312 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2317 RN = res = (int32)accum;
2319 //NOTE: The flags are set based upon the last add/multiply done...
2323 static void dsp_opcode_abs(void)
2327 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);
2332 if (_Rn == 0x80000000)
2336 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2337 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2342 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2346 static void dsp_opcode_div(void)
2353 if (dsp_div_control & 1)
2355 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2356 if (dsp_remain&0x80000000)
2358 RN = (((uint64)_Rn) << 16) / _Rm;
2362 dsp_remain = _Rn % _Rm;
2363 if (dsp_remain&0x80000000)
2372 static void dsp_opcode_imultn(void)
2374 #ifdef DSP_DIS_IMULTN
2376 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);
2378 // This is OK, since this multiply won't overflow 32 bits...
2379 int32 res = (int32)((int16)RN * (int16)RM);
2380 dsp_acc = (int64)res;
2382 #ifdef DSP_DIS_IMULTN
2384 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));
2388 static void dsp_opcode_neg(void)
2392 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);
2395 SET_ZNC_SUB(0, RN, res);
2399 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2403 static void dsp_opcode_shlq(void)
2407 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);
2409 INT32 r1 = 32 - IMM_1;
2410 UINT32 res = RN << r1;
2411 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2415 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2419 static void dsp_opcode_shrq(void)
2423 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);
2425 INT32 r1 = dsp_convert_zero[IMM_1];
2426 UINT32 res = RN >> r1;
2427 SET_ZN(res); dsp_flag_c = RN & 1;
2431 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2435 static void dsp_opcode_ror(void)
2439 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);
2441 UINT32 r1 = RM & 0x1F;
2442 UINT32 res = (RN >> r1) | (RN << (32 - r1));
2443 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2447 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);
2451 static void dsp_opcode_rorq(void)
2455 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);
2457 UINT32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2459 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
2461 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2464 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2468 static void dsp_opcode_sha(void)
2470 int32 sRm=(int32)RM;
2476 if (shift>=32) shift=32;
2477 dsp_flag_c=(_Rn&0x80000000)>>31;
2487 if (shift>=32) shift=32;
2491 _Rn=((int32)_Rn)>>1;
2499 static void dsp_opcode_sharq(void)
2501 #ifdef DSP_DIS_SHARQ
2503 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);
2505 UINT32 res = (INT32)RN >> dsp_convert_zero[IMM_1];
2506 SET_ZN(res); dsp_flag_c = RN & 0x01;
2508 #ifdef DSP_DIS_SHARQ
2510 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2514 static void dsp_opcode_sh(void)
2516 int32 sRm=(int32)RM;
2521 uint32 shift=(-sRm);
2522 if (shift>=32) shift=32;
2523 dsp_flag_c=(_Rn&0x80000000)>>31;
2533 if (shift>=32) shift=32;
2545 void dsp_opcode_addqmod(void)
2547 #ifdef DSP_DIS_ADDQMOD
2549 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);
2551 UINT32 r1 = dsp_convert_zero[IMM_1];
2553 UINT32 res = r2 + r1;
2554 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2556 SET_ZNC_ADD(r2, r1, res);
2557 #ifdef DSP_DIS_ADDQMOD
2559 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2563 void dsp_opcode_subqmod(void)
2565 UINT32 r1 = dsp_convert_zero[IMM_1];
2567 UINT32 res = r2 - r1;
2568 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2571 SET_ZNC_SUB(r2, r1, res);
2574 void dsp_opcode_mirror(void)
2577 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2581 void dsp_opcode_sat32s(void)
2583 INT32 r2 = (UINT32)RN;
2584 INT32 temp = dsp_acc >> 32;
2585 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
2590 void dsp_opcode_sat16s(void)
2593 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2599 // New pipelined DSP core
2602 static void DSP_abs(void);
2603 static void DSP_add(void);
2604 static void DSP_addc(void);
2605 static void DSP_addq(void);
2606 static void DSP_addqmod(void);
2607 static void DSP_addqt(void);
2608 static void DSP_and(void);
2609 static void DSP_bclr(void);
2610 static void DSP_bset(void);
2611 static void DSP_btst(void);
2612 static void DSP_cmp(void);
2613 static void DSP_cmpq(void);
2614 static void DSP_div(void);
2615 static void DSP_imacn(void);
2616 static void DSP_imult(void);
2617 static void DSP_imultn(void);
2618 static void DSP_illegal(void);
2619 static void DSP_jr(void);
2620 static void DSP_jump(void);
2621 static void DSP_load(void);
2622 static void DSP_loadb(void);
2623 static void DSP_loadw(void);
2624 static void DSP_load_r14_i(void);
2625 static void DSP_load_r14_r(void);
2626 static void DSP_load_r15_i(void);
2627 static void DSP_load_r15_r(void);
2628 static void DSP_mirror(void);
2629 static void DSP_mmult(void);
2630 static void DSP_move(void);
2631 static void DSP_movefa(void);
2632 static void DSP_movei(void);
2633 static void DSP_movepc(void);
2634 static void DSP_moveq(void);
2635 static void DSP_moveta(void);
2636 static void DSP_mtoi(void);
2637 static void DSP_mult(void);
2638 static void DSP_neg(void);
2639 static void DSP_nop(void);
2640 static void DSP_normi(void);
2641 static void DSP_not(void);
2642 static void DSP_or(void);
2643 static void DSP_resmac(void);
2644 static void DSP_ror(void);
2645 static void DSP_rorq(void);
2646 static void DSP_sat16s(void);
2647 static void DSP_sat32s(void);
2648 static void DSP_sh(void);
2649 static void DSP_sha(void);
2650 static void DSP_sharq(void);
2651 static void DSP_shlq(void);
2652 static void DSP_shrq(void);
2653 static void DSP_store(void);
2654 static void DSP_storeb(void);
2655 static void DSP_storew(void);
2656 static void DSP_store_r14_i(void);
2657 static void DSP_store_r14_r(void);
2658 static void DSP_store_r15_i(void);
2659 static void DSP_store_r15_r(void);
2660 static void DSP_sub(void);
2661 static void DSP_subc(void);
2662 static void DSP_subq(void);
2663 static void DSP_subqmod(void);
2664 static void DSP_subqt(void);
2665 static void DSP_xor(void);
2667 void (* DSPOpcode[64])() =
2669 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2670 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2671 DSP_neg, DSP_and, DSP_or, DSP_xor,
2672 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2674 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2675 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2676 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2677 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2679 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2680 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2681 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2682 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2684 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2685 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2686 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2687 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2690 bool readAffected[64][2] =
2692 { true, true}, { true, true}, {false, true}, {false, true},
2693 { true, true}, { true, true}, {false, true}, {false, true},
2694 {false, true}, { true, true}, { true, true}, { true, true},
2695 {false, true}, {false, true}, {false, true}, {false, true},
2697 { true, true}, { true, true}, { true, true}, {false, true},
2698 { true, true}, { true, true}, {false, true}, { true, true},
2699 {false, true}, {false, true}, { true, true}, {false, true},
2700 { true, true}, {false, true}, { true, true}, {false, true},
2702 {false, true}, {false, true}, { true, false}, {false, false},
2703 { true, false}, {false, false}, {false, false}, { true, false},
2704 { true, false}, { true, false}, {false, true}, { true, false},
2705 { true, false}, { true, true}, { true, true}, { true, true},
2707 {false, true}, { true, true}, { true, true}, {false, true},
2708 { true, false}, { true, false}, { true, true}, { true, false},
2709 { true, false}, {false, false}, { true, false}, { true, false},
2710 { true, true}, { true, true}, {false, false}, {false, true}
2713 bool isLoadStore[65] =
2715 false, false, false, false, false, false, false, false,
2716 false, false, false, false, false, false, false, false,
2718 false, false, false, false, false, false, false, false,
2719 false, false, false, false, false, false, false, false,
2721 false, false, false, false, false, false, false, true,
2722 true, true, false, true, true, true, true, true,
2724 false, true, true, false, false, false, false, false,
2725 false, false, true, true, true, true, false, false, false
2728 void FlushDSPPipeline(void)
2730 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2732 for(int i=0; i<4; i++)
2733 pipeline[i].opcode = PIPELINE_STALL;
2735 for(int i=0; i<32; i++)
2740 // New pipelined DSP execution core
2742 /*void DSPExecP(int32 cycles)
2744 // bool inhibitFetch = false;
2746 dsp_releaseTimeSlice_flag = 0;
2749 while (cycles > 0 && DSP_RUNNING)
2751 WriteLog("DSPExecP: Pipeline status...\n");
2752 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);
2753 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);
2754 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);
2755 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);
2756 WriteLog(" --> Scoreboard: ");
2757 for(int i=0; i<32; i++)
2758 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2760 // Stage 1: Instruction fetch
2761 // if (!inhibitFetch)
2763 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2764 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2765 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2766 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2767 if (pipeline[plPtrFetch].opcode == 38)
2768 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2769 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2772 // inhibitFetch = false;
2773 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2775 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2776 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);
2777 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);
2778 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);
2779 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);
2780 // Stage 2: Read registers
2781 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2782 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2783 if (scoreboard[pipeline[plPtrRead].operand2])
2784 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2785 // We have a hit in the scoreboard, so we have to stall the pipeline...
2787 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2788 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2789 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2790 pipeline[plPtrFetch] = pipeline[plPtrRead];
2791 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2795 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2796 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2797 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2799 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2800 // Shouldn't we be more selective with the register scoreboarding?
2801 // Yes, we should. !!! FIX !!!
2802 scoreboard[pipeline[plPtrRead].operand2] = true;
2803 //Advance PC here??? Yes.
2804 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2805 //This is a mangling of the pipeline stages, but what else to do???
2806 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2809 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2810 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);
2811 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);
2812 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);
2813 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);
2815 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2817 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2818 DSPOpcode[pipeline[plPtrExec].opcode]();
2819 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2820 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2825 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2826 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);
2827 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);
2828 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);
2829 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);
2830 // Stage 4: Write back register
2831 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2833 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2834 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2836 scoreboard[pipeline[plPtrWrite].operand1]
2837 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2840 // Push instructions through the pipeline...
2841 plPtrFetch = (++plPtrFetch) & 0x03;
2842 plPtrRead = (++plPtrRead) & 0x03;
2843 plPtrExec = (++plPtrExec) & 0x03;
2844 plPtrWrite = (++plPtrWrite) & 0x03;
2851 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2853 // Should be fixed now. Another problem is figuring how to do the sequence following
2854 // a branch followed with the JR & JUMP instructions...
2856 // There are two conflicting problems:
2859 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2860 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2861 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2862 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2863 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2864 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2865 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2866 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2867 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2868 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2869 DSP: Finished interrupt.
2870 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2871 ; bank 0 (where is was prepared)!
2872 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2873 F1B252: NOP [NCZ:001]
2876 // The other is when you see this at the end of an IRQ:
2879 JUMP T, (R29) ; R29 = Previous stack + 2
2880 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2882 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2883 ; 1) The STORE goes through the pipeline and is executed/written back
2884 ; 2) The pipeline is flushed
2885 ; 3) The DSP_PC is set to the new address
2886 ; 4) Execution resumes
2888 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2889 ; bank 0 instead of the current bank 1 and so goes astray!
2892 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2893 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2897 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2898 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2899 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2900 If it were done properly, the STORE write back would occur *after* (well, technically,
2901 during) the execution of the the JUMP that follows it.
2905 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2906 F1B08A: NOP [NCZ:001]
2908 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2911 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2914 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2915 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2916 F1B08A: NOP [NCZ:001]
2918 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2921 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2922 DSP: CPU -> DSP interrupt
2923 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2924 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2926 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2929 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2930 F1B006: NOP [NCZ:001]
2932 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2935 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2936 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2939 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2940 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2943 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2944 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2947 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2948 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
2951 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
2954 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
2957 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
2958 F1B0FE: NOP [NCZ:000]
2960 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
2963 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
2966 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
2967 F1B138: NOP [NCZ:000]
2969 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
2972 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
2973 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
2974 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
2977 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
2978 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2981 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
2982 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
2983 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2985 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
2986 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
2989 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
2990 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
2991 DSP: Finished interrupt.
2992 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
2994 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
2997 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
2998 F1B016: NOP [NCZ:001]
3000 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3003 uint32 pcQueue1[0x400];
3005 static uint32 prevR1;
3006 //Let's try a 3 stage pipeline....
3007 //Looks like 3 stage is correct, otherwise bad things happen...
3008 void DSPExecP2(int32 cycles)
3010 dsp_releaseTimeSlice_flag = 0;
3013 while (cycles > 0 && DSP_RUNNING)
3015 /*extern uint32 totalFrames;
3016 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3017 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3018 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3020 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3023 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3025 if (dsp_pc == 0xF1B092)
3026 doDSPDis = false;//*/
3027 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3028 doDSPDis = true;//*/
3029 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3030 doDSPDis = true;//*/
3031 /*if (dsp_pc == 0xF1B0A0)
3032 doDSPDis = true;//*/
3033 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3034 doDSPDis = true;//*/
3035 //Two parter... (not sure how to write this)
3036 //if (dsp_pc == 0xF1B0D2)
3037 // prevR1 = dsp_reg[1];
3039 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3040 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3043 pcQueue1[pcQPtr1++] = dsp_pc;
3046 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3048 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3053 for(int i=0; i<0x400; i++)
3055 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3056 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3060 if (IMASKCleared) // If IMASK was cleared,
3062 #ifdef DSP_DEBUG_IRQ
3063 WriteLog("DSP: Finished interrupt.\n");
3065 DSPHandleIRQs(); // See if any other interrupts are pending!
3066 IMASKCleared = false;
3069 //if (dsp_flags & REGPAGE)
3070 // WriteLog(" --> REGPAGE has just been set!\n");
3071 #ifdef DSP_DEBUG_PL2
3074 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3075 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]);
3076 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]);
3077 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]);
3078 WriteLog(" --> Scoreboard: ");
3079 for(int i=0; i<32; i++)
3080 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3084 // Stage 1a: Instruction fetch
3085 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3086 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3087 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3088 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3089 if (pipeline[plPtrRead].opcode == 38)
3090 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3091 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3092 #ifdef DSP_DEBUG_PL2
3095 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3096 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3097 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]);
3098 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]);
3099 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]);
3102 // Stage 1b: Read registers
3103 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3104 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3106 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3107 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3108 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3109 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3110 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3111 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3112 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3114 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3115 // We have a hit in the scoreboard, so we have to stall the pipeline...
3116 #ifdef DSP_DEBUG_PL2
3120 WriteLog(" --> Stalling pipeline: ");
3121 if (readAffected[pipeline[plPtrRead].opcode][0])
3122 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3123 if (readAffected[pipeline[plPtrRead].opcode][1])
3124 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3128 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3129 #ifdef DSP_DEBUG_PL2
3134 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3135 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3136 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3138 // Shouldn't we be more selective with the register scoreboarding?
3139 // Yes, we should. !!! FIX !!! Kinda [DONE]
3140 #ifndef NEW_SCOREBOARD
3141 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3143 //Hopefully this will fix the dual MOVEQ # problem...
3144 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3147 //Advance PC here??? Yes.
3148 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3151 #ifdef DSP_DEBUG_PL2
3154 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3155 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]);
3156 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]);
3157 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]);
3161 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3164 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"));
3165 #ifdef DSP_DEBUG_PL2
3168 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3173 lastExec = pipeline[plPtrExec].instruction;
3174 //WriteLog("[lastExec = %04X]\n", lastExec);
3176 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3177 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3178 DSPOpcode[pipeline[plPtrExec].opcode]();
3179 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3183 //Let's not, until we do the stalling correctly...
3184 //But, we gotta while we're doing the comparison core...!
3185 //Or do we? cycles--;
3186 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3187 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3188 //to model this clock cycle behavior correctly...
3189 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3190 //don't affect the reads at stage 1...
3191 #ifdef DSP_DEBUG_STALL
3193 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3197 #ifdef DSP_DEBUG_PL2
3200 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3201 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]);
3202 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]);
3203 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]);
3207 // Stage 3: Write back register/memory address
3208 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3210 /*if (pipeline[plPtrWrite].writebackRegister == 3
3211 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3214 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3217 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3219 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3220 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3223 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3224 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3225 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3226 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3228 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3232 #ifndef NEW_SCOREBOARD
3233 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3234 scoreboard[pipeline[plPtrWrite].operand2] = false;
3236 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3237 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3238 if (scoreboard[pipeline[plPtrWrite].operand2])
3239 scoreboard[pipeline[plPtrWrite].operand2]--;
3243 // Push instructions through the pipeline...
3244 plPtrRead = (++plPtrRead) & 0x03;
3245 plPtrExec = (++plPtrExec) & 0x03;
3246 plPtrWrite = (++plPtrWrite) & 0x03;
3255 //#define DSP_DEBUG_PL3
3256 //Let's try a 2 stage pipeline....
3257 void DSPExecP3(int32 cycles)
3259 dsp_releaseTimeSlice_flag = 0;
3262 while (cycles > 0 && DSP_RUNNING)
3264 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3266 #ifdef DSP_DEBUG_PL3
3267 WriteLog("DSPExecP: Pipeline status...\n");
3268 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]);
3269 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]);
3270 WriteLog(" --> Scoreboard: ");
3271 for(int i=0; i<32; i++)
3272 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3275 // Stage 1a: Instruction fetch
3276 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3277 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3278 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3279 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3280 if (pipeline[plPtrRead].opcode == 38)
3281 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3282 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3283 #ifdef DSP_DEBUG_PL3
3284 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3285 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3286 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]);
3287 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]);
3289 // Stage 1b: Read registers
3290 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3291 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3292 // We have a hit in the scoreboard, so we have to stall the pipeline...
3293 #ifdef DSP_DEBUG_PL3
3295 WriteLog(" --> Stalling pipeline: ");
3296 if (readAffected[pipeline[plPtrRead].opcode][0])
3297 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3298 if (readAffected[pipeline[plPtrRead].opcode][1])
3299 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3302 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3303 #ifdef DSP_DEBUG_PL3
3308 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3309 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3310 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3312 // Shouldn't we be more selective with the register scoreboarding?
3313 // Yes, we should. !!! FIX !!! [Kinda DONE]
3314 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3316 //Advance PC here??? Yes.
3317 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3320 #ifdef DSP_DEBUG_PL3
3321 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3322 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]);
3323 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]);
3325 // Stage 2a: Execute
3326 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3328 #ifdef DSP_DEBUG_PL3
3329 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3331 DSPOpcode[pipeline[plPtrExec].opcode]();
3332 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3333 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3338 #ifdef DSP_DEBUG_PL3
3339 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3340 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]);
3341 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]);
3344 // Stage 2b: Write back register
3345 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3347 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3348 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3350 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3351 scoreboard[pipeline[plPtrExec].operand2] = false;
3354 // Push instructions through the pipeline...
3355 plPtrRead = (++plPtrRead) & 0x03;
3356 plPtrExec = (++plPtrExec) & 0x03;
3363 // DSP pipelined opcode handlers
3366 #define PRM pipeline[plPtrExec].reg1
3367 #define PRN pipeline[plPtrExec].reg2
3368 #define PIMM1 pipeline[plPtrExec].operand1
3369 #define PIMM2 pipeline[plPtrExec].operand2
3370 #define PRES pipeline[plPtrExec].result
3371 #define PWBR pipeline[plPtrExec].writebackRegister
3372 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3373 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3374 #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))
3375 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3377 static void DSP_abs(void)
3381 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);
3385 if (_Rn == 0x80000000)
3389 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3390 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3391 CLR_ZN; SET_Z(PRES);
3395 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3399 static void DSP_add(void)
3403 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);
3405 UINT32 res = PRN + PRM;
3406 SET_ZNC_ADD(PRN, PRM, res);
3410 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);
3414 static void DSP_addc(void)
3418 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);
3420 UINT32 res = PRN + PRM + dsp_flag_c;
3421 UINT32 carry = dsp_flag_c;
3422 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3423 SET_ZNC_ADD(PRN + carry, PRM, res);
3424 // SET_ZNC_ADD(PRN, PRM + carry, res);
3428 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);
3432 static void DSP_addq(void)
3436 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);
3438 UINT32 r1 = dsp_convert_zero[PIMM1];
3439 UINT32 res = PRN + r1;
3440 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3444 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3448 static void DSP_addqmod(void)
3450 #ifdef DSP_DIS_ADDQMOD
3452 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);
3454 UINT32 r1 = dsp_convert_zero[PIMM1];
3456 UINT32 res = r2 + r1;
3457 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3459 SET_ZNC_ADD(r2, r1, res);
3460 #ifdef DSP_DIS_ADDQMOD
3462 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3466 static void DSP_addqt(void)
3468 #ifdef DSP_DIS_ADDQT
3470 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);
3472 PRES = PRN + dsp_convert_zero[PIMM1];
3473 #ifdef DSP_DIS_ADDQT
3475 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3479 static void DSP_and(void)
3483 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);
3489 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);
3493 static void DSP_bclr(void)
3497 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);
3499 PRES = PRN & ~(1 << PIMM1);
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_bset(void)
3511 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);
3513 PRES = PRN | (1 << PIMM1);
3517 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3521 static void DSP_btst(void)
3525 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);
3527 dsp_flag_z = (~PRN >> PIMM1) & 1;
3531 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3535 static void DSP_cmp(void)
3539 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);
3541 UINT32 res = PRN - PRM;
3542 SET_ZNC_SUB(PRN, PRM, res);
3546 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3550 static void DSP_cmpq(void)
3552 static int32 sqtable[32] =
3553 { 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 };
3556 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);
3558 UINT32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3559 UINT32 res = PRN - r1;
3560 SET_ZNC_SUB(PRN, r1, res);
3564 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3568 static void DSP_div(void)
3570 uint32 _Rm = PRM, _Rn = PRN;
3574 if (dsp_div_control & 1)
3576 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3577 if (dsp_remain & 0x80000000)
3579 PRES = (((uint64)_Rn) << 16) / _Rm;
3583 dsp_remain = _Rn % _Rm;
3584 if (dsp_remain & 0x80000000)
3593 static void DSP_imacn(void)
3595 #ifdef DSP_DIS_IMACN
3597 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);
3599 int32 res = (int16)PRM * (int16)PRN;
3600 dsp_acc += (int64)res;
3601 //Should we AND the result to fit into 40 bits here???
3603 #ifdef DSP_DIS_IMACN
3605 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));
3609 static void DSP_imult(void)
3611 #ifdef DSP_DIS_IMULT
3613 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);
3615 PRES = (int16)PRN * (int16)PRM;
3617 #ifdef DSP_DIS_IMULT
3619 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);
3623 static void DSP_imultn(void)
3625 #ifdef DSP_DIS_IMULTN
3627 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);
3629 // This is OK, since this multiply won't overflow 32 bits...
3630 int32 res = (int32)((int16)PRN * (int16)PRM);
3631 dsp_acc = (int64)res;
3634 #ifdef DSP_DIS_IMULTN
3636 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));
3640 static void DSP_illegal(void)
3642 #ifdef DSP_DIS_ILLEGAL
3644 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3649 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3650 // can cause trouble because an interrupt can occur *before* the instruction following the
3651 // jump can execute... !!! FIX !!!
3652 // This can probably be solved by judicious coding in the pipeline execution core...
3653 // And should be fixed now...
3654 static void DSP_jr(void)
3657 char * condition[32] =
3658 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3659 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3660 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3661 "???", "???", "???", "F" };
3663 //How come this is always off by 2???
3664 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);
3666 // KLUDGE: Used by BRANCH_CONDITION macro
3667 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3669 if (BRANCH_CONDITION(PIMM2))
3673 WriteLog("Branched!\n");
3675 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3676 //Account for pipeline effects...
3677 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3678 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3680 // Now that we've branched, we have to make sure that the following instruction
3681 // is executed atomically with this one and then flush the pipeline before setting
3684 // Step 1: Handle writebacks at stage 3 of pipeline
3685 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3687 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3688 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3690 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3691 scoreboard[pipeline[plPtrWrite].operand2] = false;
3693 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3695 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3697 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3698 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3701 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3702 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3703 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3704 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3706 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3710 #ifndef NEW_SCOREBOARD
3711 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3712 scoreboard[pipeline[plPtrWrite].operand2] = false;
3714 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3715 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3716 if (scoreboard[pipeline[plPtrWrite].operand2])
3717 scoreboard[pipeline[plPtrWrite].operand2]--;
3721 // Step 2: Push instruction through pipeline & execute following instruction
3722 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3723 // we effectively handle the final push of the instruction through the
3724 // pipeline when the new PC takes effect (since when we return, the
3725 // pipeline code will be executing the writeback stage. If we reverse
3726 // the execution order of the pipeline stages, this will no longer be
3728 pipeline[plPtrExec] = pipeline[plPtrRead];
3729 //This is BAD. We need to get that next opcode and execute it!
3730 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3731 // remove this crap.
3732 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3734 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3735 pipeline[plPtrExec].opcode = instruction >> 10;
3736 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3737 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3738 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3739 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3740 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3742 dsp_pc += 2; // For DSP_DIS_* accuracy
3743 DSPOpcode[pipeline[plPtrExec].opcode]();
3744 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3745 pipeline[plPtrWrite] = pipeline[plPtrExec];
3747 // Step 3: Flush pipeline & set new PC
3748 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3755 WriteLog("Branch NOT taken.\n");
3761 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3764 static void DSP_jump(void)
3767 char * condition[32] =
3768 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3769 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3770 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3771 "???", "???", "???", "F" };
3773 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);
3775 // KLUDGE: Used by BRANCH_CONDITION macro
3776 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3778 if (BRANCH_CONDITION(PIMM2))
3782 WriteLog("Branched!\n");
3784 uint32 PCSave = PRM;
3785 // Now that we've branched, we have to make sure that the following instruction
3786 // is executed atomically with this one and then flush the pipeline before setting
3789 // Step 1: Handle writebacks at stage 3 of pipeline
3790 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3792 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3793 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3795 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3796 scoreboard[pipeline[plPtrWrite].operand2] = false;
3798 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3800 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3802 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3803 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3806 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3807 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3808 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3809 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3811 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3815 #ifndef NEW_SCOREBOARD
3816 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3817 scoreboard[pipeline[plPtrWrite].operand2] = false;
3819 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3820 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3821 if (scoreboard[pipeline[plPtrWrite].operand2])
3822 scoreboard[pipeline[plPtrWrite].operand2]--;
3826 // Step 2: Push instruction through pipeline & execute following instruction
3827 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3828 // we effectively handle the final push of the instruction through the
3829 // pipeline when the new PC takes effect (since when we return, the
3830 // pipeline code will be executing the writeback stage. If we reverse
3831 // the execution order of the pipeline stages, this will no longer be
3833 pipeline[plPtrExec] = pipeline[plPtrRead];
3834 //This is BAD. We need to get that next opcode and execute it!
3835 //Also, same problem in JR!
3836 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3837 // remove this crap.
3838 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3840 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3841 pipeline[plPtrExec].opcode = instruction >> 10;
3842 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3843 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3844 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3845 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3846 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3848 dsp_pc += 2; // For DSP_DIS_* accuracy
3849 DSPOpcode[pipeline[plPtrExec].opcode]();
3850 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3851 pipeline[plPtrWrite] = pipeline[plPtrExec];
3853 // Step 3: Flush pipeline & set new PC
3854 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3861 WriteLog("Branch NOT taken.\n");
3869 static void DSP_load(void)
3873 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);
3875 PRES = DSPReadLong(PRM, DSP);
3878 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3882 static void DSP_loadb(void)
3884 #ifdef DSP_DIS_LOADB
3886 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);
3888 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3889 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3891 PRES = JaguarReadByte(PRM, DSP);
3892 #ifdef DSP_DIS_LOADB
3894 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3898 static void DSP_loadw(void)
3900 #ifdef DSP_DIS_LOADW
3902 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);
3904 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3905 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3907 PRES = JaguarReadWord(PRM, DSP);
3908 #ifdef DSP_DIS_LOADW
3910 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3914 static void DSP_load_r14_i(void)
3916 #ifdef DSP_DIS_LOAD14I
3918 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);
3920 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3921 #ifdef DSP_DIS_LOAD14I
3923 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3927 static void DSP_load_r14_r(void)
3929 #ifdef DSP_DIS_LOAD14R
3931 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);
3933 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3934 #ifdef DSP_DIS_LOAD14R
3936 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3940 static void DSP_load_r15_i(void)
3942 #ifdef DSP_DIS_LOAD15I
3944 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);
3946 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3947 #ifdef DSP_DIS_LOAD15I
3949 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3953 static void DSP_load_r15_r(void)
3955 #ifdef DSP_DIS_LOAD15R
3957 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);
3959 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
3960 #ifdef DSP_DIS_LOAD15R
3962 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3966 static void DSP_mirror(void)
3969 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
3973 static void DSP_mmult(void)
3975 int count = dsp_matrix_control&0x0f;
3976 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
3980 if (!(dsp_matrix_control & 0x10))
3982 for (int i = 0; i < count; i++)
3986 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
3988 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
3989 int16 b=((int16)DSPReadWord(addr + 2, DSP));
3996 for (int i = 0; i < count; i++)
4000 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4002 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4003 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4009 PRES = res = (int32)accum;
4011 //NOTE: The flags are set based upon the last add/multiply done...
4015 static void DSP_move(void)
4019 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);
4024 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);
4028 static void DSP_movefa(void)
4030 #ifdef DSP_DIS_MOVEFA
4032 // 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);
4033 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);
4035 // PRES = ALTERNATE_RM;
4036 PRES = dsp_alternate_reg[PIMM1];
4037 #ifdef DSP_DIS_MOVEFA
4039 // 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);
4040 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);
4044 static void DSP_movei(void)
4046 #ifdef DSP_DIS_MOVEI
4048 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);
4050 // // This instruction is followed by 32-bit value in LSW / MSW format...
4051 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4053 #ifdef DSP_DIS_MOVEI
4055 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4059 static void DSP_movepc(void)
4061 #ifdef DSP_DIS_MOVEPC
4063 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);
4065 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4066 // PRES = dsp_pc - 2;
4067 //Account for pipeline effects...
4068 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4069 #ifdef DSP_DIS_MOVEPC
4071 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4075 static void DSP_moveq(void)
4077 #ifdef DSP_DIS_MOVEQ
4079 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);
4082 #ifdef DSP_DIS_MOVEQ
4084 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4088 static void DSP_moveta(void)
4090 #ifdef DSP_DIS_MOVETA
4092 // 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);
4093 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]);
4095 // ALTERNATE_RN = PRM;
4096 dsp_alternate_reg[PIMM2] = PRM;
4098 #ifdef DSP_DIS_MOVETA
4100 // 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);
4101 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]);
4105 static void DSP_mtoi(void)
4107 PRES = (((INT32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4111 static void DSP_mult(void)
4115 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);
4117 PRES = (uint16)PRM * (uint16)PRN;
4121 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);
4125 static void DSP_neg(void)
4129 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);
4132 SET_ZNC_SUB(0, PRN, res);
4136 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4140 static void DSP_nop(void)
4144 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4149 static void DSP_normi(void)
4156 while ((_Rm & 0xffc00000) == 0)
4161 while ((_Rm & 0xff800000) != 0)
4171 static void DSP_not(void)
4175 WriteLog("%06X: NOT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", DSP_PPC, PIMM1, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRN);
4181 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);
4185 static void DSP_or(void)
4189 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);
4195 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);
4199 static void DSP_resmac(void)
4201 #ifdef DSP_DIS_RESMAC
4203 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));
4205 PRES = (uint32)dsp_acc;
4206 #ifdef DSP_DIS_RESMAC
4208 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4212 static void DSP_ror(void)
4216 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);
4218 UINT32 r1 = PRM & 0x1F;
4219 UINT32 res = (PRN >> r1) | (PRN << (32 - r1));
4220 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4224 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
4228 static void DSP_rorq(void)
4232 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);
4234 UINT32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4236 UINT32 res = (r2 >> r1) | (r2 << (32 - r1));
4238 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4241 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4245 static void DSP_sat16s(void)
4248 UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4253 static void DSP_sat32s(void)
4255 INT32 r2 = (UINT32)PRN;
4256 INT32 temp = dsp_acc >> 32;
4257 UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7FFFFFFF : r2;
4262 static void DSP_sh(void)
4264 int32 sRm = (int32)PRM;
4269 uint32 shift = -sRm;
4274 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4289 dsp_flag_c = _Rn & 0x1;
4302 static void DSP_sha(void)
4304 int32 sRm = (int32)PRM;
4309 uint32 shift = -sRm;
4314 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4329 dsp_flag_c = _Rn & 0x1;
4333 _Rn = ((int32)_Rn) >> 1;
4342 static void DSP_sharq(void)
4344 #ifdef DSP_DIS_SHARQ
4346 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);
4348 UINT32 res = (INT32)PRN >> dsp_convert_zero[PIMM1];
4349 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4351 #ifdef DSP_DIS_SHARQ
4353 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4357 static void DSP_shlq(void)
4361 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);
4363 INT32 r1 = 32 - PIMM1;
4364 UINT32 res = PRN << r1;
4365 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4369 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4373 static void DSP_shrq(void)
4377 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);
4379 INT32 r1 = dsp_convert_zero[PIMM1];
4380 UINT32 res = PRN >> r1;
4381 SET_ZN(res); dsp_flag_c = PRN & 1;
4385 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4389 static void DSP_store(void)
4391 #ifdef DSP_DIS_STORE
4393 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);
4395 // DSPWriteLong(PRM, PRN, DSP);
4397 pipeline[plPtrExec].address = PRM;
4398 pipeline[plPtrExec].value = PRN;
4399 pipeline[plPtrExec].type = TYPE_DWORD;
4403 static void DSP_storeb(void)
4405 #ifdef DSP_DIS_STOREB
4407 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);
4409 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4410 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4412 // JaguarWriteByte(PRM, PRN, DSP);
4415 pipeline[plPtrExec].address = PRM;
4417 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4419 pipeline[plPtrExec].value = PRN & 0xFF;
4420 pipeline[plPtrExec].type = TYPE_DWORD;
4424 pipeline[plPtrExec].value = PRN;
4425 pipeline[plPtrExec].type = TYPE_BYTE;
4431 static void DSP_storew(void)
4433 #ifdef DSP_DIS_STOREW
4435 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);
4437 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4438 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4440 // JaguarWriteWord(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 & 0xFFFF;
4448 pipeline[plPtrExec].type = TYPE_DWORD;
4452 pipeline[plPtrExec].value = PRN;
4453 pipeline[plPtrExec].type = TYPE_WORD;
4458 static void DSP_store_r14_i(void)
4460 #ifdef DSP_DIS_STORE14I
4462 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));
4464 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4466 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4467 pipeline[plPtrExec].value = PRN;
4468 pipeline[plPtrExec].type = TYPE_DWORD;
4472 static void DSP_store_r14_r(void)
4474 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4476 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4477 pipeline[plPtrExec].value = PRN;
4478 pipeline[plPtrExec].type = TYPE_DWORD;
4482 static void DSP_store_r15_i(void)
4484 #ifdef DSP_DIS_STORE15I
4486 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));
4488 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4490 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4491 pipeline[plPtrExec].value = PRN;
4492 pipeline[plPtrExec].type = TYPE_DWORD;
4496 static void DSP_store_r15_r(void)
4498 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4500 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4501 pipeline[plPtrExec].value = PRN;
4502 pipeline[plPtrExec].type = TYPE_DWORD;
4506 static void DSP_sub(void)
4510 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);
4512 UINT32 res = PRN - PRM;
4513 SET_ZNC_SUB(PRN, PRM, res);
4517 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);
4521 static void DSP_subc(void)
4525 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);
4527 UINT32 res = PRN - PRM - dsp_flag_c;
4528 UINT32 borrow = dsp_flag_c;
4529 SET_ZNC_SUB(PRN - borrow, PRM, res);
4533 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);
4537 static void DSP_subq(void)
4541 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);
4543 UINT32 r1 = dsp_convert_zero[PIMM1];
4544 UINT32 res = PRN - r1;
4545 SET_ZNC_SUB(PRN, r1, res);
4549 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4553 static void DSP_subqmod(void)
4555 UINT32 r1 = dsp_convert_zero[PIMM1];
4557 UINT32 res = r2 - r1;
4558 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4560 SET_ZNC_SUB(r2, r1, res);
4563 static void DSP_subqt(void)
4565 #ifdef DSP_DIS_SUBQT
4567 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);
4569 PRES = PRN - dsp_convert_zero[PIMM1];
4570 #ifdef DSP_DIS_SUBQT
4572 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4576 static void DSP_xor(void)
4580 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);
4586 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);