4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James L. Hammons
7 // (C) 2010 Underground Software
9 // JLH = James L. Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 11/26/2011 Added fixes for LOAD/STORE alignment issues
19 #include <SDL.h> // Used only for SDL_GetTicks...
30 // Seems alignment in loads & stores was off...
31 #define DSP_CORRECT_ALIGNMENT
34 //#define DSP_DEBUG_IRQ
35 //#define DSP_DEBUG_PL2
36 //#define DSP_DEBUG_STALL
37 //#define DSP_DEBUG_CC
38 #define NEW_SCOREBOARD
40 // Disassembly definitions
47 #define DSP_DIS_ADDQMOD
57 #define DSP_DIS_IMULTN
58 #define DSP_DIS_ILLEGAL
62 #define DSP_DIS_LOAD14I
63 #define DSP_DIS_LOAD14R
64 #define DSP_DIS_LOAD15I
65 #define DSP_DIS_LOAD15R
71 #define DSP_DIS_MOVEFA
72 #define DSP_DIS_MOVEPC // Pipeline only!
73 #define DSP_DIS_MOVETA
79 #define DSP_DIS_RESMAC
86 #define DSP_DIS_STORE14I
87 #define DSP_DIS_STORE15I
88 #define DSP_DIS_STOREB
89 #define DSP_DIS_STOREW
96 bool doDSPDis = false;
97 //bool doDSPDis = true;
132 + load_r15_indexed 284500
134 + store_r15_indexed 47416
138 + load_r14_ri 1229448
141 // Pipeline structures
143 const bool affectsScoreboard[64] =
145 true, true, true, true,
146 true, true, true, true,
147 true, true, true, true,
148 true, false, true, true,
150 true, true, false, true,
151 false, true, true, true,
152 true, true, true, true,
153 true, true, false, false,
155 true, true, true, true,
156 false, true, true, true,
157 true, true, true, true,
158 true, false, false, false,
160 true, false, false, true,
161 false, false, true, true,
162 true, false, true, true,
163 false, false, false, true
169 uint8 opcode, operand1, operand2;
170 uint32 reg1, reg2, areg1, areg2;
172 uint8 writebackRegister;
173 // General memory store...
182 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
183 #ifndef NEW_SCOREBOARD
186 uint8 scoreboard[32];
188 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
189 PipelineStage pipeline[4];
190 bool IMASKCleared = false;
192 // DSP flags (old--have to get rid of this crap)
194 #define CINT0FLAG 0x00200
195 #define CINT1FLAG 0x00400
196 #define CINT2FLAG 0x00800
197 #define CINT3FLAG 0x01000
198 #define CINT4FLAG 0x02000
199 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
200 #define CINT5FLAG 0x20000 /* DSP only */
204 #define ZERO_FLAG 0x00001
205 #define CARRY_FLAG 0x00002
206 #define NEGA_FLAG 0x00004
207 #define IMASK 0x00008
208 #define INT_ENA0 0x00010
209 #define INT_ENA1 0x00020
210 #define INT_ENA2 0x00040
211 #define INT_ENA3 0x00080
212 #define INT_ENA4 0x00100
213 #define INT_CLR0 0x00200
214 #define INT_CLR1 0x00400
215 #define INT_CLR2 0x00800
216 #define INT_CLR3 0x01000
217 #define INT_CLR4 0x02000
218 #define REGPAGE 0x04000
219 #define DMAEN 0x08000
220 #define INT_ENA5 0x10000
221 #define INT_CLR5 0x20000
225 #define DSPGO 0x00001
226 #define CPUINT 0x00002
227 #define DSPINT0 0x00004
228 #define SINGLE_STEP 0x00008
229 #define SINGLE_GO 0x00010
231 #define INT_LAT0 0x00040
232 #define INT_LAT1 0x00080
233 #define INT_LAT2 0x00100
234 #define INT_LAT3 0x00200
235 #define INT_LAT4 0x00400
236 #define BUS_HOG 0x00800
237 #define VERSION 0x0F000
238 #define INT_LAT5 0x10000
240 extern uint32 jaguar_mainRom_crc32;
242 // Is opcode 62 *really* a NOP? Seems like it...
243 static void dsp_opcode_abs(void);
244 static void dsp_opcode_add(void);
245 static void dsp_opcode_addc(void);
246 static void dsp_opcode_addq(void);
247 static void dsp_opcode_addqmod(void);
248 static void dsp_opcode_addqt(void);
249 static void dsp_opcode_and(void);
250 static void dsp_opcode_bclr(void);
251 static void dsp_opcode_bset(void);
252 static void dsp_opcode_btst(void);
253 static void dsp_opcode_cmp(void);
254 static void dsp_opcode_cmpq(void);
255 static void dsp_opcode_div(void);
256 static void dsp_opcode_imacn(void);
257 static void dsp_opcode_imult(void);
258 static void dsp_opcode_imultn(void);
259 static void dsp_opcode_jr(void);
260 static void dsp_opcode_jump(void);
261 static void dsp_opcode_load(void);
262 static void dsp_opcode_loadb(void);
263 static void dsp_opcode_loadw(void);
264 static void dsp_opcode_load_r14_indexed(void);
265 static void dsp_opcode_load_r14_ri(void);
266 static void dsp_opcode_load_r15_indexed(void);
267 static void dsp_opcode_load_r15_ri(void);
268 static void dsp_opcode_mirror(void);
269 static void dsp_opcode_mmult(void);
270 static void dsp_opcode_move(void);
271 static void dsp_opcode_movei(void);
272 static void dsp_opcode_movefa(void);
273 static void dsp_opcode_move_pc(void);
274 static void dsp_opcode_moveq(void);
275 static void dsp_opcode_moveta(void);
276 static void dsp_opcode_mtoi(void);
277 static void dsp_opcode_mult(void);
278 static void dsp_opcode_neg(void);
279 static void dsp_opcode_nop(void);
280 static void dsp_opcode_normi(void);
281 static void dsp_opcode_not(void);
282 static void dsp_opcode_or(void);
283 static void dsp_opcode_resmac(void);
284 static void dsp_opcode_ror(void);
285 static void dsp_opcode_rorq(void);
286 static void dsp_opcode_xor(void);
287 static void dsp_opcode_sat16s(void);
288 static void dsp_opcode_sat32s(void);
289 static void dsp_opcode_sh(void);
290 static void dsp_opcode_sha(void);
291 static void dsp_opcode_sharq(void);
292 static void dsp_opcode_shlq(void);
293 static void dsp_opcode_shrq(void);
294 static void dsp_opcode_store(void);
295 static void dsp_opcode_storeb(void);
296 static void dsp_opcode_storew(void);
297 static void dsp_opcode_store_r14_indexed(void);
298 static void dsp_opcode_store_r14_ri(void);
299 static void dsp_opcode_store_r15_indexed(void);
300 static void dsp_opcode_store_r15_ri(void);
301 static void dsp_opcode_sub(void);
302 static void dsp_opcode_subc(void);
303 static void dsp_opcode_subq(void);
304 static void dsp_opcode_subqmod(void);
305 static void dsp_opcode_subqt(void);
307 uint8 dsp_opcode_cycles[64] =
309 3, 3, 3, 3, 3, 3, 3, 3,
310 3, 3, 3, 3, 3, 3, 3, 3,
311 3, 3, 1, 3, 1, 18, 3, 3,
312 3, 3, 3, 3, 3, 3, 3, 3,
313 3, 3, 2, 2, 2, 2, 3, 4,
314 5, 4, 5, 6, 6, 1, 1, 1,
315 1, 2, 2, 2, 1, 1, 9, 3,
316 3, 1, 6, 6, 2, 2, 3, 3
318 //Here's a QnD kludge...
319 //This is wrong, wrong, WRONG, but it seems to work for the time being...
320 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
321 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
322 /*uint8 dsp_opcode_cycles[64] =
324 1, 1, 1, 1, 1, 1, 1, 1,
325 1, 1, 1, 1, 1, 1, 1, 1,
326 1, 1, 1, 1, 1, 9, 1, 1,
327 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 2,
329 2, 2, 2, 3, 3, 1, 1, 1,
330 1, 1, 1, 1, 1, 1, 4, 1,
331 1, 1, 3, 3, 1, 1, 1, 1
334 void (* dsp_opcode[64])() =
336 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
337 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
338 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
339 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
340 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
341 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
342 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
343 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
344 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
345 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
346 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
347 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
348 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
349 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
350 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
351 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
354 uint32 dsp_opcode_use[65];
356 const char * dsp_opcode_str[65]=
358 "add", "addc", "addq", "addqt",
359 "sub", "subc", "subq", "subqt",
360 "neg", "and", "or", "xor",
361 "not", "btst", "bset", "bclr",
362 "mult", "imult", "imultn", "resmac",
363 "imacn", "div", "abs", "sh",
364 "shlq", "shrq", "sha", "sharq",
365 "ror", "rorq", "cmp", "cmpq",
366 "subqmod", "sat16s", "move", "moveq",
367 "moveta", "movefa", "movei", "loadb",
368 "loadw", "load", "sat32s", "load_r14_indexed",
369 "load_r15_indexed", "storeb", "storew", "store",
370 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
371 "jump", "jr", "mmult", "mtoi",
372 "normi", "nop", "load_r14_ri", "load_r15_ri",
373 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
378 static uint64 dsp_acc; // 40 bit register, NOT 32!
379 static uint32 dsp_remain;
380 static uint32 dsp_modulo;
381 static uint32 dsp_flags;
382 static uint32 dsp_matrix_control;
383 static uint32 dsp_pointer_to_matrix;
384 static uint32 dsp_data_organization;
386 static uint32 dsp_div_control;
387 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
388 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
389 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
391 static uint32 dsp_opcode_first_parameter;
392 static uint32 dsp_opcode_second_parameter;
394 #define DSP_RUNNING (dsp_control & 0x01)
396 #define RM dsp_reg[dsp_opcode_first_parameter]
397 #define RN dsp_reg[dsp_opcode_second_parameter]
398 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
399 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
400 #define IMM_1 dsp_opcode_first_parameter
401 #define IMM_2 dsp_opcode_second_parameter
403 #define CLR_Z (dsp_flag_z = 0)
404 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
405 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
406 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
407 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
408 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
409 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
410 #define SET_ZN(r) SET_N(r); SET_Z(r)
411 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
412 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
414 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 };
415 uint8 * dsp_branch_condition_table = NULL;
416 static uint16 * mirror_table = NULL;
417 static uint8 dsp_ram_8[0x2000];
419 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
421 static uint32 dsp_in_exec = 0;
422 static uint32 dsp_releaseTimeSlice_flag = 0;
427 // Comparison core vars (used only for core comparison! :-)
428 static uint64 count = 0;
429 static uint8 ram1[0x2000], ram2[0x2000];
430 static uint32 regs1[64], regs2[64];
431 static uint32 ctrl1[14], ctrl2[14];
434 // Private function prototypes
436 void DSPDumpRegisters(void);
437 void DSPDumpDisassembly(void);
438 void FlushDSPPipeline(void);
441 void dsp_reset_stats(void)
443 for(int i=0; i<65; i++)
444 dsp_opcode_use[i] = 0;
447 void DSPReleaseTimeslice(void)
449 //This does absolutely nothing!!! !!! FIX !!!
450 dsp_releaseTimeSlice_flag = 1;
453 void dsp_build_branch_condition_table(void)
455 // Allocate the mirror table
457 mirror_table = (uint16 *)malloc(65536 * sizeof(uint16));
459 // Fill in the mirror table
461 for(int i=0; i<65536; i++)
462 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
463 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
464 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
465 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
466 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
467 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
468 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
469 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
471 if (!dsp_branch_condition_table)
473 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8));
475 // Fill in the condition table
476 if (dsp_branch_condition_table)
478 for(int i=0; i<8; i++)
480 for(int j=0; j<32; j++)
487 if (!(i & ZERO_FLAG))
490 if (i & (CARRY_FLAG << (j >> 4)))
493 if (!(i & (CARRY_FLAG << (j >> 4))))
495 dsp_branch_condition_table[i * 32 + j] = result;
502 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
504 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
505 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
507 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
510 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
512 if (offset==0xF1CFE0)
515 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
516 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
518 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
520 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
522 if ((offset&0x03)==0)
525 if ((offset&0x03)==1)
526 return((data>>16)&0xff);
528 if ((offset&0x03)==2)
529 return((data>>8)&0xff);
531 if ((offset&0x03)==3)
535 return JaguarReadByte(offset, who);
538 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
540 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
541 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
543 offset &= 0xFFFFFFFE;
545 /* if (jaguar_mainRom_crc32==0xa74a97cd)
547 if (offset==0xF1A114) return(0x0000);
548 if (offset==0xF1A116) return(0x0000);
549 if (offset==0xF1B000) return(0x1234);
550 if (offset==0xF1B002) return(0x5678);
553 if (jaguar_mainRom_crc32==0x7ae20823)
555 if (offset==0xF1B9D8) return(0x0000);
556 if (offset==0xF1B9Da) return(0x0000);
557 if (offset==0xF1B2C0) return(0x0000);
558 if (offset==0xF1B2C2) return(0x0000);
561 // pour permettre � wolfenstein 3d de tourner sans le dsp
562 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
566 // pour permettre � nba jam de tourner sans le dsp
567 /* if (jaguar_mainRom_crc32==0x4faddb18)
569 if (offset==0xf1b2c0) return(0);
570 if (offset==0xf1b2c2) return(0);
571 if (offset==0xf1b240) return(0);
572 if (offset==0xf1b242) return(0);
573 if (offset==0xF1B340) return(0);
574 if (offset==0xF1B342) return(0);
575 if (offset==0xF1BAD8) return(0);
576 if (offset==0xF1BADA) return(0);
577 if (offset==0xF1B040) return(0);
578 if (offset==0xF1B042) return(0);
579 if (offset==0xF1B0C0) return(0);
580 if (offset==0xF1B0C2) return(0);
581 if (offset==0xF1B140) return(0);
582 if (offset==0xF1B142) return(0);
583 if (offset==0xF1B1C0) return(0);
584 if (offset==0xF1B1C2) return(0);
587 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
589 offset -= DSP_WORK_RAM_BASE;
590 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
592 return GET16(dsp_ram_8, offset);
594 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
596 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
599 return data & 0xFFFF;
604 return JaguarReadWord(offset, who);
607 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
609 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
610 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
613 offset &= 0xFFFFFFFC;
614 /*if (offset == 0xF1BCF4)
616 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));
617 DSPDumpDisassembly();
619 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
621 offset -= DSP_WORK_RAM_BASE;
622 return GET32(dsp_ram_8, offset);
624 //NOTE: Didn't return DSP_ACCUM!!!
625 //Mebbe it's not 'spose to! Yes, it is!
626 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
631 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
632 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
633 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
635 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
636 return dsp_flags & 0xFFFFC1FF;
637 case 0x04: return dsp_matrix_control;
638 case 0x08: return dsp_pointer_to_matrix;
639 case 0x0C: return dsp_data_organization;
640 case 0x10: return dsp_pc;
641 case 0x14: return dsp_control;
642 case 0x18: return dsp_modulo;
643 case 0x1C: return dsp_remain;
645 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
647 // unaligned long read-- !!! FIX !!!
651 return JaguarReadLong(offset, who);
654 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
656 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
657 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
659 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
661 offset -= DSP_WORK_RAM_BASE;
662 dsp_ram_8[offset] = data;
663 //This is rather stupid! !!! FIX !!!
664 /* if (dsp_in_exec == 0)
666 m68k_end_timeslice();
667 gpu_releaseTimeslice();
671 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
673 uint32 reg = offset & 0x1C;
674 int bytenum = offset & 0x03;
676 if ((reg >= 0x1C) && (reg <= 0x1F))
677 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
680 //This looks funky. !!! FIX !!!
681 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
682 bytenum = 3 - bytenum; // convention motorola !!!
683 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
684 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
688 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
689 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
690 JaguarWriteByte(offset, data, who);
693 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
695 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
696 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
697 offset &= 0xFFFFFFFE;
698 /*if (offset == 0xF1BCF4)
700 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
702 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
703 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
705 /*if (offset == 0xF1B2F4)
707 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
709 offset -= DSP_WORK_RAM_BASE;
710 dsp_ram_8[offset] = data >> 8;
711 dsp_ram_8[offset+1] = data & 0xFF;
712 //This is rather stupid! !!! FIX !!!
713 /* if (dsp_in_exec == 0)
715 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
716 m68k_end_timeslice();
717 gpu_releaseTimeslice();
721 SET16(ram1, offset, data),
722 SET16(ram2, offset, data);
727 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
729 if ((offset & 0x1C) == 0x1C)
732 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
734 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
738 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
740 old_data = (old_data&0xffff0000)|(data&0xffff);
742 old_data = (old_data&0xffff)|((data&0xffff)<<16);
743 DSPWriteLong(offset & 0xffffffc, old_data, who);
748 JaguarWriteWord(offset, data, who);
751 //bool badWrite = false;
752 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
754 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
755 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
757 offset &= 0xFFFFFFFC;
758 /*if (offset == 0xF1BCF4)
760 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
762 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
763 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
765 /*if (offset == 0xF1BE2C)
767 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
769 offset -= DSP_WORK_RAM_BASE;
770 SET32(dsp_ram_8, offset, data);
773 SET32(ram1, offset, data),
774 SET32(ram2, offset, data);
779 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
787 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
789 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
790 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
792 dsp_flag_z = dsp_flags & 0x01;
793 dsp_flag_c = (dsp_flags >> 1) & 0x01;
794 dsp_flag_n = (dsp_flags >> 2) & 0x01;
795 DSPUpdateRegisterBanks();
796 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
797 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
798 /* if (IMASKCleared) // If IMASK was cleared,
801 WriteLog("DSP: Finished interrupt.\n");
803 DSPHandleIRQs(); // see if any other interrupts need servicing!
808 if (/*4-8, 16*/data & 0x101F0)
809 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
810 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
811 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
812 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
813 /*if (data & 0x00020) // CD BIOS DSP code...
815 //001AC1BA: movea.l #$1AC200, A0
816 //001AC1C0: move.l #$1AC68C, D0
819 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
820 uint32 j = 0xF1B97C;//0x1AC200;
821 while (j <= 0xF1BE08)//0x1AC68C)
824 j += dasmjag(JAGUAR_DSP, buffer, j);
825 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
826 WriteLog("\t%08X: %s\n", oldj, buffer);
833 dsp_matrix_control = data;
836 // According to JTRM, only lines 2-11 are addressable, the rest being
837 // hardwired to $F1Bxxx.
838 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
841 dsp_data_organization = data;
846 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
851 ctrl1[0] = ctrl2[0] = data;
858 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
860 bool wasRunning = DSP_RUNNING;
861 // uint32 dsp_was_running = DSP_RUNNING;
862 // Check for DSP -> CPU interrupt
866 WriteLog("DSP: DSP -> CPU interrupt\n");
869 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
870 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
871 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
873 JERRYSetPendingIRQ(IRQ2_DSP);
874 DSPReleaseTimeslice();
875 m68k_set_irq(2); // Set 68000 IPL 2...
879 // Check for CPU -> DSP interrupt
883 WriteLog("DSP: CPU -> DSP interrupt\n");
885 m68k_end_timeslice();
886 GPUReleaseTimeslice();
887 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
891 if (data & SINGLE_STEP)
893 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
896 // Protect writes to VERSION and the interrupt latches...
897 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
898 dsp_control = (dsp_control & mask) | (data & ~mask);
902 ctrl1[8] = ctrl2[8] = dsp_control;
906 // if dsp wasn't running but is now running
907 // execute a few cycles
908 //This is just plain wrong, wrong, WRONG!
909 #ifndef DSP_SINGLE_STEPPING
910 /* if (!dsp_was_running && DSP_RUNNING)
915 //This is WRONG! !!! FIX !!!
916 if (dsp_control & 0x18)
921 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
923 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
926 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
927 // !!! FIX !!! [DONE]
931 m68k_end_timeslice();
933 GPUReleaseTimeslice();
937 //DSPDumpDisassembly();
945 dsp_div_control = data;
947 // default: // unaligned long read
953 //We don't have to break this up like this! We CAN do 32 bit writes!
954 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
955 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
956 //if (offset > 0xF1FFFF)
958 JaguarWriteLong(offset, data, who);
962 // Update the DSP register file pointers depending on REGPAGE bit
964 void DSPUpdateRegisterBanks(void)
966 int bank = (dsp_flags & REGPAGE);
968 if (dsp_flags & IMASK)
969 bank = 0; // IMASK forces main bank to be bank 0
972 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
974 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
978 // Check for and handle any asserted DSP IRQs
980 void DSPHandleIRQs(void)
982 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
985 // Get the active interrupt bits (latches) & interrupt mask (enables)
986 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
987 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
989 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
992 if (!bits) // Bail if nothing is enabled
995 int which = 0; // Determine which interrupt
1009 #ifdef DSP_DEBUG_IRQ
1010 WriteLog("DSP: Generating interrupt #%i...", which);
1013 //if (which == 0) doDSPDis = true;
1015 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1016 // directly into the pipeline, it has the side effect of ensuring that the
1017 // instruction interrupted also gets to do its writeback. We simulate that
1019 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1021 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1022 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1024 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1025 scoreboard[pipeline[plPtrWrite].operand2] = false;
1027 //This should be execute (or should it?--not sure now!)
1028 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1029 //and what just executed is now in the Write position...). So why didn't it do the
1030 //writeback into register 0?
1031 #ifdef DSP_DEBUG_IRQ
1032 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1033 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]);
1034 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]);
1035 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]);
1037 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1039 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1041 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1042 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1045 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1046 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1047 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1048 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1050 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1054 #ifndef NEW_SCOREBOARD
1055 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1056 scoreboard[pipeline[plPtrWrite].operand2] = false;
1058 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1059 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1060 if (scoreboard[pipeline[plPtrWrite].operand2])
1061 scoreboard[pipeline[plPtrWrite].operand2]--;
1068 ctrl2[4] = dsp_flags;
1071 DSPUpdateRegisterBanks();
1072 #ifdef DSP_DEBUG_IRQ
1073 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1074 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]);
1077 // subqt #4,r31 ; pre-decrement stack pointer
1078 // move pc,r30 ; address of interrupted code
1079 // store r30,(r31) ; store return address
1086 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1087 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1088 //It missed the place that it was supposed to come back to, so this is WRONG!
1090 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1092 // R -> baz (<- PC points here)
1093 // E -> bar (when it should point here!)
1096 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1097 // which means (assuming they're all 2 bytes long) that the code below will come back on
1098 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1099 // instruction stream...
1101 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1102 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1105 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1109 // movei #service_address,r30 ; pointer to ISR entry
1110 // jump (r30) ; jump to ISR
1112 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1115 ctrl2[0] = regs2[30] = dsp_pc;
1122 // Non-pipelined version...
1124 void DSPHandleIRQsNP(void)
1128 memcpy(dsp_ram_8, ram1, 0x2000);
1129 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1130 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1133 dsp_remain = ctrl1[2];
1134 dsp_modulo = ctrl1[3];
1135 dsp_flags = ctrl1[4];
1136 dsp_matrix_control = ctrl1[5];
1137 dsp_pointer_to_matrix = ctrl1[6];
1138 dsp_data_organization = ctrl1[7];
1139 dsp_control = ctrl1[8];
1140 dsp_div_control = ctrl1[9];
1141 IMASKCleared = ctrl1[10];
1142 dsp_flag_z = ctrl1[11];
1143 dsp_flag_n = ctrl1[12];
1144 dsp_flag_c = ctrl1[13];
1145 DSPUpdateRegisterBanks();
1148 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1151 // Get the active interrupt bits (latches) & interrupt mask (enables)
1152 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1153 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1155 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1158 if (!bits) // Bail if nothing is enabled
1161 int which = 0; // Determine which interrupt
1175 #ifdef DSP_DEBUG_IRQ
1176 WriteLog("DSP: Generating interrupt #%i...", which);
1182 ctrl1[4] = dsp_flags;
1185 DSPUpdateRegisterBanks();
1186 #ifdef DSP_DEBUG_IRQ
1187 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1190 // subqt #4,r31 ; pre-decrement stack pointer
1191 // move pc,r30 ; address of interrupted code
1192 // store r30,(r31) ; store return address
1199 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1202 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1206 // movei #service_address,r30 ; pointer to ISR entry
1207 // jump (r30) ; jump to ISR
1209 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1212 ctrl1[0] = regs1[30] = dsp_pc;
1218 // Set the specified DSP IRQ line to a given state
1220 void DSPSetIRQLine(int irqline, int state)
1222 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1223 uint32 mask = INT_LAT0 << irqline;
1224 dsp_control &= ~mask; // Clear the latch bit
1227 ctrl1[8] = ctrl2[8] = dsp_control;
1233 dsp_control |= mask; // Set the latch bit
1237 ctrl1[8] = ctrl2[8] = dsp_control;
1243 // Not sure if this is correct behavior, but according to JTRM,
1244 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1245 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1246 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1251 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1252 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1253 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1255 dsp_build_branch_condition_table();
1261 dsp_pc = 0x00F1B000;
1262 dsp_acc = 0x00000000;
1263 dsp_remain = 0x00000000;
1264 dsp_modulo = 0xFFFFFFFF;
1265 dsp_flags = 0x00040000;
1266 dsp_matrix_control = 0x00000000;
1267 dsp_pointer_to_matrix = 0x00000000;
1268 dsp_data_organization = 0xFFFFFFFF;
1269 dsp_control = 0x00002000; // Report DSP version 2
1270 dsp_div_control = 0x00000000;
1273 dsp_reg = dsp_reg_bank_0;
1274 dsp_alternate_reg = dsp_reg_bank_1;
1276 for(int i=0; i<32; i++)
1277 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1280 IMASKCleared = false;
1283 memset(dsp_ram_8, 0xFF, 0x2000);
1286 void DSPDumpDisassembly(void)
1290 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1291 uint32 j = 0xF1B000;
1292 while (j <= 0xF1CFFF)
1295 j += dasmjag(JAGUAR_DSP, buffer, j);
1296 WriteLog("\t%08X: %s\n", oldj, buffer);
1300 void DSPDumpRegisters(void)
1302 //Shoud add modulus, etc to dump here...
1303 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1304 WriteLog("\nRegisters bank 0\n");
1305 for(int j=0; j<8; j++)
1307 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1308 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1309 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1310 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1311 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1313 WriteLog("Registers bank 1\n");
1314 for(int j=0; j<8; j++)
1316 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1317 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1318 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1319 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1320 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1327 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1328 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1330 // get the active interrupt bits
1331 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1332 // get the interrupt mask
1333 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1335 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1336 WriteLog("\nRegisters bank 0\n");
1337 for(int j=0; j<8; j++)
1339 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1340 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1341 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1342 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1343 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1345 WriteLog("\nRegisters bank 1\n");
1348 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1349 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1350 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1351 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1352 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1356 static char buffer[512];
1357 j = DSP_WORK_RAM_BASE;
1358 while (j <= 0xF1BFFF)
1361 j += dasmjag(JAGUAR_DSP, buffer, j);
1362 WriteLog("\t%08X: %s\n", oldj, buffer);
1365 WriteLog("DSP opcodes use:\n");
1368 if (dsp_opcode_use[i])
1369 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1372 // memory_free(dsp_ram_8);
1373 // memory_free(dsp_reg_bank_0);
1374 // memory_free(dsp_reg_bank_1);
1375 if (dsp_branch_condition_table)
1376 free(dsp_branch_condition_table);
1385 // DSP comparison core...
1388 static uint16 lastExec;
1389 void DSPExecComp(int32 cycles)
1391 while (cycles > 0 && DSP_RUNNING)
1393 // Load up vars for non-pipelined core
1394 memcpy(dsp_ram_8, ram1, 0x2000);
1395 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1396 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1399 dsp_remain = ctrl1[2];
1400 dsp_modulo = ctrl1[3];
1401 dsp_flags = ctrl1[4];
1402 dsp_matrix_control = ctrl1[5];
1403 dsp_pointer_to_matrix = ctrl1[6];
1404 dsp_data_organization = ctrl1[7];
1405 dsp_control = ctrl1[8];
1406 dsp_div_control = ctrl1[9];
1407 IMASKCleared = ctrl1[10];
1408 dsp_flag_z = ctrl1[11];
1409 dsp_flag_n = ctrl1[12];
1410 dsp_flag_c = ctrl1[13];
1411 DSPUpdateRegisterBanks();
1413 // Decrement cycles based on non-pipelined core...
1414 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1415 cycles -= dsp_opcode_cycles[instr1 >> 10];
1417 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1418 DSPExec(1); // Do *one* instruction
1421 memcpy(ram1, dsp_ram_8, 0x2000);
1422 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1423 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1426 ctrl1[2] = dsp_remain;
1427 ctrl1[3] = dsp_modulo;
1428 ctrl1[4] = dsp_flags;
1429 ctrl1[5] = dsp_matrix_control;
1430 ctrl1[6] = dsp_pointer_to_matrix;
1431 ctrl1[7] = dsp_data_organization;
1432 ctrl1[8] = dsp_control;
1433 ctrl1[9] = dsp_div_control;
1434 ctrl1[10] = IMASKCleared;
1435 ctrl1[11] = dsp_flag_z;
1436 ctrl1[12] = dsp_flag_n;
1437 ctrl1[13] = dsp_flag_c;
1439 // Load up vars for pipelined core
1440 memcpy(dsp_ram_8, ram2, 0x2000);
1441 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1442 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1445 dsp_remain = ctrl2[2];
1446 dsp_modulo = ctrl2[3];
1447 dsp_flags = ctrl2[4];
1448 dsp_matrix_control = ctrl2[5];
1449 dsp_pointer_to_matrix = ctrl2[6];
1450 dsp_data_organization = ctrl2[7];
1451 dsp_control = ctrl2[8];
1452 dsp_div_control = ctrl2[9];
1453 IMASKCleared = ctrl2[10];
1454 dsp_flag_z = ctrl2[11];
1455 dsp_flag_n = ctrl2[12];
1456 dsp_flag_c = ctrl2[13];
1457 DSPUpdateRegisterBanks();
1459 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1460 DSPExecP2(1); // Do *one* instruction
1463 memcpy(ram2, dsp_ram_8, 0x2000);
1464 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1465 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1468 ctrl2[2] = dsp_remain;
1469 ctrl2[3] = dsp_modulo;
1470 ctrl2[4] = dsp_flags;
1471 ctrl2[5] = dsp_matrix_control;
1472 ctrl2[6] = dsp_pointer_to_matrix;
1473 ctrl2[7] = dsp_data_organization;
1474 ctrl2[8] = dsp_control;
1475 ctrl2[9] = dsp_div_control;
1476 ctrl2[10] = IMASKCleared;
1477 ctrl2[11] = dsp_flag_z;
1478 ctrl2[12] = dsp_flag_n;
1479 ctrl2[13] = dsp_flag_c;
1481 if (instr1 != lastExec)
1483 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1485 // 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));
1486 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1487 // if (ctrl1[0] < ppc) // P ran ahead of NP
1488 //How to test this crap???
1491 DSPExecP2(1); // Do one more instruction
1494 memcpy(ram2, dsp_ram_8, 0x2000);
1495 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1496 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1499 ctrl2[2] = dsp_remain;
1500 ctrl2[3] = dsp_modulo;
1501 ctrl2[4] = dsp_flags;
1502 ctrl2[5] = dsp_matrix_control;
1503 ctrl2[6] = dsp_pointer_to_matrix;
1504 ctrl2[7] = dsp_data_organization;
1505 ctrl2[8] = dsp_control;
1506 ctrl2[9] = dsp_div_control;
1507 ctrl2[10] = IMASKCleared;
1508 ctrl2[11] = dsp_flag_z;
1509 ctrl2[12] = dsp_flag_n;
1510 ctrl2[13] = dsp_flag_c;
1512 // else // NP ran ahead of P
1513 if (instr1 != lastExec) // Must be the other way...
1516 // Load up vars for non-pipelined core
1517 memcpy(dsp_ram_8, ram1, 0x2000);
1518 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1519 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1522 dsp_remain = ctrl1[2];
1523 dsp_modulo = ctrl1[3];
1524 dsp_flags = ctrl1[4];
1525 dsp_matrix_control = ctrl1[5];
1526 dsp_pointer_to_matrix = ctrl1[6];
1527 dsp_data_organization = ctrl1[7];
1528 dsp_control = ctrl1[8];
1529 dsp_div_control = ctrl1[9];
1530 IMASKCleared = ctrl1[10];
1531 dsp_flag_z = ctrl1[11];
1532 dsp_flag_n = ctrl1[12];
1533 dsp_flag_c = ctrl1[13];
1534 DSPUpdateRegisterBanks();
1536 for(int k=0; k<2; k++)
1538 // Decrement cycles based on non-pipelined core...
1539 instr1 = DSPReadWord(dsp_pc, DSP);
1540 cycles -= dsp_opcode_cycles[instr1 >> 10];
1542 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1543 DSPExec(1); // Do *one* instruction
1547 memcpy(ram1, dsp_ram_8, 0x2000);
1548 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1549 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1552 ctrl1[2] = dsp_remain;
1553 ctrl1[3] = dsp_modulo;
1554 ctrl1[4] = dsp_flags;
1555 ctrl1[5] = dsp_matrix_control;
1556 ctrl1[6] = dsp_pointer_to_matrix;
1557 ctrl1[7] = dsp_data_organization;
1558 ctrl1[8] = dsp_control;
1559 ctrl1[9] = dsp_div_control;
1560 ctrl1[10] = IMASKCleared;
1561 ctrl1[11] = dsp_flag_z;
1562 ctrl1[12] = dsp_flag_n;
1563 ctrl1[13] = dsp_flag_c;
1567 if (instr1 != lastExec)
1569 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1571 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1572 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1585 // DSP execution core
1587 //static bool R20Set = false, tripwire = false;
1588 //static uint32 pcQueue[32], ptrPCQ = 0;
1589 void DSPExec(int32 cycles)
1591 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1592 dsp_check_if_i2s_interrupt_needed();*/
1594 #ifdef DSP_SINGLE_STEPPING
1595 if (dsp_control & 0x18)
1598 dsp_control &= ~0x10;
1601 //There is *no* good reason to do this here!
1603 dsp_releaseTimeSlice_flag = 0;
1606 while (cycles > 0 && DSP_RUNNING)
1608 /*extern uint32 totalFrames;
1609 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1610 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1611 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1613 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1616 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1618 if (dsp_pc == 0xF1B092)
1619 doDSPDis = false;//*/
1620 /*if (dsp_pc == 0xF1B140)
1621 doDSPDis = true;//*/
1623 if (IMASKCleared) // If IMASK was cleared,
1625 #ifdef DSP_DEBUG_IRQ
1626 WriteLog("DSP: Finished interrupt.\n");
1628 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1629 IMASKCleared = false;
1634 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1635 for(int i=0; i<80; i+=4)
1636 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1639 /*if (dsp_pc == 0xF1B55E)
1641 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1643 /*if (dsp_pc == 0xF1B7D2) // Start here???
1645 pcQueue[ptrPCQ++] = dsp_pc;
1647 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1648 uint32 index = opcode >> 10;
1649 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1650 dsp_opcode_second_parameter = opcode & 0x1F;
1652 dsp_opcode[index]();
1653 dsp_opcode_use[index]++;
1654 cycles -= dsp_opcode_cycles[index];
1655 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1657 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1660 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1662 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1664 DSPDumpDisassembly();
1667 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1670 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1673 WriteLog("\nBacktrace:\n");
1674 for(int i=0; i<32; i++)
1676 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1677 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1687 // DSP opcode handlers
1690 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1691 // can cause trouble because an interrupt can occur *before* the instruction following the
1692 // jump can execute... !!! FIX !!!
1693 static void dsp_opcode_jump(void)
1696 const char * condition[32] =
1697 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1698 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1699 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1700 "???", "???", "???", "F" };
1702 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);
1705 /* dsp_flag_c=dsp_flag_c?1:0;
1706 dsp_flag_z=dsp_flag_z?1:0;
1707 dsp_flag_n=dsp_flag_n?1:0;*/
1708 // KLUDGE: Used by BRANCH_CONDITION
1709 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1711 if (BRANCH_CONDITION(IMM_2))
1715 WriteLog("Branched!\n");
1717 uint32 delayed_pc = RM;
1719 dsp_pc = delayed_pc;
1724 WriteLog("Branch NOT taken.\n");
1728 static void dsp_opcode_jr(void)
1731 const char * condition[32] =
1732 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1733 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1734 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1735 "???", "???", "???", "F" };
1737 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);
1740 /* dsp_flag_c=dsp_flag_c?1:0;
1741 dsp_flag_z=dsp_flag_z?1:0;
1742 dsp_flag_n=dsp_flag_n?1:0;*/
1743 // KLUDGE: Used by BRANCH_CONDITION
1744 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1746 if (BRANCH_CONDITION(IMM_2))
1750 WriteLog("Branched!\n");
1752 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1753 int32 delayed_pc = dsp_pc + (offset * 2);
1755 dsp_pc = delayed_pc;
1760 WriteLog("Branch NOT taken.\n");
1764 static void dsp_opcode_add(void)
1768 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);
1770 uint32 res = RN + RM;
1771 SET_ZNC_ADD(RN, RM, res);
1775 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1779 static void dsp_opcode_addc(void)
1783 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);
1785 uint32 res = RN + RM + dsp_flag_c;
1786 uint32 carry = dsp_flag_c;
1787 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1788 SET_ZNC_ADD(RN + carry, RM, res);
1789 // SET_ZNC_ADD(RN, RM + carry, res);
1793 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);
1797 static void dsp_opcode_addq(void)
1801 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);
1803 uint32 r1 = dsp_convert_zero[IMM_1];
1804 uint32 res = RN + r1;
1805 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1809 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1813 static void dsp_opcode_sub(void)
1817 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);
1819 uint32 res = RN - RM;
1820 SET_ZNC_SUB(RN, RM, res);
1824 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);
1828 static void dsp_opcode_subc(void)
1832 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);
1834 uint32 res = RN - RM - dsp_flag_c;
1835 uint32 borrow = dsp_flag_c;
1836 SET_ZNC_SUB(RN - borrow, RM, res);
1840 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);
1844 static void dsp_opcode_subq(void)
1848 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);
1850 uint32 r1 = dsp_convert_zero[IMM_1];
1851 uint32 res = RN - r1;
1852 SET_ZNC_SUB(RN, r1, res);
1856 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1860 static void dsp_opcode_cmp(void)
1864 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);
1866 uint32 res = RN - RM;
1867 SET_ZNC_SUB(RN, RM, res);
1870 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1874 static void dsp_opcode_cmpq(void)
1876 static int32 sqtable[32] =
1877 { 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 };
1880 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);
1882 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1883 uint32 res = RN - r1;
1884 SET_ZNC_SUB(RN, r1, res);
1887 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1891 static void dsp_opcode_and(void)
1895 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);
1901 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1905 static void dsp_opcode_or(void)
1909 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);
1915 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);
1919 static void dsp_opcode_xor(void)
1923 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);
1929 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);
1933 static void dsp_opcode_not(void)
1937 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1943 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1947 static void dsp_opcode_move_pc(void)
1952 static void dsp_opcode_store_r14_indexed(void)
1954 #ifdef DSP_DIS_STORE14I
1956 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));
1958 #ifdef DSP_CORRECT_ALIGNMENT
1959 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1961 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1965 static void dsp_opcode_store_r15_indexed(void)
1967 #ifdef DSP_DIS_STORE15I
1969 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));
1971 #ifdef DSP_CORRECT_ALIGNMENT
1972 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1974 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1978 static void dsp_opcode_load_r14_ri(void)
1980 #ifdef DSP_DIS_LOAD14R
1982 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);
1984 #ifdef DSP_CORRECT_ALIGNMENT
1985 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1987 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1989 #ifdef DSP_DIS_LOAD14R
1991 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1995 static void dsp_opcode_load_r15_ri(void)
1997 #ifdef DSP_DIS_LOAD15R
1999 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);
2001 #ifdef DSP_CORRECT_ALIGNMENT
2002 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2004 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2006 #ifdef DSP_DIS_LOAD15R
2008 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2012 static void dsp_opcode_store_r14_ri(void)
2014 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2017 static void dsp_opcode_store_r15_ri(void)
2019 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2022 static void dsp_opcode_nop(void)
2026 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2030 static void dsp_opcode_storeb(void)
2032 #ifdef DSP_DIS_STOREB
2034 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);
2036 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037 DSPWriteLong(RM, RN & 0xFF, DSP);
2039 JaguarWriteByte(RM, RN, DSP);
2042 static void dsp_opcode_storew(void)
2044 #ifdef DSP_DIS_STOREW
2046 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);
2048 #ifdef DSP_CORRECT_ALIGNMENT
2049 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2050 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2052 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2054 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2055 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2057 JaguarWriteWord(RM, RN, DSP);
2061 static void dsp_opcode_store(void)
2063 #ifdef DSP_DIS_STORE
2065 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);
2067 #ifdef DSP_CORRECT_ALIGNMENT
2068 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2070 DSPWriteLong(RM, RN, DSP);
2074 static void dsp_opcode_loadb(void)
2076 #ifdef DSP_DIS_LOADB
2078 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);
2080 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2081 RN = DSPReadLong(RM, DSP) & 0xFF;
2083 RN = JaguarReadByte(RM, DSP);
2084 #ifdef DSP_DIS_LOADB
2086 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2090 static void dsp_opcode_loadw(void)
2092 #ifdef DSP_DIS_LOADW
2094 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);
2096 #ifdef DSP_CORRECT_ALIGNMENT
2097 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2098 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2100 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2102 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2103 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2105 RN = JaguarReadWord(RM, DSP);
2107 #ifdef DSP_DIS_LOADW
2109 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2113 static void dsp_opcode_load(void)
2117 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);
2119 #ifdef DSP_CORRECT_ALIGNMENT
2120 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2122 RN = DSPReadLong(RM, DSP);
2126 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2130 static void dsp_opcode_load_r14_indexed(void)
2132 #ifdef DSP_DIS_LOAD14I
2134 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);
2136 #ifdef DSP_CORRECT_ALIGNMENT
2137 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2139 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2141 #ifdef DSP_DIS_LOAD14I
2143 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2147 static void dsp_opcode_load_r15_indexed(void)
2149 #ifdef DSP_DIS_LOAD15I
2151 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);
2153 #ifdef DSP_CORRECT_ALIGNMENT
2154 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2156 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2158 #ifdef DSP_DIS_LOAD15I
2160 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2164 static void dsp_opcode_movei(void)
2166 #ifdef DSP_DIS_MOVEI
2168 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);
2170 // This instruction is followed by 32-bit value in LSW / MSW format...
2171 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2173 #ifdef DSP_DIS_MOVEI
2175 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2179 static void dsp_opcode_moveta(void)
2181 #ifdef DSP_DIS_MOVETA
2183 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);
2186 #ifdef DSP_DIS_MOVETA
2188 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);
2192 static void dsp_opcode_movefa(void)
2194 #ifdef DSP_DIS_MOVEFA
2196 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);
2199 #ifdef DSP_DIS_MOVEFA
2201 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);
2205 static void dsp_opcode_move(void)
2209 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);
2214 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);
2218 static void dsp_opcode_moveq(void)
2220 #ifdef DSP_DIS_MOVEQ
2222 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);
2225 #ifdef DSP_DIS_MOVEQ
2227 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2231 static void dsp_opcode_resmac(void)
2233 #ifdef DSP_DIS_RESMAC
2235 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));
2237 RN = (uint32)dsp_acc;
2238 #ifdef DSP_DIS_RESMAC
2240 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2244 static void dsp_opcode_imult(void)
2246 #ifdef DSP_DIS_IMULT
2248 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);
2250 RN = (int16)RN * (int16)RM;
2252 #ifdef DSP_DIS_IMULT
2254 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);
2258 static void dsp_opcode_mult(void)
2262 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);
2264 RN = (uint16)RM * (uint16)RN;
2268 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);
2272 static void dsp_opcode_bclr(void)
2276 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);
2278 uint32 res = RN & ~(1 << IMM_1);
2283 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2287 static void dsp_opcode_btst(void)
2291 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);
2293 dsp_flag_z = (~RN >> IMM_1) & 1;
2296 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2300 static void dsp_opcode_bset(void)
2304 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);
2306 uint32 res = RN | (1 << IMM_1);
2311 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2315 static void dsp_opcode_subqt(void)
2317 #ifdef DSP_DIS_SUBQT
2319 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);
2321 RN -= dsp_convert_zero[IMM_1];
2322 #ifdef DSP_DIS_SUBQT
2324 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2328 static void dsp_opcode_addqt(void)
2330 #ifdef DSP_DIS_ADDQT
2332 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);
2334 RN += dsp_convert_zero[IMM_1];
2335 #ifdef DSP_DIS_ADDQT
2337 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2341 static void dsp_opcode_imacn(void)
2343 #ifdef DSP_DIS_IMACN
2345 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);
2347 int32 res = (int16)RM * (int16)RN;
2348 dsp_acc += (int64)res;
2349 //Should we AND the result to fit into 40 bits here???
2350 #ifdef DSP_DIS_IMACN
2352 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));
2356 static void dsp_opcode_mtoi(void)
2358 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2362 static void dsp_opcode_normi(void)
2369 while ((_Rm & 0xffc00000) == 0)
2374 while ((_Rm & 0xff800000) != 0)
2384 static void dsp_opcode_mmult(void)
2386 int count = dsp_matrix_control&0x0f;
2387 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2391 if (!(dsp_matrix_control & 0x10))
2393 for (int i = 0; i < count; i++)
2397 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2399 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2400 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2407 for (int i = 0; i < count; i++)
2411 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2413 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2414 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2419 RN = res = (int32)accum;
2421 //NOTE: The flags are set based upon the last add/multiply done...
2425 static void dsp_opcode_abs(void)
2429 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);
2434 if (_Rn == 0x80000000)
2438 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2439 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2444 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2448 static void dsp_opcode_div(void)
2455 if (dsp_div_control & 1)
2457 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2458 if (dsp_remain&0x80000000)
2460 RN = (((uint64)_Rn) << 16) / _Rm;
2464 dsp_remain = _Rn % _Rm;
2465 if (dsp_remain&0x80000000)
2474 static void dsp_opcode_imultn(void)
2476 #ifdef DSP_DIS_IMULTN
2478 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);
2480 // This is OK, since this multiply won't overflow 32 bits...
2481 int32 res = (int32)((int16)RN * (int16)RM);
2482 dsp_acc = (int64)res;
2484 #ifdef DSP_DIS_IMULTN
2486 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));
2490 static void dsp_opcode_neg(void)
2494 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);
2497 SET_ZNC_SUB(0, RN, res);
2501 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2505 static void dsp_opcode_shlq(void)
2509 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);
2511 int32 r1 = 32 - IMM_1;
2512 uint32 res = RN << r1;
2513 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2517 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2521 static void dsp_opcode_shrq(void)
2525 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);
2527 int32 r1 = dsp_convert_zero[IMM_1];
2528 uint32 res = RN >> r1;
2529 SET_ZN(res); dsp_flag_c = RN & 1;
2533 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2537 static void dsp_opcode_ror(void)
2541 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);
2543 uint32 r1 = RM & 0x1F;
2544 uint32 res = (RN >> r1) | (RN << (32 - r1));
2545 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2549 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);
2553 static void dsp_opcode_rorq(void)
2557 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);
2559 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2561 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2563 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2570 static void dsp_opcode_sha(void)
2572 int32 sRm=(int32)RM;
2578 if (shift>=32) shift=32;
2579 dsp_flag_c=(_Rn&0x80000000)>>31;
2589 if (shift>=32) shift=32;
2593 _Rn=((int32)_Rn)>>1;
2601 static void dsp_opcode_sharq(void)
2603 #ifdef DSP_DIS_SHARQ
2605 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);
2607 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2608 SET_ZN(res); dsp_flag_c = RN & 0x01;
2610 #ifdef DSP_DIS_SHARQ
2612 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2616 static void dsp_opcode_sh(void)
2618 int32 sRm=(int32)RM;
2623 uint32 shift=(-sRm);
2624 if (shift>=32) shift=32;
2625 dsp_flag_c=(_Rn&0x80000000)>>31;
2635 if (shift>=32) shift=32;
2647 void dsp_opcode_addqmod(void)
2649 #ifdef DSP_DIS_ADDQMOD
2651 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);
2653 uint32 r1 = dsp_convert_zero[IMM_1];
2655 uint32 res = r2 + r1;
2656 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2658 SET_ZNC_ADD(r2, r1, res);
2659 #ifdef DSP_DIS_ADDQMOD
2661 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2665 void dsp_opcode_subqmod(void)
2667 uint32 r1 = dsp_convert_zero[IMM_1];
2669 uint32 res = r2 - r1;
2670 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2673 SET_ZNC_SUB(r2, r1, res);
2676 void dsp_opcode_mirror(void)
2679 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2683 void dsp_opcode_sat32s(void)
2685 int32 r2 = (uint32)RN;
2686 int32 temp = dsp_acc >> 32;
2687 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2692 void dsp_opcode_sat16s(void)
2695 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2701 // New pipelined DSP core
2704 static void DSP_abs(void);
2705 static void DSP_add(void);
2706 static void DSP_addc(void);
2707 static void DSP_addq(void);
2708 static void DSP_addqmod(void);
2709 static void DSP_addqt(void);
2710 static void DSP_and(void);
2711 static void DSP_bclr(void);
2712 static void DSP_bset(void);
2713 static void DSP_btst(void);
2714 static void DSP_cmp(void);
2715 static void DSP_cmpq(void);
2716 static void DSP_div(void);
2717 static void DSP_imacn(void);
2718 static void DSP_imult(void);
2719 static void DSP_imultn(void);
2720 static void DSP_illegal(void);
2721 static void DSP_jr(void);
2722 static void DSP_jump(void);
2723 static void DSP_load(void);
2724 static void DSP_loadb(void);
2725 static void DSP_loadw(void);
2726 static void DSP_load_r14_i(void);
2727 static void DSP_load_r14_r(void);
2728 static void DSP_load_r15_i(void);
2729 static void DSP_load_r15_r(void);
2730 static void DSP_mirror(void);
2731 static void DSP_mmult(void);
2732 static void DSP_move(void);
2733 static void DSP_movefa(void);
2734 static void DSP_movei(void);
2735 static void DSP_movepc(void);
2736 static void DSP_moveq(void);
2737 static void DSP_moveta(void);
2738 static void DSP_mtoi(void);
2739 static void DSP_mult(void);
2740 static void DSP_neg(void);
2741 static void DSP_nop(void);
2742 static void DSP_normi(void);
2743 static void DSP_not(void);
2744 static void DSP_or(void);
2745 static void DSP_resmac(void);
2746 static void DSP_ror(void);
2747 static void DSP_rorq(void);
2748 static void DSP_sat16s(void);
2749 static void DSP_sat32s(void);
2750 static void DSP_sh(void);
2751 static void DSP_sha(void);
2752 static void DSP_sharq(void);
2753 static void DSP_shlq(void);
2754 static void DSP_shrq(void);
2755 static void DSP_store(void);
2756 static void DSP_storeb(void);
2757 static void DSP_storew(void);
2758 static void DSP_store_r14_i(void);
2759 static void DSP_store_r14_r(void);
2760 static void DSP_store_r15_i(void);
2761 static void DSP_store_r15_r(void);
2762 static void DSP_sub(void);
2763 static void DSP_subc(void);
2764 static void DSP_subq(void);
2765 static void DSP_subqmod(void);
2766 static void DSP_subqt(void);
2767 static void DSP_xor(void);
2769 void (* DSPOpcode[64])() =
2771 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2772 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2773 DSP_neg, DSP_and, DSP_or, DSP_xor,
2774 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2776 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2777 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2778 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2779 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2781 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2782 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2783 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2784 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2786 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2787 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2788 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2789 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2792 bool readAffected[64][2] =
2794 { true, true}, { true, true}, {false, true}, {false, true},
2795 { true, true}, { true, true}, {false, true}, {false, true},
2796 {false, true}, { true, true}, { true, true}, { true, true},
2797 {false, true}, {false, true}, {false, true}, {false, true},
2799 { true, true}, { true, true}, { true, true}, {false, true},
2800 { true, true}, { true, true}, {false, true}, { true, true},
2801 {false, true}, {false, true}, { true, true}, {false, true},
2802 { true, true}, {false, true}, { true, true}, {false, true},
2804 {false, true}, {false, true}, { true, false}, {false, false},
2805 { true, false}, {false, false}, {false, false}, { true, false},
2806 { true, false}, { true, false}, {false, true}, { true, false},
2807 { true, false}, { true, true}, { true, true}, { true, true},
2809 {false, true}, { true, true}, { true, true}, {false, true},
2810 { true, false}, { true, false}, { true, true}, { true, false},
2811 { true, false}, {false, false}, { true, false}, { true, false},
2812 { true, true}, { true, true}, {false, false}, {false, true}
2815 bool isLoadStore[65] =
2817 false, false, false, false, false, false, false, false,
2818 false, false, false, false, false, false, false, false,
2820 false, false, false, false, false, false, false, false,
2821 false, false, false, false, false, false, false, false,
2823 false, false, false, false, false, false, false, true,
2824 true, true, false, true, true, true, true, true,
2826 false, true, true, false, false, false, false, false,
2827 false, false, true, true, true, true, false, false, false
2830 void FlushDSPPipeline(void)
2832 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2834 for(int i=0; i<4; i++)
2835 pipeline[i].opcode = PIPELINE_STALL;
2837 for(int i=0; i<32; i++)
2842 // New pipelined DSP execution core
2844 /*void DSPExecP(int32 cycles)
2846 // bool inhibitFetch = false;
2848 dsp_releaseTimeSlice_flag = 0;
2851 while (cycles > 0 && DSP_RUNNING)
2853 WriteLog("DSPExecP: Pipeline status...\n");
2854 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2855 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2856 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2857 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2858 WriteLog(" --> Scoreboard: ");
2859 for(int i=0; i<32; i++)
2860 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2862 // Stage 1: Instruction fetch
2863 // if (!inhibitFetch)
2865 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2866 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2867 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2868 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2869 if (pipeline[plPtrFetch].opcode == 38)
2870 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2871 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2874 // inhibitFetch = false;
2875 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2877 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2878 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);
2879 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);
2880 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);
2881 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);
2882 // Stage 2: Read registers
2883 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2884 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2885 if (scoreboard[pipeline[plPtrRead].operand2])
2886 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2887 // We have a hit in the scoreboard, so we have to stall the pipeline...
2889 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2890 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2891 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2892 pipeline[plPtrFetch] = pipeline[plPtrRead];
2893 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2897 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2898 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2899 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2901 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2902 // Shouldn't we be more selective with the register scoreboarding?
2903 // Yes, we should. !!! FIX !!!
2904 scoreboard[pipeline[plPtrRead].operand2] = true;
2905 //Advance PC here??? Yes.
2906 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2907 //This is a mangling of the pipeline stages, but what else to do???
2908 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2911 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2912 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);
2913 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);
2914 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);
2915 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);
2917 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2919 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2920 DSPOpcode[pipeline[plPtrExec].opcode]();
2921 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2922 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2927 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2928 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);
2929 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);
2930 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);
2931 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);
2932 // Stage 4: Write back register
2933 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2935 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2936 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2938 scoreboard[pipeline[plPtrWrite].operand1]
2939 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2942 // Push instructions through the pipeline...
2943 plPtrFetch = (++plPtrFetch) & 0x03;
2944 plPtrRead = (++plPtrRead) & 0x03;
2945 plPtrExec = (++plPtrExec) & 0x03;
2946 plPtrWrite = (++plPtrWrite) & 0x03;
2953 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2955 // Should be fixed now. Another problem is figuring how to do the sequence following
2956 // a branch followed with the JR & JUMP instructions...
2958 // There are two conflicting problems:
2961 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2962 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2963 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2964 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2965 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2966 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2967 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2968 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2969 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2970 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2971 DSP: Finished interrupt.
2972 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2973 ; bank 0 (where is was prepared)!
2974 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2975 F1B252: NOP [NCZ:001]
2978 // The other is when you see this at the end of an IRQ:
2981 JUMP T, (R29) ; R29 = Previous stack + 2
2982 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2984 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2985 ; 1) The STORE goes through the pipeline and is executed/written back
2986 ; 2) The pipeline is flushed
2987 ; 3) The DSP_PC is set to the new address
2988 ; 4) Execution resumes
2990 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2991 ; bank 0 instead of the current bank 1 and so goes astray!
2994 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2995 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2999 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3000 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3001 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3002 If it were done properly, the STORE write back would occur *after* (well, technically,
3003 during) the execution of the the JUMP that follows it.
3007 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3008 F1B08A: NOP [NCZ:001]
3010 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3013 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3016 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3017 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3018 F1B08A: NOP [NCZ:001]
3020 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3023 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3024 DSP: CPU -> DSP interrupt
3025 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3026 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3028 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3031 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3032 F1B006: NOP [NCZ:001]
3034 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3037 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3038 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3041 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3042 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3045 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3046 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3049 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3050 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3053 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3056 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3059 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3060 F1B0FE: NOP [NCZ:000]
3062 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3065 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3068 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3069 F1B138: NOP [NCZ:000]
3071 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3074 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3075 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3076 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3079 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3080 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3083 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3084 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3085 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3087 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3088 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3091 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3092 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3093 DSP: Finished interrupt.
3094 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3096 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3099 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3100 F1B016: NOP [NCZ:001]
3102 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3105 uint32 pcQueue1[0x400];
3107 static uint32 prevR1;
3108 //Let's try a 3 stage pipeline....
3109 //Looks like 3 stage is correct, otherwise bad things happen...
3110 void DSPExecP2(int32 cycles)
3112 dsp_releaseTimeSlice_flag = 0;
3115 while (cycles > 0 && DSP_RUNNING)
3117 /*extern uint32 totalFrames;
3118 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3119 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3120 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3122 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3125 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3127 if (dsp_pc == 0xF1B092)
3128 doDSPDis = false;//*/
3129 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3130 doDSPDis = true;//*/
3131 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3132 doDSPDis = true;//*/
3133 /*if (dsp_pc == 0xF1B0A0)
3134 doDSPDis = true;//*/
3135 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3136 doDSPDis = true;//*/
3137 //Two parter... (not sure how to write this)
3138 //if (dsp_pc == 0xF1B0D2)
3139 // prevR1 = dsp_reg[1];
3141 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3142 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3145 pcQueue1[pcQPtr1++] = dsp_pc;
3148 #ifdef DSP_DEBUG_PL2
3149 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3151 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3156 for(int i=0; i<0x400; i++)
3158 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3159 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3165 if (IMASKCleared) // If IMASK was cleared,
3167 #ifdef DSP_DEBUG_IRQ
3168 WriteLog("DSP: Finished interrupt.\n");
3170 DSPHandleIRQs(); // See if any other interrupts are pending!
3171 IMASKCleared = false;
3174 //if (dsp_flags & REGPAGE)
3175 // WriteLog(" --> REGPAGE has just been set!\n");
3176 #ifdef DSP_DEBUG_PL2
3179 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3180 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]);
3181 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]);
3182 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]);
3183 WriteLog(" --> Scoreboard: ");
3184 for(int i=0; i<32; i++)
3185 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3189 // Stage 1a: Instruction fetch
3190 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3191 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3192 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3193 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3194 if (pipeline[plPtrRead].opcode == 38)
3195 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3196 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3197 #ifdef DSP_DEBUG_PL2
3200 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3201 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3202 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]);
3203 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]);
3204 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 1b: Read registers
3208 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3209 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3211 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3212 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3213 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3214 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3215 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3216 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3217 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3219 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3220 // We have a hit in the scoreboard, so we have to stall the pipeline...
3221 #ifdef DSP_DEBUG_PL2
3225 WriteLog(" --> Stalling pipeline: ");
3226 if (readAffected[pipeline[plPtrRead].opcode][0])
3227 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3228 if (readAffected[pipeline[plPtrRead].opcode][1])
3229 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3233 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3234 #ifdef DSP_DEBUG_PL2
3239 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3240 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3241 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3243 // Shouldn't we be more selective with the register scoreboarding?
3244 // Yes, we should. !!! FIX !!! Kinda [DONE]
3245 #ifndef NEW_SCOREBOARD
3246 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3248 //Hopefully this will fix the dual MOVEQ # problem...
3249 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3252 //Advance PC here??? Yes.
3253 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3256 #ifdef DSP_DEBUG_PL2
3259 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3260 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]);
3261 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]);
3262 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]);
3266 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3268 #ifdef DSP_DEBUG_PL2
3270 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"));
3274 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3279 lastExec = pipeline[plPtrExec].instruction;
3280 //WriteLog("[lastExec = %04X]\n", lastExec);
3282 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3283 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3284 DSPOpcode[pipeline[plPtrExec].opcode]();
3285 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3289 //Let's not, until we do the stalling correctly...
3290 //But, we gotta while we're doing the comparison core...!
3291 //Or do we? cycles--;
3292 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3293 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3294 //to model this clock cycle behavior correctly...
3295 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3296 //don't affect the reads at stage 1...
3297 #ifdef DSP_DEBUG_STALL
3299 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3303 #ifdef DSP_DEBUG_PL2
3306 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3307 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]);
3308 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]);
3309 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]);
3313 // Stage 3: Write back register/memory address
3314 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3316 /*if (pipeline[plPtrWrite].writebackRegister == 3
3317 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3320 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3323 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3325 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3326 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3329 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3330 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3331 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3332 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3334 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3338 #ifndef NEW_SCOREBOARD
3339 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3340 scoreboard[pipeline[plPtrWrite].operand2] = false;
3342 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3343 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3344 if (scoreboard[pipeline[plPtrWrite].operand2])
3345 scoreboard[pipeline[plPtrWrite].operand2]--;
3349 // Push instructions through the pipeline...
3350 plPtrRead = (++plPtrRead) & 0x03;
3351 plPtrExec = (++plPtrExec) & 0x03;
3352 plPtrWrite = (++plPtrWrite) & 0x03;
3361 //#define DSP_DEBUG_PL3
3362 //Let's try a 2 stage pipeline....
3363 void DSPExecP3(int32 cycles)
3365 dsp_releaseTimeSlice_flag = 0;
3368 while (cycles > 0 && DSP_RUNNING)
3370 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3372 #ifdef DSP_DEBUG_PL3
3373 WriteLog("DSPExecP: Pipeline status...\n");
3374 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]);
3375 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]);
3376 WriteLog(" --> Scoreboard: ");
3377 for(int i=0; i<32; i++)
3378 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3381 // Stage 1a: Instruction fetch
3382 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3383 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3384 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3385 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3386 if (pipeline[plPtrRead].opcode == 38)
3387 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3388 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3389 #ifdef DSP_DEBUG_PL3
3390 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3391 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3392 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]);
3393 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]);
3395 // Stage 1b: Read registers
3396 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3397 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3398 // We have a hit in the scoreboard, so we have to stall the pipeline...
3399 #ifdef DSP_DEBUG_PL3
3401 WriteLog(" --> Stalling pipeline: ");
3402 if (readAffected[pipeline[plPtrRead].opcode][0])
3403 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3404 if (readAffected[pipeline[plPtrRead].opcode][1])
3405 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3408 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3409 #ifdef DSP_DEBUG_PL3
3414 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3415 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3416 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3418 // Shouldn't we be more selective with the register scoreboarding?
3419 // Yes, we should. !!! FIX !!! [Kinda DONE]
3420 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3422 //Advance PC here??? Yes.
3423 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3426 #ifdef DSP_DEBUG_PL3
3427 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3428 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]);
3429 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]);
3431 // Stage 2a: Execute
3432 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3434 #ifdef DSP_DEBUG_PL3
3435 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3437 DSPOpcode[pipeline[plPtrExec].opcode]();
3438 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3439 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3444 #ifdef DSP_DEBUG_PL3
3445 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3446 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]);
3447 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]);
3450 // Stage 2b: Write back register
3451 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3453 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3454 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3456 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3457 scoreboard[pipeline[plPtrExec].operand2] = false;
3460 // Push instructions through the pipeline...
3461 plPtrRead = (++plPtrRead) & 0x03;
3462 plPtrExec = (++plPtrExec) & 0x03;
3469 // DSP pipelined opcode handlers
3472 #define PRM pipeline[plPtrExec].reg1
3473 #define PRN pipeline[plPtrExec].reg2
3474 #define PIMM1 pipeline[plPtrExec].operand1
3475 #define PIMM2 pipeline[plPtrExec].operand2
3476 #define PRES pipeline[plPtrExec].result
3477 #define PWBR pipeline[plPtrExec].writebackRegister
3478 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3479 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3480 #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))
3481 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3483 static void DSP_abs(void)
3487 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);
3491 if (_Rn == 0x80000000)
3495 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3496 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3497 CLR_ZN; SET_Z(PRES);
3501 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3505 static void DSP_add(void)
3509 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);
3511 uint32 res = PRN + PRM;
3512 SET_ZNC_ADD(PRN, PRM, res);
3516 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);
3520 static void DSP_addc(void)
3524 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);
3526 uint32 res = PRN + PRM + dsp_flag_c;
3527 uint32 carry = dsp_flag_c;
3528 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3529 SET_ZNC_ADD(PRN + carry, PRM, res);
3530 // SET_ZNC_ADD(PRN, PRM + carry, res);
3534 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);
3538 static void DSP_addq(void)
3542 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);
3544 uint32 r1 = dsp_convert_zero[PIMM1];
3545 uint32 res = PRN + r1;
3546 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3550 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3554 static void DSP_addqmod(void)
3556 #ifdef DSP_DIS_ADDQMOD
3558 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);
3560 uint32 r1 = dsp_convert_zero[PIMM1];
3562 uint32 res = r2 + r1;
3563 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3565 SET_ZNC_ADD(r2, r1, res);
3566 #ifdef DSP_DIS_ADDQMOD
3568 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3572 static void DSP_addqt(void)
3574 #ifdef DSP_DIS_ADDQT
3576 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);
3578 PRES = PRN + dsp_convert_zero[PIMM1];
3579 #ifdef DSP_DIS_ADDQT
3581 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3585 static void DSP_and(void)
3589 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);
3595 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);
3599 static void DSP_bclr(void)
3603 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);
3605 PRES = PRN & ~(1 << PIMM1);
3609 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3613 static void DSP_bset(void)
3617 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);
3619 PRES = PRN | (1 << PIMM1);
3623 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3627 static void DSP_btst(void)
3631 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);
3633 dsp_flag_z = (~PRN >> PIMM1) & 1;
3637 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3641 static void DSP_cmp(void)
3645 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);
3647 uint32 res = PRN - PRM;
3648 SET_ZNC_SUB(PRN, PRM, res);
3652 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3656 static void DSP_cmpq(void)
3658 static int32 sqtable[32] =
3659 { 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 };
3662 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);
3664 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3665 uint32 res = PRN - r1;
3666 SET_ZNC_SUB(PRN, r1, res);
3670 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3674 static void DSP_div(void)
3676 uint32 _Rm = PRM, _Rn = PRN;
3680 if (dsp_div_control & 1)
3682 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3683 if (dsp_remain & 0x80000000)
3685 PRES = (((uint64)_Rn) << 16) / _Rm;
3689 dsp_remain = _Rn % _Rm;
3690 if (dsp_remain & 0x80000000)
3699 static void DSP_imacn(void)
3701 #ifdef DSP_DIS_IMACN
3703 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);
3705 int32 res = (int16)PRM * (int16)PRN;
3706 dsp_acc += (int64)res;
3707 //Should we AND the result to fit into 40 bits here???
3709 #ifdef DSP_DIS_IMACN
3711 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));
3715 static void DSP_imult(void)
3717 #ifdef DSP_DIS_IMULT
3719 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);
3721 PRES = (int16)PRN * (int16)PRM;
3723 #ifdef DSP_DIS_IMULT
3725 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);
3729 static void DSP_imultn(void)
3731 #ifdef DSP_DIS_IMULTN
3733 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);
3735 // This is OK, since this multiply won't overflow 32 bits...
3736 int32 res = (int32)((int16)PRN * (int16)PRM);
3737 dsp_acc = (int64)res;
3740 #ifdef DSP_DIS_IMULTN
3742 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));
3746 static void DSP_illegal(void)
3748 #ifdef DSP_DIS_ILLEGAL
3750 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3755 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3756 // can cause trouble because an interrupt can occur *before* the instruction following the
3757 // jump can execute... !!! FIX !!!
3758 // This can probably be solved by judicious coding in the pipeline execution core...
3759 // And should be fixed now...
3760 static void DSP_jr(void)
3763 const char * condition[32] =
3764 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3765 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3766 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3767 "???", "???", "???", "F" };
3769 //How come this is always off by 2???
3770 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);
3772 // KLUDGE: Used by BRANCH_CONDITION macro
3773 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3775 if (BRANCH_CONDITION(PIMM2))
3779 WriteLog("Branched!\n");
3781 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3782 //Account for pipeline effects...
3783 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3784 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3786 // Now that we've branched, we have to make sure that the following instruction
3787 // is executed atomically with this one and then flush the pipeline before setting
3790 // Step 1: Handle writebacks at stage 3 of pipeline
3791 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3793 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3794 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3796 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3797 scoreboard[pipeline[plPtrWrite].operand2] = false;
3799 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3801 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3803 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3804 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3807 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3808 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3809 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3810 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3812 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3816 #ifndef NEW_SCOREBOARD
3817 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3818 scoreboard[pipeline[plPtrWrite].operand2] = false;
3820 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3821 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3822 if (scoreboard[pipeline[plPtrWrite].operand2])
3823 scoreboard[pipeline[plPtrWrite].operand2]--;
3827 // Step 2: Push instruction through pipeline & execute following instruction
3828 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3829 // we effectively handle the final push of the instruction through the
3830 // pipeline when the new PC takes effect (since when we return, the
3831 // pipeline code will be executing the writeback stage. If we reverse
3832 // the execution order of the pipeline stages, this will no longer be
3834 pipeline[plPtrExec] = pipeline[plPtrRead];
3835 //This is BAD. We need to get that next opcode and execute it!
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");
3867 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3870 static void DSP_jump(void)
3873 const char * condition[32] =
3874 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3875 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3876 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3877 "???", "???", "???", "F" };
3879 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);
3881 // KLUDGE: Used by BRANCH_CONDITION macro
3882 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3884 if (BRANCH_CONDITION(PIMM2))
3888 WriteLog("Branched!\n");
3890 uint32 PCSave = PRM;
3891 // Now that we've branched, we have to make sure that the following instruction
3892 // is executed atomically with this one and then flush the pipeline before setting
3895 // Step 1: Handle writebacks at stage 3 of pipeline
3896 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3898 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3899 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3901 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3902 scoreboard[pipeline[plPtrWrite].operand2] = false;
3904 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3906 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3908 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3909 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3912 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3913 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3914 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3915 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3917 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3921 #ifndef NEW_SCOREBOARD
3922 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3923 scoreboard[pipeline[plPtrWrite].operand2] = false;
3925 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3926 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3927 if (scoreboard[pipeline[plPtrWrite].operand2])
3928 scoreboard[pipeline[plPtrWrite].operand2]--;
3932 // Step 2: Push instruction through pipeline & execute following instruction
3933 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3934 // we effectively handle the final push of the instruction through the
3935 // pipeline when the new PC takes effect (since when we return, the
3936 // pipeline code will be executing the writeback stage. If we reverse
3937 // the execution order of the pipeline stages, this will no longer be
3939 pipeline[plPtrExec] = pipeline[plPtrRead];
3940 //This is BAD. We need to get that next opcode and execute it!
3941 //Also, same problem in JR!
3942 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3943 // remove this crap.
3944 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3946 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3947 pipeline[plPtrExec].opcode = instruction >> 10;
3948 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3949 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3950 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3951 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3952 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3954 dsp_pc += 2; // For DSP_DIS_* accuracy
3955 DSPOpcode[pipeline[plPtrExec].opcode]();
3956 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3957 pipeline[plPtrWrite] = pipeline[plPtrExec];
3959 // Step 3: Flush pipeline & set new PC
3960 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3967 WriteLog("Branch NOT taken.\n");
3975 static void DSP_load(void)
3979 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);
3981 #ifdef DSP_CORRECT_ALIGNMENT
3982 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3984 PRES = DSPReadLong(PRM, DSP);
3988 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3992 static void DSP_loadb(void)
3994 #ifdef DSP_DIS_LOADB
3996 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);
3998 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3999 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4001 PRES = JaguarReadByte(PRM, DSP);
4002 #ifdef DSP_DIS_LOADB
4004 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4008 static void DSP_loadw(void)
4010 #ifdef DSP_DIS_LOADW
4012 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);
4014 #ifdef DSP_CORRECT_ALIGNMENT
4015 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4016 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4018 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4020 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4021 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4023 PRES = JaguarReadWord(PRM, DSP);
4025 #ifdef DSP_DIS_LOADW
4027 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4031 static void DSP_load_r14_i(void)
4033 #ifdef DSP_DIS_LOAD14I
4035 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);
4037 #ifdef DSP_CORRECT_ALIGNMENT
4038 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4040 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4042 #ifdef DSP_DIS_LOAD14I
4044 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4048 static void DSP_load_r14_r(void)
4050 #ifdef DSP_DIS_LOAD14R
4052 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);
4054 #ifdef DSP_CORRECT_ALIGNMENT
4055 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4057 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4059 #ifdef DSP_DIS_LOAD14R
4061 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4065 static void DSP_load_r15_i(void)
4067 #ifdef DSP_DIS_LOAD15I
4069 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);
4071 #ifdef DSP_CORRECT_ALIGNMENT
4072 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4074 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4076 #ifdef DSP_DIS_LOAD15I
4078 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4082 static void DSP_load_r15_r(void)
4084 #ifdef DSP_DIS_LOAD15R
4086 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);
4088 #ifdef DSP_CORRECT_ALIGNMENT
4089 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4091 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4093 #ifdef DSP_DIS_LOAD15R
4095 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4099 static void DSP_mirror(void)
4102 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4106 static void DSP_mmult(void)
4108 int count = dsp_matrix_control&0x0f;
4109 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4113 if (!(dsp_matrix_control & 0x10))
4115 for (int i = 0; i < count; i++)
4119 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4121 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4122 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4129 for (int i = 0; i < count; i++)
4133 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4135 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4136 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4142 PRES = res = (int32)accum;
4144 //NOTE: The flags are set based upon the last add/multiply done...
4148 static void DSP_move(void)
4152 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);
4157 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);
4161 static void DSP_movefa(void)
4163 #ifdef DSP_DIS_MOVEFA
4165 // 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);
4166 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);
4168 // PRES = ALTERNATE_RM;
4169 PRES = dsp_alternate_reg[PIMM1];
4170 #ifdef DSP_DIS_MOVEFA
4172 // 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);
4173 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);
4177 static void DSP_movei(void)
4179 #ifdef DSP_DIS_MOVEI
4181 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);
4183 // // This instruction is followed by 32-bit value in LSW / MSW format...
4184 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4186 #ifdef DSP_DIS_MOVEI
4188 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4192 static void DSP_movepc(void)
4194 #ifdef DSP_DIS_MOVEPC
4196 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);
4198 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4199 // PRES = dsp_pc - 2;
4200 //Account for pipeline effects...
4201 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4202 #ifdef DSP_DIS_MOVEPC
4204 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4208 static void DSP_moveq(void)
4210 #ifdef DSP_DIS_MOVEQ
4212 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);
4215 #ifdef DSP_DIS_MOVEQ
4217 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4221 static void DSP_moveta(void)
4223 #ifdef DSP_DIS_MOVETA
4225 // 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);
4226 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]);
4228 // ALTERNATE_RN = PRM;
4229 dsp_alternate_reg[PIMM2] = PRM;
4231 #ifdef DSP_DIS_MOVETA
4233 // 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);
4234 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]);
4238 static void DSP_mtoi(void)
4240 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4244 static void DSP_mult(void)
4248 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);
4250 PRES = (uint16)PRM * (uint16)PRN;
4254 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);
4258 static void DSP_neg(void)
4262 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);
4265 SET_ZNC_SUB(0, PRN, res);
4269 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4273 static void DSP_nop(void)
4277 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4282 static void DSP_normi(void)
4289 while ((_Rm & 0xffc00000) == 0)
4294 while ((_Rm & 0xff800000) != 0)
4304 static void DSP_not(void)
4308 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", DSP_PPC, PIMM2, dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4314 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4318 static void DSP_or(void)
4322 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);
4328 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);
4332 static void DSP_resmac(void)
4334 #ifdef DSP_DIS_RESMAC
4336 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));
4338 PRES = (uint32)dsp_acc;
4339 #ifdef DSP_DIS_RESMAC
4341 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4345 static void DSP_ror(void)
4349 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);
4351 uint32 r1 = PRM & 0x1F;
4352 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4353 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4357 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);
4361 static void DSP_rorq(void)
4365 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);
4367 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4369 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4371 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4374 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4378 static void DSP_sat16s(void)
4381 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4386 static void DSP_sat32s(void)
4388 int32 r2 = (uint32)PRN;
4389 int32 temp = dsp_acc >> 32;
4390 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4395 static void DSP_sh(void)
4397 int32 sRm = (int32)PRM;
4402 uint32 shift = -sRm;
4407 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4422 dsp_flag_c = _Rn & 0x1;
4435 static void DSP_sha(void)
4437 int32 sRm = (int32)PRM;
4442 uint32 shift = -sRm;
4447 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4462 dsp_flag_c = _Rn & 0x1;
4466 _Rn = ((int32)_Rn) >> 1;
4475 static void DSP_sharq(void)
4477 #ifdef DSP_DIS_SHARQ
4479 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);
4481 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4482 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4484 #ifdef DSP_DIS_SHARQ
4486 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4490 static void DSP_shlq(void)
4494 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);
4496 int32 r1 = 32 - PIMM1;
4497 uint32 res = PRN << r1;
4498 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4502 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4506 static void DSP_shrq(void)
4510 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);
4512 int32 r1 = dsp_convert_zero[PIMM1];
4513 uint32 res = PRN >> r1;
4514 SET_ZN(res); dsp_flag_c = PRN & 1;
4518 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4522 static void DSP_store(void)
4524 #ifdef DSP_DIS_STORE
4526 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);
4528 // DSPWriteLong(PRM, PRN, DSP);
4530 #ifdef DSP_CORRECT_ALIGNMENT
4531 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4533 pipeline[plPtrExec].address = PRM;
4535 pipeline[plPtrExec].value = PRN;
4536 pipeline[plPtrExec].type = TYPE_DWORD;
4540 static void DSP_storeb(void)
4542 #ifdef DSP_DIS_STOREB
4544 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);
4546 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4547 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4549 // JaguarWriteByte(PRM, PRN, DSP);
4552 pipeline[plPtrExec].address = PRM;
4554 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4556 pipeline[plPtrExec].value = PRN & 0xFF;
4557 pipeline[plPtrExec].type = TYPE_DWORD;
4561 pipeline[plPtrExec].value = PRN;
4562 pipeline[plPtrExec].type = TYPE_BYTE;
4568 static void DSP_storew(void)
4570 #ifdef DSP_DIS_STOREW
4572 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);
4574 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4575 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4577 // JaguarWriteWord(PRM, PRN, DSP);
4580 #ifdef DSP_CORRECT_ALIGNMENT
4581 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4583 pipeline[plPtrExec].address = PRM;
4586 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4588 pipeline[plPtrExec].value = PRN & 0xFFFF;
4589 pipeline[plPtrExec].type = TYPE_DWORD;
4593 pipeline[plPtrExec].value = PRN;
4594 pipeline[plPtrExec].type = TYPE_WORD;
4599 static void DSP_store_r14_i(void)
4601 #ifdef DSP_DIS_STORE14I
4603 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));
4605 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4607 #ifdef DSP_CORRECT_ALIGNMENT
4608 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4610 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4612 pipeline[plPtrExec].value = PRN;
4613 pipeline[plPtrExec].type = TYPE_DWORD;
4617 static void DSP_store_r14_r(void)
4619 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4621 #ifdef DSP_CORRECT_ALIGNMENT
4622 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4624 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4626 pipeline[plPtrExec].value = PRN;
4627 pipeline[plPtrExec].type = TYPE_DWORD;
4631 static void DSP_store_r15_i(void)
4633 #ifdef DSP_DIS_STORE15I
4635 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));
4637 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4639 #ifdef DSP_CORRECT_ALIGNMENT
4640 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4642 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4644 pipeline[plPtrExec].value = PRN;
4645 pipeline[plPtrExec].type = TYPE_DWORD;
4649 static void DSP_store_r15_r(void)
4651 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4653 #ifdef DSP_CORRECT_ALIGNMENT
4654 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4656 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4658 pipeline[plPtrExec].value = PRN;
4659 pipeline[plPtrExec].type = TYPE_DWORD;
4663 static void DSP_sub(void)
4667 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);
4669 uint32 res = PRN - PRM;
4670 SET_ZNC_SUB(PRN, PRM, res);
4674 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);
4678 static void DSP_subc(void)
4682 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);
4684 uint32 res = PRN - PRM - dsp_flag_c;
4685 uint32 borrow = dsp_flag_c;
4686 SET_ZNC_SUB(PRN - borrow, PRM, res);
4690 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);
4694 static void DSP_subq(void)
4698 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);
4700 uint32 r1 = dsp_convert_zero[PIMM1];
4701 uint32 res = PRN - r1;
4702 SET_ZNC_SUB(PRN, r1, res);
4706 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4710 static void DSP_subqmod(void)
4712 uint32 r1 = dsp_convert_zero[PIMM1];
4714 uint32 res = r2 - r1;
4715 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4717 SET_ZNC_SUB(r2, r1, res);
4720 static void DSP_subqt(void)
4722 #ifdef DSP_DIS_SUBQT
4724 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);
4726 PRES = PRN - dsp_convert_zero[PIMM1];
4727 #ifdef DSP_DIS_SUBQT
4729 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4733 static void DSP_xor(void)
4737 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);
4743 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);