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
32 //#define DSP_CORRECT_ALIGNMENT_STORE
35 //#define DSP_DEBUG_IRQ
36 //#define DSP_DEBUG_PL2
37 //#define DSP_DEBUG_STALL
38 //#define DSP_DEBUG_CC
39 #define NEW_SCOREBOARD
41 // Disassembly definitions
48 #define DSP_DIS_ADDQMOD
58 #define DSP_DIS_IMULTN
59 #define DSP_DIS_ILLEGAL
63 #define DSP_DIS_LOAD14I
64 #define DSP_DIS_LOAD14R
65 #define DSP_DIS_LOAD15I
66 #define DSP_DIS_LOAD15R
72 #define DSP_DIS_MOVEFA
73 #define DSP_DIS_MOVEPC // Pipeline only!
74 #define DSP_DIS_MOVETA
80 #define DSP_DIS_RESMAC
87 #define DSP_DIS_STORE14I
88 #define DSP_DIS_STORE15I
89 #define DSP_DIS_STOREB
90 #define DSP_DIS_STOREW
97 bool doDSPDis = false;
98 //bool doDSPDis = true;
133 + load_r15_indexed 284500
135 + store_r15_indexed 47416
139 + load_r14_ri 1229448
142 // Pipeline structures
144 const bool affectsScoreboard[64] =
146 true, true, true, true,
147 true, true, true, true,
148 true, true, true, true,
149 true, false, true, true,
151 true, true, false, true,
152 false, true, true, true,
153 true, true, true, true,
154 true, true, false, false,
156 true, true, true, true,
157 false, true, true, true,
158 true, true, true, true,
159 true, false, false, false,
161 true, false, false, true,
162 false, false, true, true,
163 true, false, true, true,
164 false, false, false, true
170 uint8 opcode, operand1, operand2;
171 uint32 reg1, reg2, areg1, areg2;
173 uint8 writebackRegister;
174 // General memory store...
183 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
184 #ifndef NEW_SCOREBOARD
187 uint8 scoreboard[32];
189 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
190 PipelineStage pipeline[4];
191 bool IMASKCleared = false;
193 // DSP flags (old--have to get rid of this crap)
195 #define CINT0FLAG 0x00200
196 #define CINT1FLAG 0x00400
197 #define CINT2FLAG 0x00800
198 #define CINT3FLAG 0x01000
199 #define CINT4FLAG 0x02000
200 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
201 #define CINT5FLAG 0x20000 /* DSP only */
205 #define ZERO_FLAG 0x00001
206 #define CARRY_FLAG 0x00002
207 #define NEGA_FLAG 0x00004
208 #define IMASK 0x00008
209 #define INT_ENA0 0x00010
210 #define INT_ENA1 0x00020
211 #define INT_ENA2 0x00040
212 #define INT_ENA3 0x00080
213 #define INT_ENA4 0x00100
214 #define INT_CLR0 0x00200
215 #define INT_CLR1 0x00400
216 #define INT_CLR2 0x00800
217 #define INT_CLR3 0x01000
218 #define INT_CLR4 0x02000
219 #define REGPAGE 0x04000
220 #define DMAEN 0x08000
221 #define INT_ENA5 0x10000
222 #define INT_CLR5 0x20000
226 #define DSPGO 0x00001
227 #define CPUINT 0x00002
228 #define DSPINT0 0x00004
229 #define SINGLE_STEP 0x00008
230 #define SINGLE_GO 0x00010
232 #define INT_LAT0 0x00040
233 #define INT_LAT1 0x00080
234 #define INT_LAT2 0x00100
235 #define INT_LAT3 0x00200
236 #define INT_LAT4 0x00400
237 #define BUS_HOG 0x00800
238 #define VERSION 0x0F000
239 #define INT_LAT5 0x10000
241 extern uint32 jaguar_mainRom_crc32;
243 // Is opcode 62 *really* a NOP? Seems like it...
244 static void dsp_opcode_abs(void);
245 static void dsp_opcode_add(void);
246 static void dsp_opcode_addc(void);
247 static void dsp_opcode_addq(void);
248 static void dsp_opcode_addqmod(void);
249 static void dsp_opcode_addqt(void);
250 static void dsp_opcode_and(void);
251 static void dsp_opcode_bclr(void);
252 static void dsp_opcode_bset(void);
253 static void dsp_opcode_btst(void);
254 static void dsp_opcode_cmp(void);
255 static void dsp_opcode_cmpq(void);
256 static void dsp_opcode_div(void);
257 static void dsp_opcode_imacn(void);
258 static void dsp_opcode_imult(void);
259 static void dsp_opcode_imultn(void);
260 static void dsp_opcode_jr(void);
261 static void dsp_opcode_jump(void);
262 static void dsp_opcode_load(void);
263 static void dsp_opcode_loadb(void);
264 static void dsp_opcode_loadw(void);
265 static void dsp_opcode_load_r14_indexed(void);
266 static void dsp_opcode_load_r14_ri(void);
267 static void dsp_opcode_load_r15_indexed(void);
268 static void dsp_opcode_load_r15_ri(void);
269 static void dsp_opcode_mirror(void);
270 static void dsp_opcode_mmult(void);
271 static void dsp_opcode_move(void);
272 static void dsp_opcode_movei(void);
273 static void dsp_opcode_movefa(void);
274 static void dsp_opcode_move_pc(void);
275 static void dsp_opcode_moveq(void);
276 static void dsp_opcode_moveta(void);
277 static void dsp_opcode_mtoi(void);
278 static void dsp_opcode_mult(void);
279 static void dsp_opcode_neg(void);
280 static void dsp_opcode_nop(void);
281 static void dsp_opcode_normi(void);
282 static void dsp_opcode_not(void);
283 static void dsp_opcode_or(void);
284 static void dsp_opcode_resmac(void);
285 static void dsp_opcode_ror(void);
286 static void dsp_opcode_rorq(void);
287 static void dsp_opcode_xor(void);
288 static void dsp_opcode_sat16s(void);
289 static void dsp_opcode_sat32s(void);
290 static void dsp_opcode_sh(void);
291 static void dsp_opcode_sha(void);
292 static void dsp_opcode_sharq(void);
293 static void dsp_opcode_shlq(void);
294 static void dsp_opcode_shrq(void);
295 static void dsp_opcode_store(void);
296 static void dsp_opcode_storeb(void);
297 static void dsp_opcode_storew(void);
298 static void dsp_opcode_store_r14_indexed(void);
299 static void dsp_opcode_store_r14_ri(void);
300 static void dsp_opcode_store_r15_indexed(void);
301 static void dsp_opcode_store_r15_ri(void);
302 static void dsp_opcode_sub(void);
303 static void dsp_opcode_subc(void);
304 static void dsp_opcode_subq(void);
305 static void dsp_opcode_subqmod(void);
306 static void dsp_opcode_subqt(void);
308 uint8 dsp_opcode_cycles[64] =
310 3, 3, 3, 3, 3, 3, 3, 3,
311 3, 3, 3, 3, 3, 3, 3, 3,
312 3, 3, 1, 3, 1, 18, 3, 3,
313 3, 3, 3, 3, 3, 3, 3, 3,
314 3, 3, 2, 2, 2, 2, 3, 4,
315 5, 4, 5, 6, 6, 1, 1, 1,
316 1, 2, 2, 2, 1, 1, 9, 3,
317 3, 1, 6, 6, 2, 2, 3, 3
319 //Here's a QnD kludge...
320 //This is wrong, wrong, WRONG, but it seems to work for the time being...
321 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
322 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
323 /*uint8 dsp_opcode_cycles[64] =
325 1, 1, 1, 1, 1, 1, 1, 1,
326 1, 1, 1, 1, 1, 1, 1, 1,
327 1, 1, 1, 1, 1, 9, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 1,
329 1, 1, 1, 1, 1, 1, 1, 2,
330 2, 2, 2, 3, 3, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 4, 1,
332 1, 1, 3, 3, 1, 1, 1, 1
335 void (* dsp_opcode[64])() =
337 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
338 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
339 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
340 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
341 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
342 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
343 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
344 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
345 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
346 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
347 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
348 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
349 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
350 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
351 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
352 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
355 uint32 dsp_opcode_use[65];
357 const char * dsp_opcode_str[65]=
359 "add", "addc", "addq", "addqt",
360 "sub", "subc", "subq", "subqt",
361 "neg", "and", "or", "xor",
362 "not", "btst", "bset", "bclr",
363 "mult", "imult", "imultn", "resmac",
364 "imacn", "div", "abs", "sh",
365 "shlq", "shrq", "sha", "sharq",
366 "ror", "rorq", "cmp", "cmpq",
367 "subqmod", "sat16s", "move", "moveq",
368 "moveta", "movefa", "movei", "loadb",
369 "loadw", "load", "sat32s", "load_r14_indexed",
370 "load_r15_indexed", "storeb", "storew", "store",
371 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
372 "jump", "jr", "mmult", "mtoi",
373 "normi", "nop", "load_r14_ri", "load_r15_ri",
374 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
379 static uint64 dsp_acc; // 40 bit register, NOT 32!
380 static uint32 dsp_remain;
381 static uint32 dsp_modulo;
382 static uint32 dsp_flags;
383 static uint32 dsp_matrix_control;
384 static uint32 dsp_pointer_to_matrix;
385 static uint32 dsp_data_organization;
387 static uint32 dsp_div_control;
388 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
389 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
390 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
392 static uint32 dsp_opcode_first_parameter;
393 static uint32 dsp_opcode_second_parameter;
395 #define DSP_RUNNING (dsp_control & 0x01)
397 #define RM dsp_reg[dsp_opcode_first_parameter]
398 #define RN dsp_reg[dsp_opcode_second_parameter]
399 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
400 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
401 #define IMM_1 dsp_opcode_first_parameter
402 #define IMM_2 dsp_opcode_second_parameter
404 #define CLR_Z (dsp_flag_z = 0)
405 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
406 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
407 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
408 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
409 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
410 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
411 #define SET_ZN(r) SET_N(r); SET_Z(r)
412 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
413 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
415 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 };
416 uint8 * dsp_branch_condition_table = NULL;
417 static uint16 * mirror_table = NULL;
418 static uint8 dsp_ram_8[0x2000];
420 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
422 static uint32 dsp_in_exec = 0;
423 static uint32 dsp_releaseTimeSlice_flag = 0;
428 // Comparison core vars (used only for core comparison! :-)
429 static uint64 count = 0;
430 static uint8 ram1[0x2000], ram2[0x2000];
431 static uint32 regs1[64], regs2[64];
432 static uint32 ctrl1[14], ctrl2[14];
435 // Private function prototypes
437 void DSPDumpRegisters(void);
438 void DSPDumpDisassembly(void);
439 void FlushDSPPipeline(void);
442 void dsp_reset_stats(void)
444 for(int i=0; i<65; i++)
445 dsp_opcode_use[i] = 0;
448 void DSPReleaseTimeslice(void)
450 //This does absolutely nothing!!! !!! FIX !!!
451 dsp_releaseTimeSlice_flag = 1;
454 void dsp_build_branch_condition_table(void)
456 // Allocate the mirror table
458 mirror_table = (uint16 *)malloc(65536 * sizeof(uint16));
460 // Fill in the mirror table
462 for(int i=0; i<65536; i++)
463 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
464 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
465 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
466 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
467 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
468 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
469 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
470 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
472 if (!dsp_branch_condition_table)
474 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8));
476 // Fill in the condition table
477 if (dsp_branch_condition_table)
479 for(int i=0; i<8; i++)
481 for(int j=0; j<32; j++)
488 if (!(i & ZERO_FLAG))
491 if (i & (CARRY_FLAG << (j >> 4)))
494 if (!(i & (CARRY_FLAG << (j >> 4))))
496 dsp_branch_condition_table[i * 32 + j] = result;
503 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
505 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
506 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
508 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
511 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
513 if (offset==0xF1CFE0)
516 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
517 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
519 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
521 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
523 if ((offset&0x03)==0)
526 if ((offset&0x03)==1)
527 return((data>>16)&0xff);
529 if ((offset&0x03)==2)
530 return((data>>8)&0xff);
532 if ((offset&0x03)==3)
536 return JaguarReadByte(offset, who);
539 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
541 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
542 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
544 offset &= 0xFFFFFFFE;
546 /* if (jaguar_mainRom_crc32==0xa74a97cd)
548 if (offset==0xF1A114) return(0x0000);
549 if (offset==0xF1A116) return(0x0000);
550 if (offset==0xF1B000) return(0x1234);
551 if (offset==0xF1B002) return(0x5678);
554 if (jaguar_mainRom_crc32==0x7ae20823)
556 if (offset==0xF1B9D8) return(0x0000);
557 if (offset==0xF1B9Da) return(0x0000);
558 if (offset==0xF1B2C0) return(0x0000);
559 if (offset==0xF1B2C2) return(0x0000);
562 // pour permettre � wolfenstein 3d de tourner sans le dsp
563 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
567 // pour permettre � nba jam de tourner sans le dsp
568 /* if (jaguar_mainRom_crc32==0x4faddb18)
570 if (offset==0xf1b2c0) return(0);
571 if (offset==0xf1b2c2) return(0);
572 if (offset==0xf1b240) return(0);
573 if (offset==0xf1b242) return(0);
574 if (offset==0xF1B340) return(0);
575 if (offset==0xF1B342) return(0);
576 if (offset==0xF1BAD8) return(0);
577 if (offset==0xF1BADA) return(0);
578 if (offset==0xF1B040) return(0);
579 if (offset==0xF1B042) return(0);
580 if (offset==0xF1B0C0) return(0);
581 if (offset==0xF1B0C2) return(0);
582 if (offset==0xF1B140) return(0);
583 if (offset==0xF1B142) return(0);
584 if (offset==0xF1B1C0) return(0);
585 if (offset==0xF1B1C2) return(0);
588 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
590 offset -= DSP_WORK_RAM_BASE;
591 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
593 return GET16(dsp_ram_8, offset);
595 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
597 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
600 return data & 0xFFFF;
605 return JaguarReadWord(offset, who);
608 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
610 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
611 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
614 offset &= 0xFFFFFFFC;
615 /*if (offset == 0xF1BCF4)
617 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));
618 DSPDumpDisassembly();
620 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
622 offset -= DSP_WORK_RAM_BASE;
623 return GET32(dsp_ram_8, offset);
625 //NOTE: Didn't return DSP_ACCUM!!!
626 //Mebbe it's not 'spose to! Yes, it is!
627 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
632 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
633 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
634 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
636 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
637 return dsp_flags & 0xFFFFC1FF;
638 case 0x04: return dsp_matrix_control;
639 case 0x08: return dsp_pointer_to_matrix;
640 case 0x0C: return dsp_data_organization;
641 case 0x10: return dsp_pc;
642 case 0x14: return dsp_control;
643 case 0x18: return dsp_modulo;
644 case 0x1C: return dsp_remain;
646 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
648 // unaligned long read-- !!! FIX !!!
652 return JaguarReadLong(offset, who);
655 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
657 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
658 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
660 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
662 offset -= DSP_WORK_RAM_BASE;
663 dsp_ram_8[offset] = data;
664 //This is rather stupid! !!! FIX !!!
665 /* if (dsp_in_exec == 0)
667 m68k_end_timeslice();
668 dsp_releaseTimeslice();
672 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
674 uint32 reg = offset & 0x1C;
675 int bytenum = offset & 0x03;
677 if ((reg >= 0x1C) && (reg <= 0x1F))
678 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
681 //This looks funky. !!! FIX !!!
682 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
683 bytenum = 3 - bytenum; // convention motorola !!!
684 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
685 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
689 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
690 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
691 JaguarWriteByte(offset, data, who);
694 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
696 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
697 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
698 offset &= 0xFFFFFFFE;
699 /*if (offset == 0xF1BCF4)
701 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
703 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
704 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
706 /*if (offset == 0xF1B2F4)
708 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
710 offset -= DSP_WORK_RAM_BASE;
711 dsp_ram_8[offset] = data >> 8;
712 dsp_ram_8[offset+1] = data & 0xFF;
713 //This is rather stupid! !!! FIX !!!
714 /* if (dsp_in_exec == 0)
716 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
717 m68k_end_timeslice();
718 dsp_releaseTimeslice();
722 SET16(ram1, offset, data),
723 SET16(ram2, offset, data);
728 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
730 if ((offset & 0x1C) == 0x1C)
733 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
735 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
739 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
741 old_data = (old_data&0xffff0000)|(data&0xffff);
743 old_data = (old_data&0xffff)|((data&0xffff)<<16);
744 DSPWriteLong(offset & 0xffffffc, old_data, who);
749 JaguarWriteWord(offset, data, who);
752 //bool badWrite = false;
753 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
755 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
756 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
758 offset &= 0xFFFFFFFC;
759 /*if (offset == 0xF1BCF4)
761 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
763 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
764 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
766 /*if (offset == 0xF1BE2C)
768 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
770 offset -= DSP_WORK_RAM_BASE;
771 SET32(dsp_ram_8, offset, data);
774 SET32(ram1, offset, data),
775 SET32(ram2, offset, data);
780 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
788 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
790 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
791 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
793 dsp_flag_z = dsp_flags & 0x01;
794 dsp_flag_c = (dsp_flags >> 1) & 0x01;
795 dsp_flag_n = (dsp_flags >> 2) & 0x01;
796 DSPUpdateRegisterBanks();
797 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
798 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
799 /* if (IMASKCleared) // If IMASK was cleared,
802 WriteLog("DSP: Finished interrupt.\n");
804 DSPHandleIRQs(); // see if any other interrupts need servicing!
809 if (/*4-8, 16*/data & 0x101F0)
810 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
811 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
812 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
813 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
814 /*if (data & 0x00020) // CD BIOS DSP code...
816 //001AC1BA: movea.l #$1AC200, A0
817 //001AC1C0: move.l #$1AC68C, D0
820 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
821 uint32 j = 0xF1B97C;//0x1AC200;
822 while (j <= 0xF1BE08)//0x1AC68C)
825 j += dasmjag(JAGUAR_DSP, buffer, j);
826 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
827 WriteLog("\t%08X: %s\n", oldj, buffer);
834 dsp_matrix_control = data;
837 // According to JTRM, only lines 2-11 are addressable, the rest being
838 // hardwired to $F1Bxxx.
839 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
842 dsp_data_organization = data;
847 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
852 ctrl1[0] = ctrl2[0] = data;
859 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
861 bool wasRunning = DSP_RUNNING;
862 // uint32 dsp_was_running = DSP_RUNNING;
863 // Check for DSP -> CPU interrupt
867 WriteLog("DSP: DSP -> CPU interrupt\n");
870 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
871 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
872 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
874 JERRYSetPendingIRQ(IRQ2_DSP);
875 DSPReleaseTimeslice();
876 m68k_set_irq(2); // Set 68000 IPL 2...
880 // Check for CPU -> DSP interrupt
884 WriteLog("DSP: CPU -> DSP interrupt\n");
886 m68k_end_timeslice();
887 DSPReleaseTimeslice();
888 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
892 if (data & SINGLE_STEP)
894 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
897 // Protect writes to VERSION and the interrupt latches...
898 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
899 dsp_control = (dsp_control & mask) | (data & ~mask);
903 ctrl1[8] = ctrl2[8] = dsp_control;
907 // if dsp wasn't running but is now running
908 // execute a few cycles
909 //This is just plain wrong, wrong, WRONG!
910 #ifndef DSP_SINGLE_STEPPING
911 /* if (!dsp_was_running && DSP_RUNNING)
916 //This is WRONG! !!! FIX !!!
917 if (dsp_control & 0x18)
922 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
924 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
927 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
928 // !!! FIX !!! [DONE]
932 m68k_end_timeslice();
934 DSPReleaseTimeslice();
938 //DSPDumpDisassembly();
946 dsp_div_control = data;
948 // default: // unaligned long read
954 //We don't have to break this up like this! We CAN do 32 bit writes!
955 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
956 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
957 //if (offset > 0xF1FFFF)
959 JaguarWriteLong(offset, data, who);
963 // Update the DSP register file pointers depending on REGPAGE bit
965 void DSPUpdateRegisterBanks(void)
967 int bank = (dsp_flags & REGPAGE);
969 if (dsp_flags & IMASK)
970 bank = 0; // IMASK forces main bank to be bank 0
973 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
975 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
979 // Check for and handle any asserted DSP IRQs
981 void DSPHandleIRQs(void)
983 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
986 // Get the active interrupt bits (latches) & interrupt mask (enables)
987 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
988 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
990 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
993 if (!bits) // Bail if nothing is enabled
996 int which = 0; // Determine which interrupt
1010 #ifdef DSP_DEBUG_IRQ
1011 WriteLog("DSP: Generating interrupt #%i...", which);
1014 //if (which == 0) doDSPDis = true;
1016 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1017 // directly into the pipeline, it has the side effect of ensuring that the
1018 // instruction interrupted also gets to do its writeback. We simulate that
1020 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1022 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1023 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1025 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1026 scoreboard[pipeline[plPtrWrite].operand2] = false;
1028 //This should be execute (or should it?--not sure now!)
1029 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1030 //and what just executed is now in the Write position...). So why didn't it do the
1031 //writeback into register 0?
1032 #ifdef DSP_DEBUG_IRQ
1033 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1034 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]);
1035 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]);
1036 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]);
1038 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1040 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1042 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1043 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1046 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1047 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1048 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1049 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1051 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1055 #ifndef NEW_SCOREBOARD
1056 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1057 scoreboard[pipeline[plPtrWrite].operand2] = false;
1059 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1060 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1061 if (scoreboard[pipeline[plPtrWrite].operand2])
1062 scoreboard[pipeline[plPtrWrite].operand2]--;
1069 ctrl2[4] = dsp_flags;
1072 DSPUpdateRegisterBanks();
1073 #ifdef DSP_DEBUG_IRQ
1074 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1075 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]);
1078 // subqt #4,r31 ; pre-decrement stack pointer
1079 // move pc,r30 ; address of interrupted code
1080 // store r30,(r31) ; store return address
1087 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1088 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1089 //It missed the place that it was supposed to come back to, so this is WRONG!
1091 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1093 // R -> baz (<- PC points here)
1094 // E -> bar (when it should point here!)
1097 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1098 // which means (assuming they're all 2 bytes long) that the code below will come back on
1099 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1100 // instruction stream...
1102 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1103 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1106 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1110 // movei #service_address,r30 ; pointer to ISR entry
1111 // jump (r30) ; jump to ISR
1113 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1116 ctrl2[0] = regs2[30] = dsp_pc;
1123 // Non-pipelined version...
1125 void DSPHandleIRQsNP(void)
1129 memcpy(dsp_ram_8, ram1, 0x2000);
1130 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1131 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1134 dsp_remain = ctrl1[2];
1135 dsp_modulo = ctrl1[3];
1136 dsp_flags = ctrl1[4];
1137 dsp_matrix_control = ctrl1[5];
1138 dsp_pointer_to_matrix = ctrl1[6];
1139 dsp_data_organization = ctrl1[7];
1140 dsp_control = ctrl1[8];
1141 dsp_div_control = ctrl1[9];
1142 IMASKCleared = ctrl1[10];
1143 dsp_flag_z = ctrl1[11];
1144 dsp_flag_n = ctrl1[12];
1145 dsp_flag_c = ctrl1[13];
1146 DSPUpdateRegisterBanks();
1149 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1152 // Get the active interrupt bits (latches) & interrupt mask (enables)
1153 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1154 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1156 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1159 if (!bits) // Bail if nothing is enabled
1162 int which = 0; // Determine which interrupt
1176 #ifdef DSP_DEBUG_IRQ
1177 WriteLog("DSP: Generating interrupt #%i...", which);
1183 ctrl1[4] = dsp_flags;
1186 DSPUpdateRegisterBanks();
1187 #ifdef DSP_DEBUG_IRQ
1188 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1191 // subqt #4,r31 ; pre-decrement stack pointer
1192 // move pc,r30 ; address of interrupted code
1193 // store r30,(r31) ; store return address
1200 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1203 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1207 // movei #service_address,r30 ; pointer to ISR entry
1208 // jump (r30) ; jump to ISR
1210 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1213 ctrl1[0] = regs1[30] = dsp_pc;
1219 // Set the specified DSP IRQ line to a given state
1221 void DSPSetIRQLine(int irqline, int state)
1223 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1224 uint32 mask = INT_LAT0 << irqline;
1225 dsp_control &= ~mask; // Clear the latch bit
1228 ctrl1[8] = ctrl2[8] = dsp_control;
1234 dsp_control |= mask; // Set the latch bit
1238 ctrl1[8] = ctrl2[8] = dsp_control;
1244 // Not sure if this is correct behavior, but according to JTRM,
1245 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1246 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1247 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1252 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1253 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1254 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1256 dsp_build_branch_condition_table();
1262 dsp_pc = 0x00F1B000;
1263 dsp_acc = 0x00000000;
1264 dsp_remain = 0x00000000;
1265 dsp_modulo = 0xFFFFFFFF;
1266 dsp_flags = 0x00040000;
1267 dsp_matrix_control = 0x00000000;
1268 dsp_pointer_to_matrix = 0x00000000;
1269 dsp_data_organization = 0xFFFFFFFF;
1270 dsp_control = 0x00002000; // Report DSP version 2
1271 dsp_div_control = 0x00000000;
1274 dsp_reg = dsp_reg_bank_0;
1275 dsp_alternate_reg = dsp_reg_bank_1;
1277 for(int i=0; i<32; i++)
1278 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1281 IMASKCleared = false;
1284 memset(dsp_ram_8, 0xFF, 0x2000);
1287 void DSPDumpDisassembly(void)
1291 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1292 uint32 j = 0xF1B000;
1293 while (j <= 0xF1CFFF)
1296 j += dasmjag(JAGUAR_DSP, buffer, j);
1297 WriteLog("\t%08X: %s\n", oldj, buffer);
1301 void DSPDumpRegisters(void)
1303 //Shoud add modulus, etc to dump here...
1304 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1305 WriteLog("\nRegisters bank 0\n");
1306 for(int j=0; j<8; j++)
1308 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1309 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1310 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1311 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1312 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1314 WriteLog("Registers bank 1\n");
1315 for(int j=0; j<8; j++)
1317 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1318 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1319 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1320 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1321 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1328 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1329 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1331 // get the active interrupt bits
1332 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1333 // get the interrupt mask
1334 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1336 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1337 WriteLog("\nRegisters bank 0\n");
1338 for(int j=0; j<8; j++)
1340 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1341 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1342 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1343 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1344 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1346 WriteLog("\nRegisters bank 1\n");
1349 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1350 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1351 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1352 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1353 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1357 static char buffer[512];
1358 j = DSP_WORK_RAM_BASE;
1359 while (j <= 0xF1BFFF)
1362 j += dasmjag(JAGUAR_DSP, buffer, j);
1363 WriteLog("\t%08X: %s\n", oldj, buffer);
1366 WriteLog("DSP opcodes use:\n");
1369 if (dsp_opcode_use[i])
1370 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1373 // memory_free(dsp_ram_8);
1374 // memory_free(dsp_reg_bank_0);
1375 // memory_free(dsp_reg_bank_1);
1376 if (dsp_branch_condition_table)
1377 free(dsp_branch_condition_table);
1386 // DSP comparison core...
1389 static uint16 lastExec;
1390 void DSPExecComp(int32 cycles)
1392 while (cycles > 0 && DSP_RUNNING)
1394 // Load up vars for non-pipelined core
1395 memcpy(dsp_ram_8, ram1, 0x2000);
1396 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1397 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1400 dsp_remain = ctrl1[2];
1401 dsp_modulo = ctrl1[3];
1402 dsp_flags = ctrl1[4];
1403 dsp_matrix_control = ctrl1[5];
1404 dsp_pointer_to_matrix = ctrl1[6];
1405 dsp_data_organization = ctrl1[7];
1406 dsp_control = ctrl1[8];
1407 dsp_div_control = ctrl1[9];
1408 IMASKCleared = ctrl1[10];
1409 dsp_flag_z = ctrl1[11];
1410 dsp_flag_n = ctrl1[12];
1411 dsp_flag_c = ctrl1[13];
1412 DSPUpdateRegisterBanks();
1414 // Decrement cycles based on non-pipelined core...
1415 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1416 cycles -= dsp_opcode_cycles[instr1 >> 10];
1418 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1419 DSPExec(1); // Do *one* instruction
1422 memcpy(ram1, dsp_ram_8, 0x2000);
1423 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1424 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1427 ctrl1[2] = dsp_remain;
1428 ctrl1[3] = dsp_modulo;
1429 ctrl1[4] = dsp_flags;
1430 ctrl1[5] = dsp_matrix_control;
1431 ctrl1[6] = dsp_pointer_to_matrix;
1432 ctrl1[7] = dsp_data_organization;
1433 ctrl1[8] = dsp_control;
1434 ctrl1[9] = dsp_div_control;
1435 ctrl1[10] = IMASKCleared;
1436 ctrl1[11] = dsp_flag_z;
1437 ctrl1[12] = dsp_flag_n;
1438 ctrl1[13] = dsp_flag_c;
1440 // Load up vars for pipelined core
1441 memcpy(dsp_ram_8, ram2, 0x2000);
1442 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1443 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1446 dsp_remain = ctrl2[2];
1447 dsp_modulo = ctrl2[3];
1448 dsp_flags = ctrl2[4];
1449 dsp_matrix_control = ctrl2[5];
1450 dsp_pointer_to_matrix = ctrl2[6];
1451 dsp_data_organization = ctrl2[7];
1452 dsp_control = ctrl2[8];
1453 dsp_div_control = ctrl2[9];
1454 IMASKCleared = ctrl2[10];
1455 dsp_flag_z = ctrl2[11];
1456 dsp_flag_n = ctrl2[12];
1457 dsp_flag_c = ctrl2[13];
1458 DSPUpdateRegisterBanks();
1460 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1461 DSPExecP2(1); // Do *one* instruction
1464 memcpy(ram2, dsp_ram_8, 0x2000);
1465 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1466 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1469 ctrl2[2] = dsp_remain;
1470 ctrl2[3] = dsp_modulo;
1471 ctrl2[4] = dsp_flags;
1472 ctrl2[5] = dsp_matrix_control;
1473 ctrl2[6] = dsp_pointer_to_matrix;
1474 ctrl2[7] = dsp_data_organization;
1475 ctrl2[8] = dsp_control;
1476 ctrl2[9] = dsp_div_control;
1477 ctrl2[10] = IMASKCleared;
1478 ctrl2[11] = dsp_flag_z;
1479 ctrl2[12] = dsp_flag_n;
1480 ctrl2[13] = dsp_flag_c;
1482 if (instr1 != lastExec)
1484 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1486 // 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));
1487 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1488 // if (ctrl1[0] < ppc) // P ran ahead of NP
1489 //How to test this crap???
1492 DSPExecP2(1); // Do one more instruction
1495 memcpy(ram2, dsp_ram_8, 0x2000);
1496 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1497 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1500 ctrl2[2] = dsp_remain;
1501 ctrl2[3] = dsp_modulo;
1502 ctrl2[4] = dsp_flags;
1503 ctrl2[5] = dsp_matrix_control;
1504 ctrl2[6] = dsp_pointer_to_matrix;
1505 ctrl2[7] = dsp_data_organization;
1506 ctrl2[8] = dsp_control;
1507 ctrl2[9] = dsp_div_control;
1508 ctrl2[10] = IMASKCleared;
1509 ctrl2[11] = dsp_flag_z;
1510 ctrl2[12] = dsp_flag_n;
1511 ctrl2[13] = dsp_flag_c;
1513 // else // NP ran ahead of P
1514 if (instr1 != lastExec) // Must be the other way...
1517 // Load up vars for non-pipelined core
1518 memcpy(dsp_ram_8, ram1, 0x2000);
1519 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1520 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1523 dsp_remain = ctrl1[2];
1524 dsp_modulo = ctrl1[3];
1525 dsp_flags = ctrl1[4];
1526 dsp_matrix_control = ctrl1[5];
1527 dsp_pointer_to_matrix = ctrl1[6];
1528 dsp_data_organization = ctrl1[7];
1529 dsp_control = ctrl1[8];
1530 dsp_div_control = ctrl1[9];
1531 IMASKCleared = ctrl1[10];
1532 dsp_flag_z = ctrl1[11];
1533 dsp_flag_n = ctrl1[12];
1534 dsp_flag_c = ctrl1[13];
1535 DSPUpdateRegisterBanks();
1537 for(int k=0; k<2; k++)
1539 // Decrement cycles based on non-pipelined core...
1540 instr1 = DSPReadWord(dsp_pc, DSP);
1541 cycles -= dsp_opcode_cycles[instr1 >> 10];
1543 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1544 DSPExec(1); // Do *one* instruction
1548 memcpy(ram1, dsp_ram_8, 0x2000);
1549 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1550 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1553 ctrl1[2] = dsp_remain;
1554 ctrl1[3] = dsp_modulo;
1555 ctrl1[4] = dsp_flags;
1556 ctrl1[5] = dsp_matrix_control;
1557 ctrl1[6] = dsp_pointer_to_matrix;
1558 ctrl1[7] = dsp_data_organization;
1559 ctrl1[8] = dsp_control;
1560 ctrl1[9] = dsp_div_control;
1561 ctrl1[10] = IMASKCleared;
1562 ctrl1[11] = dsp_flag_z;
1563 ctrl1[12] = dsp_flag_n;
1564 ctrl1[13] = dsp_flag_c;
1568 if (instr1 != lastExec)
1570 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1572 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1573 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1586 // DSP execution core
1588 //static bool R20Set = false, tripwire = false;
1589 //static uint32 pcQueue[32], ptrPCQ = 0;
1590 void DSPExec(int32 cycles)
1592 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1593 dsp_check_if_i2s_interrupt_needed();*/
1595 #ifdef DSP_SINGLE_STEPPING
1596 if (dsp_control & 0x18)
1599 dsp_control &= ~0x10;
1602 //There is *no* good reason to do this here!
1604 dsp_releaseTimeSlice_flag = 0;
1607 while (cycles > 0 && DSP_RUNNING)
1609 /*extern uint32 totalFrames;
1610 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1611 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1612 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1614 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1617 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1619 if (dsp_pc == 0xF1B092)
1620 doDSPDis = false;//*/
1621 /*if (dsp_pc == 0xF1B140)
1622 doDSPDis = true;//*/
1624 if (IMASKCleared) // If IMASK was cleared,
1626 #ifdef DSP_DEBUG_IRQ
1627 WriteLog("DSP: Finished interrupt.\n");
1629 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1630 IMASKCleared = false;
1635 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1636 for(int i=0; i<80; i+=4)
1637 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1640 /*if (dsp_pc == 0xF1B55E)
1642 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1644 /*if (dsp_pc == 0xF1B7D2) // Start here???
1646 pcQueue[ptrPCQ++] = dsp_pc;
1648 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1649 uint32 index = opcode >> 10;
1650 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1651 dsp_opcode_second_parameter = opcode & 0x1F;
1653 dsp_opcode[index]();
1654 dsp_opcode_use[index]++;
1655 cycles -= dsp_opcode_cycles[index];
1656 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1658 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1661 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1663 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1665 DSPDumpDisassembly();
1668 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1671 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1674 WriteLog("\nBacktrace:\n");
1675 for(int i=0; i<32; i++)
1677 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1678 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1688 // DSP opcode handlers
1691 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1692 // can cause trouble because an interrupt can occur *before* the instruction following the
1693 // jump can execute... !!! FIX !!!
1694 static void dsp_opcode_jump(void)
1697 const char * condition[32] =
1698 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1699 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1700 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1701 "???", "???", "???", "F" };
1703 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);
1706 /* dsp_flag_c=dsp_flag_c?1:0;
1707 dsp_flag_z=dsp_flag_z?1:0;
1708 dsp_flag_n=dsp_flag_n?1:0;*/
1709 // KLUDGE: Used by BRANCH_CONDITION
1710 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1712 if (BRANCH_CONDITION(IMM_2))
1716 WriteLog("Branched!\n");
1718 uint32 delayed_pc = RM;
1720 dsp_pc = delayed_pc;
1725 WriteLog("Branch NOT taken.\n");
1729 static void dsp_opcode_jr(void)
1732 const char * condition[32] =
1733 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1734 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1735 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1736 "???", "???", "???", "F" };
1738 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);
1741 /* dsp_flag_c=dsp_flag_c?1:0;
1742 dsp_flag_z=dsp_flag_z?1:0;
1743 dsp_flag_n=dsp_flag_n?1:0;*/
1744 // KLUDGE: Used by BRANCH_CONDITION
1745 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1747 if (BRANCH_CONDITION(IMM_2))
1751 WriteLog("Branched!\n");
1753 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1754 int32 delayed_pc = dsp_pc + (offset * 2);
1756 dsp_pc = delayed_pc;
1761 WriteLog("Branch NOT taken.\n");
1765 static void dsp_opcode_add(void)
1769 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);
1771 uint32 res = RN + RM;
1772 SET_ZNC_ADD(RN, RM, res);
1776 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);
1780 static void dsp_opcode_addc(void)
1784 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);
1786 uint32 res = RN + RM + dsp_flag_c;
1787 uint32 carry = dsp_flag_c;
1788 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1789 SET_ZNC_ADD(RN + carry, RM, res);
1790 // SET_ZNC_ADD(RN, RM + carry, res);
1794 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);
1798 static void dsp_opcode_addq(void)
1802 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);
1804 uint32 r1 = dsp_convert_zero[IMM_1];
1805 uint32 res = RN + r1;
1806 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1810 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1814 static void dsp_opcode_sub(void)
1818 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);
1820 uint32 res = RN - RM;
1821 SET_ZNC_SUB(RN, RM, res);
1825 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);
1829 static void dsp_opcode_subc(void)
1833 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);
1835 uint32 res = RN - RM - dsp_flag_c;
1836 uint32 borrow = dsp_flag_c;
1837 SET_ZNC_SUB(RN - borrow, RM, res);
1841 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);
1845 static void dsp_opcode_subq(void)
1849 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);
1851 uint32 r1 = dsp_convert_zero[IMM_1];
1852 uint32 res = RN - r1;
1853 SET_ZNC_SUB(RN, r1, res);
1857 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1861 static void dsp_opcode_cmp(void)
1865 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);
1867 uint32 res = RN - RM;
1868 SET_ZNC_SUB(RN, RM, res);
1871 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1875 static void dsp_opcode_cmpq(void)
1877 static int32 sqtable[32] =
1878 { 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 };
1881 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);
1883 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1884 uint32 res = RN - r1;
1885 SET_ZNC_SUB(RN, r1, res);
1888 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1892 static void dsp_opcode_and(void)
1896 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);
1902 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1906 static void dsp_opcode_or(void)
1910 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);
1916 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);
1920 static void dsp_opcode_xor(void)
1924 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);
1930 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);
1934 static void dsp_opcode_not(void)
1938 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);
1944 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1948 static void dsp_opcode_move_pc(void)
1953 static void dsp_opcode_store_r14_indexed(void)
1955 #ifdef DSP_DIS_STORE14I
1957 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));
1959 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1960 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1962 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1966 static void dsp_opcode_store_r15_indexed(void)
1968 #ifdef DSP_DIS_STORE15I
1970 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));
1972 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1973 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1975 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1979 static void dsp_opcode_load_r14_ri(void)
1981 #ifdef DSP_DIS_LOAD14R
1983 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);
1985 #ifdef DSP_CORRECT_ALIGNMENT
1986 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1988 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1990 #ifdef DSP_DIS_LOAD14R
1992 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1996 static void dsp_opcode_load_r15_ri(void)
1998 #ifdef DSP_DIS_LOAD15R
2000 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);
2002 #ifdef DSP_CORRECT_ALIGNMENT
2003 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2005 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2007 #ifdef DSP_DIS_LOAD15R
2009 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2013 static void dsp_opcode_store_r14_ri(void)
2015 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2018 static void dsp_opcode_store_r15_ri(void)
2020 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2023 static void dsp_opcode_nop(void)
2027 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2031 static void dsp_opcode_storeb(void)
2033 #ifdef DSP_DIS_STOREB
2035 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);
2037 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2038 DSPWriteLong(RM, RN & 0xFF, DSP);
2040 JaguarWriteByte(RM, RN, DSP);
2043 static void dsp_opcode_storew(void)
2045 #ifdef DSP_DIS_STOREW
2047 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);
2049 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2050 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2051 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2053 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2055 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2056 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2058 JaguarWriteWord(RM, RN, DSP);
2062 static void dsp_opcode_store(void)
2064 #ifdef DSP_DIS_STORE
2066 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);
2068 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2069 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2071 DSPWriteLong(RM, RN, DSP);
2075 static void dsp_opcode_loadb(void)
2077 #ifdef DSP_DIS_LOADB
2079 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);
2081 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2082 RN = DSPReadLong(RM, DSP) & 0xFF;
2084 RN = JaguarReadByte(RM, DSP);
2085 #ifdef DSP_DIS_LOADB
2087 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2091 static void dsp_opcode_loadw(void)
2093 #ifdef DSP_DIS_LOADW
2095 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);
2097 #ifdef DSP_CORRECT_ALIGNMENT
2098 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2099 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2101 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2103 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2104 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2106 RN = JaguarReadWord(RM, DSP);
2108 #ifdef DSP_DIS_LOADW
2110 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2114 static void dsp_opcode_load(void)
2118 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);
2120 #ifdef DSP_CORRECT_ALIGNMENT
2121 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2123 RN = DSPReadLong(RM, DSP);
2127 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2131 static void dsp_opcode_load_r14_indexed(void)
2133 #ifdef DSP_DIS_LOAD14I
2135 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);
2137 #ifdef DSP_CORRECT_ALIGNMENT
2138 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2140 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2142 #ifdef DSP_DIS_LOAD14I
2144 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2148 static void dsp_opcode_load_r15_indexed(void)
2150 #ifdef DSP_DIS_LOAD15I
2152 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);
2154 #ifdef DSP_CORRECT_ALIGNMENT
2155 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2157 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2159 #ifdef DSP_DIS_LOAD15I
2161 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2165 static void dsp_opcode_movei(void)
2167 #ifdef DSP_DIS_MOVEI
2169 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);
2171 // This instruction is followed by 32-bit value in LSW / MSW format...
2172 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2174 #ifdef DSP_DIS_MOVEI
2176 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2180 static void dsp_opcode_moveta(void)
2182 #ifdef DSP_DIS_MOVETA
2184 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);
2187 #ifdef DSP_DIS_MOVETA
2189 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);
2193 static void dsp_opcode_movefa(void)
2195 #ifdef DSP_DIS_MOVEFA
2197 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);
2200 #ifdef DSP_DIS_MOVEFA
2202 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);
2206 static void dsp_opcode_move(void)
2210 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);
2215 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);
2219 static void dsp_opcode_moveq(void)
2221 #ifdef DSP_DIS_MOVEQ
2223 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);
2226 #ifdef DSP_DIS_MOVEQ
2228 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2232 static void dsp_opcode_resmac(void)
2234 #ifdef DSP_DIS_RESMAC
2236 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));
2238 RN = (uint32)dsp_acc;
2239 #ifdef DSP_DIS_RESMAC
2241 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2245 static void dsp_opcode_imult(void)
2247 #ifdef DSP_DIS_IMULT
2249 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);
2251 RN = (int16)RN * (int16)RM;
2253 #ifdef DSP_DIS_IMULT
2255 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);
2259 static void dsp_opcode_mult(void)
2263 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);
2265 RN = (uint16)RM * (uint16)RN;
2269 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);
2273 static void dsp_opcode_bclr(void)
2277 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);
2279 uint32 res = RN & ~(1 << IMM_1);
2284 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2288 static void dsp_opcode_btst(void)
2292 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);
2294 dsp_flag_z = (~RN >> IMM_1) & 1;
2297 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2301 static void dsp_opcode_bset(void)
2305 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);
2307 uint32 res = RN | (1 << IMM_1);
2312 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2316 static void dsp_opcode_subqt(void)
2318 #ifdef DSP_DIS_SUBQT
2320 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);
2322 RN -= dsp_convert_zero[IMM_1];
2323 #ifdef DSP_DIS_SUBQT
2325 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2329 static void dsp_opcode_addqt(void)
2331 #ifdef DSP_DIS_ADDQT
2333 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);
2335 RN += dsp_convert_zero[IMM_1];
2336 #ifdef DSP_DIS_ADDQT
2338 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2342 static void dsp_opcode_imacn(void)
2344 #ifdef DSP_DIS_IMACN
2346 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);
2348 int32 res = (int16)RM * (int16)RN;
2349 dsp_acc += (int64)res;
2350 //Should we AND the result to fit into 40 bits here???
2351 #ifdef DSP_DIS_IMACN
2353 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));
2357 static void dsp_opcode_mtoi(void)
2359 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2363 static void dsp_opcode_normi(void)
2370 while ((_Rm & 0xffc00000) == 0)
2375 while ((_Rm & 0xff800000) != 0)
2385 static void dsp_opcode_mmult(void)
2387 int count = dsp_matrix_control&0x0f;
2388 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2392 if (!(dsp_matrix_control & 0x10))
2394 for (int i = 0; i < count; i++)
2398 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2400 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2401 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2408 for (int i = 0; i < count; i++)
2412 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2414 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2415 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2420 RN = res = (int32)accum;
2422 //NOTE: The flags are set based upon the last add/multiply done...
2426 static void dsp_opcode_abs(void)
2430 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);
2435 if (_Rn == 0x80000000)
2439 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2440 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2445 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2449 static void dsp_opcode_div(void)
2456 if (dsp_div_control & 1)
2458 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2459 if (dsp_remain&0x80000000)
2461 RN = (((uint64)_Rn) << 16) / _Rm;
2465 dsp_remain = _Rn % _Rm;
2466 if (dsp_remain&0x80000000)
2475 static void dsp_opcode_imultn(void)
2477 #ifdef DSP_DIS_IMULTN
2479 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);
2481 // This is OK, since this multiply won't overflow 32 bits...
2482 int32 res = (int32)((int16)RN * (int16)RM);
2483 dsp_acc = (int64)res;
2485 #ifdef DSP_DIS_IMULTN
2487 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));
2491 static void dsp_opcode_neg(void)
2495 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);
2498 SET_ZNC_SUB(0, RN, res);
2502 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2506 static void dsp_opcode_shlq(void)
2510 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);
2512 int32 r1 = 32 - IMM_1;
2513 uint32 res = RN << r1;
2514 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2518 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2522 static void dsp_opcode_shrq(void)
2526 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);
2528 int32 r1 = dsp_convert_zero[IMM_1];
2529 uint32 res = RN >> r1;
2530 SET_ZN(res); dsp_flag_c = RN & 1;
2534 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2538 static void dsp_opcode_ror(void)
2542 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);
2544 uint32 r1 = RM & 0x1F;
2545 uint32 res = (RN >> r1) | (RN << (32 - r1));
2546 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2550 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);
2554 static void dsp_opcode_rorq(void)
2558 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);
2560 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2562 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2564 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2571 static void dsp_opcode_sha(void)
2573 int32 sRm=(int32)RM;
2579 if (shift>=32) shift=32;
2580 dsp_flag_c=(_Rn&0x80000000)>>31;
2590 if (shift>=32) shift=32;
2594 _Rn=((int32)_Rn)>>1;
2602 static void dsp_opcode_sharq(void)
2604 #ifdef DSP_DIS_SHARQ
2606 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);
2608 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2609 SET_ZN(res); dsp_flag_c = RN & 0x01;
2611 #ifdef DSP_DIS_SHARQ
2613 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2617 static void dsp_opcode_sh(void)
2619 int32 sRm=(int32)RM;
2624 uint32 shift=(-sRm);
2625 if (shift>=32) shift=32;
2626 dsp_flag_c=(_Rn&0x80000000)>>31;
2636 if (shift>=32) shift=32;
2648 void dsp_opcode_addqmod(void)
2650 #ifdef DSP_DIS_ADDQMOD
2652 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);
2654 uint32 r1 = dsp_convert_zero[IMM_1];
2656 uint32 res = r2 + r1;
2657 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2659 SET_ZNC_ADD(r2, r1, res);
2660 #ifdef DSP_DIS_ADDQMOD
2662 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2666 void dsp_opcode_subqmod(void)
2668 uint32 r1 = dsp_convert_zero[IMM_1];
2670 uint32 res = r2 - r1;
2671 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2674 SET_ZNC_SUB(r2, r1, res);
2677 void dsp_opcode_mirror(void)
2680 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2684 void dsp_opcode_sat32s(void)
2686 int32 r2 = (uint32)RN;
2687 int32 temp = dsp_acc >> 32;
2688 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2693 void dsp_opcode_sat16s(void)
2696 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2702 // New pipelined DSP core
2705 static void DSP_abs(void);
2706 static void DSP_add(void);
2707 static void DSP_addc(void);
2708 static void DSP_addq(void);
2709 static void DSP_addqmod(void);
2710 static void DSP_addqt(void);
2711 static void DSP_and(void);
2712 static void DSP_bclr(void);
2713 static void DSP_bset(void);
2714 static void DSP_btst(void);
2715 static void DSP_cmp(void);
2716 static void DSP_cmpq(void);
2717 static void DSP_div(void);
2718 static void DSP_imacn(void);
2719 static void DSP_imult(void);
2720 static void DSP_imultn(void);
2721 static void DSP_illegal(void);
2722 static void DSP_jr(void);
2723 static void DSP_jump(void);
2724 static void DSP_load(void);
2725 static void DSP_loadb(void);
2726 static void DSP_loadw(void);
2727 static void DSP_load_r14_i(void);
2728 static void DSP_load_r14_r(void);
2729 static void DSP_load_r15_i(void);
2730 static void DSP_load_r15_r(void);
2731 static void DSP_mirror(void);
2732 static void DSP_mmult(void);
2733 static void DSP_move(void);
2734 static void DSP_movefa(void);
2735 static void DSP_movei(void);
2736 static void DSP_movepc(void);
2737 static void DSP_moveq(void);
2738 static void DSP_moveta(void);
2739 static void DSP_mtoi(void);
2740 static void DSP_mult(void);
2741 static void DSP_neg(void);
2742 static void DSP_nop(void);
2743 static void DSP_normi(void);
2744 static void DSP_not(void);
2745 static void DSP_or(void);
2746 static void DSP_resmac(void);
2747 static void DSP_ror(void);
2748 static void DSP_rorq(void);
2749 static void DSP_sat16s(void);
2750 static void DSP_sat32s(void);
2751 static void DSP_sh(void);
2752 static void DSP_sha(void);
2753 static void DSP_sharq(void);
2754 static void DSP_shlq(void);
2755 static void DSP_shrq(void);
2756 static void DSP_store(void);
2757 static void DSP_storeb(void);
2758 static void DSP_storew(void);
2759 static void DSP_store_r14_i(void);
2760 static void DSP_store_r14_r(void);
2761 static void DSP_store_r15_i(void);
2762 static void DSP_store_r15_r(void);
2763 static void DSP_sub(void);
2764 static void DSP_subc(void);
2765 static void DSP_subq(void);
2766 static void DSP_subqmod(void);
2767 static void DSP_subqt(void);
2768 static void DSP_xor(void);
2770 void (* DSPOpcode[64])() =
2772 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2773 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2774 DSP_neg, DSP_and, DSP_or, DSP_xor,
2775 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2777 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2778 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2779 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2780 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2782 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2783 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2784 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2785 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2787 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2788 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2789 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2790 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2793 bool readAffected[64][2] =
2795 { true, true}, { true, true}, {false, true}, {false, true},
2796 { true, true}, { true, true}, {false, true}, {false, true},
2797 {false, true}, { true, true}, { true, true}, { true, true},
2798 {false, true}, {false, true}, {false, true}, {false, true},
2800 { true, true}, { true, true}, { true, true}, {false, true},
2801 { true, true}, { true, true}, {false, true}, { true, true},
2802 {false, true}, {false, true}, { true, true}, {false, true},
2803 { true, true}, {false, true}, { true, true}, {false, true},
2805 {false, true}, {false, true}, { true, false}, {false, false},
2806 { true, false}, {false, false}, {false, false}, { true, false},
2807 { true, false}, { true, false}, {false, true}, { true, false},
2808 { true, false}, { true, true}, { true, true}, { true, true},
2810 {false, true}, { true, true}, { true, true}, {false, true},
2811 { true, false}, { true, false}, { true, true}, { true, false},
2812 { true, false}, {false, false}, { true, false}, { true, false},
2813 { true, true}, { true, true}, {false, false}, {false, true}
2816 bool isLoadStore[65] =
2818 false, false, false, false, false, false, false, false,
2819 false, false, false, false, false, false, false, false,
2821 false, false, false, false, false, false, false, false,
2822 false, false, false, false, false, false, false, false,
2824 false, false, false, false, false, false, false, true,
2825 true, true, false, true, true, true, true, true,
2827 false, true, true, false, false, false, false, false,
2828 false, false, true, true, true, true, false, false, false
2831 void FlushDSPPipeline(void)
2833 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2835 for(int i=0; i<4; i++)
2836 pipeline[i].opcode = PIPELINE_STALL;
2838 for(int i=0; i<32; i++)
2843 // New pipelined DSP execution core
2845 /*void DSPExecP(int32 cycles)
2847 // bool inhibitFetch = false;
2849 dsp_releaseTimeSlice_flag = 0;
2852 while (cycles > 0 && DSP_RUNNING)
2854 WriteLog("DSPExecP: Pipeline status...\n");
2855 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2856 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2857 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2858 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2859 WriteLog(" --> Scoreboard: ");
2860 for(int i=0; i<32; i++)
2861 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2863 // Stage 1: Instruction fetch
2864 // if (!inhibitFetch)
2866 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2867 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2868 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2869 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2870 if (pipeline[plPtrFetch].opcode == 38)
2871 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2872 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2875 // inhibitFetch = false;
2876 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2878 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2879 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);
2880 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);
2881 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);
2882 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);
2883 // Stage 2: Read registers
2884 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2885 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2886 if (scoreboard[pipeline[plPtrRead].operand2])
2887 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2888 // We have a hit in the scoreboard, so we have to stall the pipeline...
2890 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2891 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2892 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2893 pipeline[plPtrFetch] = pipeline[plPtrRead];
2894 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2898 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2899 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2900 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2902 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2903 // Shouldn't we be more selective with the register scoreboarding?
2904 // Yes, we should. !!! FIX !!!
2905 scoreboard[pipeline[plPtrRead].operand2] = true;
2906 //Advance PC here??? Yes.
2907 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2908 //This is a mangling of the pipeline stages, but what else to do???
2909 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2912 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2913 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);
2914 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);
2915 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);
2916 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);
2918 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2920 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2921 DSPOpcode[pipeline[plPtrExec].opcode]();
2922 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2923 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2928 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2929 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);
2930 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);
2931 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);
2932 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);
2933 // Stage 4: Write back register
2934 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2936 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2937 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2939 scoreboard[pipeline[plPtrWrite].operand1]
2940 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2943 // Push instructions through the pipeline...
2944 plPtrFetch = (++plPtrFetch) & 0x03;
2945 plPtrRead = (++plPtrRead) & 0x03;
2946 plPtrExec = (++plPtrExec) & 0x03;
2947 plPtrWrite = (++plPtrWrite) & 0x03;
2954 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2956 // Should be fixed now. Another problem is figuring how to do the sequence following
2957 // a branch followed with the JR & JUMP instructions...
2959 // There are two conflicting problems:
2962 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2963 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2964 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2965 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2966 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2967 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2968 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2969 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2970 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2971 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2972 DSP: Finished interrupt.
2973 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2974 ; bank 0 (where is was prepared)!
2975 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2976 F1B252: NOP [NCZ:001]
2979 // The other is when you see this at the end of an IRQ:
2982 JUMP T, (R29) ; R29 = Previous stack + 2
2983 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2985 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2986 ; 1) The STORE goes through the pipeline and is executed/written back
2987 ; 2) The pipeline is flushed
2988 ; 3) The DSP_PC is set to the new address
2989 ; 4) Execution resumes
2991 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2992 ; bank 0 instead of the current bank 1 and so goes astray!
2995 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2996 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3000 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3001 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3002 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3003 If it were done properly, the STORE write back would occur *after* (well, technically,
3004 during) the execution of the the JUMP that follows it.
3008 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3009 F1B08A: NOP [NCZ:001]
3011 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3014 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3017 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3018 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3019 F1B08A: NOP [NCZ:001]
3021 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3024 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3025 DSP: CPU -> DSP interrupt
3026 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3027 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3029 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3032 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3033 F1B006: NOP [NCZ:001]
3035 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3038 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3039 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3042 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3043 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3046 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3047 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3050 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3051 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3054 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3057 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3060 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3061 F1B0FE: NOP [NCZ:000]
3063 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3066 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3069 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3070 F1B138: NOP [NCZ:000]
3072 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3075 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3076 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3077 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3080 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3081 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3084 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3085 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3086 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3088 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3089 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3092 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3093 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3094 DSP: Finished interrupt.
3095 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3097 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3100 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3101 F1B016: NOP [NCZ:001]
3103 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3106 uint32 pcQueue1[0x400];
3108 static uint32 prevR1;
3109 //Let's try a 3 stage pipeline....
3110 //Looks like 3 stage is correct, otherwise bad things happen...
3111 void DSPExecP2(int32 cycles)
3113 dsp_releaseTimeSlice_flag = 0;
3116 while (cycles > 0 && DSP_RUNNING)
3118 /*extern uint32 totalFrames;
3119 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3120 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3121 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3123 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3126 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3128 if (dsp_pc == 0xF1B092)
3129 doDSPDis = false;//*/
3130 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3131 doDSPDis = true;//*/
3132 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3133 doDSPDis = true;//*/
3134 /*if (dsp_pc == 0xF1B0A0)
3135 doDSPDis = true;//*/
3136 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3137 doDSPDis = true;//*/
3138 //Two parter... (not sure how to write this)
3139 //if (dsp_pc == 0xF1B0D2)
3140 // prevR1 = dsp_reg[1];
3142 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3143 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3146 pcQueue1[pcQPtr1++] = dsp_pc;
3149 #ifdef DSP_DEBUG_PL2
3150 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3152 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3157 for(int i=0; i<0x400; i++)
3159 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3160 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3166 if (IMASKCleared) // If IMASK was cleared,
3168 #ifdef DSP_DEBUG_IRQ
3169 WriteLog("DSP: Finished interrupt.\n");
3171 DSPHandleIRQs(); // See if any other interrupts are pending!
3172 IMASKCleared = false;
3175 //if (dsp_flags & REGPAGE)
3176 // WriteLog(" --> REGPAGE has just been set!\n");
3177 #ifdef DSP_DEBUG_PL2
3180 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3181 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]);
3182 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]);
3183 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]);
3184 WriteLog(" --> Scoreboard: ");
3185 for(int i=0; i<32; i++)
3186 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3190 // Stage 1a: Instruction fetch
3191 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3192 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3193 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3194 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3195 if (pipeline[plPtrRead].opcode == 38)
3196 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3197 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3198 #ifdef DSP_DEBUG_PL2
3201 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3202 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3203 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]);
3204 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]);
3205 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]);
3208 // Stage 1b: Read registers
3209 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3210 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3212 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3213 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3214 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3215 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3216 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3217 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3218 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3220 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3221 // We have a hit in the scoreboard, so we have to stall the pipeline...
3222 #ifdef DSP_DEBUG_PL2
3226 WriteLog(" --> Stalling pipeline: ");
3227 if (readAffected[pipeline[plPtrRead].opcode][0])
3228 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3229 if (readAffected[pipeline[plPtrRead].opcode][1])
3230 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3234 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3235 #ifdef DSP_DEBUG_PL2
3240 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3241 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3242 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3244 // Shouldn't we be more selective with the register scoreboarding?
3245 // Yes, we should. !!! FIX !!! Kinda [DONE]
3246 #ifndef NEW_SCOREBOARD
3247 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3249 //Hopefully this will fix the dual MOVEQ # problem...
3250 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3253 //Advance PC here??? Yes.
3254 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3257 #ifdef DSP_DEBUG_PL2
3260 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3261 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]);
3262 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]);
3263 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]);
3267 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3269 #ifdef DSP_DEBUG_PL2
3271 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"));
3275 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3280 lastExec = pipeline[plPtrExec].instruction;
3281 //WriteLog("[lastExec = %04X]\n", lastExec);
3283 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3284 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3285 DSPOpcode[pipeline[plPtrExec].opcode]();
3286 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3290 //Let's not, until we do the stalling correctly...
3291 //But, we gotta while we're doing the comparison core...!
3292 //Or do we? cycles--;
3293 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3294 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3295 //to model this clock cycle behavior correctly...
3296 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3297 //don't affect the reads at stage 1...
3298 #ifdef DSP_DEBUG_STALL
3300 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3304 #ifdef DSP_DEBUG_PL2
3307 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3308 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]);
3309 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]);
3310 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]);
3314 // Stage 3: Write back register/memory address
3315 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3317 /*if (pipeline[plPtrWrite].writebackRegister == 3
3318 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3321 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3324 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3326 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3327 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3330 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3331 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3332 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3333 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3335 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3339 #ifndef NEW_SCOREBOARD
3340 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3341 scoreboard[pipeline[plPtrWrite].operand2] = false;
3343 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3344 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3345 if (scoreboard[pipeline[plPtrWrite].operand2])
3346 scoreboard[pipeline[plPtrWrite].operand2]--;
3350 // Push instructions through the pipeline...
3351 plPtrRead = (++plPtrRead) & 0x03;
3352 plPtrExec = (++plPtrExec) & 0x03;
3353 plPtrWrite = (++plPtrWrite) & 0x03;
3362 //#define DSP_DEBUG_PL3
3363 //Let's try a 2 stage pipeline....
3364 void DSPExecP3(int32 cycles)
3366 dsp_releaseTimeSlice_flag = 0;
3369 while (cycles > 0 && DSP_RUNNING)
3371 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3373 #ifdef DSP_DEBUG_PL3
3374 WriteLog("DSPExecP: Pipeline status...\n");
3375 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]);
3376 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]);
3377 WriteLog(" --> Scoreboard: ");
3378 for(int i=0; i<32; i++)
3379 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3382 // Stage 1a: Instruction fetch
3383 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3384 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3385 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3386 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3387 if (pipeline[plPtrRead].opcode == 38)
3388 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3389 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3390 #ifdef DSP_DEBUG_PL3
3391 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3392 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3393 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]);
3394 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]);
3396 // Stage 1b: Read registers
3397 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3398 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3399 // We have a hit in the scoreboard, so we have to stall the pipeline...
3400 #ifdef DSP_DEBUG_PL3
3402 WriteLog(" --> Stalling pipeline: ");
3403 if (readAffected[pipeline[plPtrRead].opcode][0])
3404 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3405 if (readAffected[pipeline[plPtrRead].opcode][1])
3406 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3409 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3410 #ifdef DSP_DEBUG_PL3
3415 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3416 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3417 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3419 // Shouldn't we be more selective with the register scoreboarding?
3420 // Yes, we should. !!! FIX !!! [Kinda DONE]
3421 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3423 //Advance PC here??? Yes.
3424 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3427 #ifdef DSP_DEBUG_PL3
3428 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3429 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]);
3430 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]);
3432 // Stage 2a: Execute
3433 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3435 #ifdef DSP_DEBUG_PL3
3436 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3438 DSPOpcode[pipeline[plPtrExec].opcode]();
3439 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3440 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3445 #ifdef DSP_DEBUG_PL3
3446 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3447 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]);
3448 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]);
3451 // Stage 2b: Write back register
3452 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3454 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3455 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3457 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3458 scoreboard[pipeline[plPtrExec].operand2] = false;
3461 // Push instructions through the pipeline...
3462 plPtrRead = (++plPtrRead) & 0x03;
3463 plPtrExec = (++plPtrExec) & 0x03;
3470 // DSP pipelined opcode handlers
3473 #define PRM pipeline[plPtrExec].reg1
3474 #define PRN pipeline[plPtrExec].reg2
3475 #define PIMM1 pipeline[plPtrExec].operand1
3476 #define PIMM2 pipeline[plPtrExec].operand2
3477 #define PRES pipeline[plPtrExec].result
3478 #define PWBR pipeline[plPtrExec].writebackRegister
3479 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3480 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3481 #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))
3482 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3484 static void DSP_abs(void)
3488 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);
3492 if (_Rn == 0x80000000)
3496 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3497 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3498 CLR_ZN; SET_Z(PRES);
3502 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3506 static void DSP_add(void)
3510 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);
3512 uint32 res = PRN + PRM;
3513 SET_ZNC_ADD(PRN, PRM, res);
3517 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
3521 static void DSP_addc(void)
3525 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);
3527 uint32 res = PRN + PRM + dsp_flag_c;
3528 uint32 carry = dsp_flag_c;
3529 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3530 SET_ZNC_ADD(PRN + carry, PRM, res);
3531 // SET_ZNC_ADD(PRN, PRM + carry, res);
3535 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);
3539 static void DSP_addq(void)
3543 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);
3545 uint32 r1 = dsp_convert_zero[PIMM1];
3546 uint32 res = PRN + r1;
3547 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3555 static void DSP_addqmod(void)
3557 #ifdef DSP_DIS_ADDQMOD
3559 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);
3561 uint32 r1 = dsp_convert_zero[PIMM1];
3563 uint32 res = r2 + r1;
3564 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3566 SET_ZNC_ADD(r2, r1, res);
3567 #ifdef DSP_DIS_ADDQMOD
3569 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3573 static void DSP_addqt(void)
3575 #ifdef DSP_DIS_ADDQT
3577 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);
3579 PRES = PRN + dsp_convert_zero[PIMM1];
3580 #ifdef DSP_DIS_ADDQT
3582 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3586 static void DSP_and(void)
3590 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);
3596 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);
3600 static void DSP_bclr(void)
3604 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);
3606 PRES = PRN & ~(1 << PIMM1);
3610 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3614 static void DSP_bset(void)
3618 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);
3620 PRES = PRN | (1 << PIMM1);
3624 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3628 static void DSP_btst(void)
3632 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);
3634 dsp_flag_z = (~PRN >> PIMM1) & 1;
3638 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3642 static void DSP_cmp(void)
3646 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);
3648 uint32 res = PRN - PRM;
3649 SET_ZNC_SUB(PRN, PRM, res);
3653 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3657 static void DSP_cmpq(void)
3659 static int32 sqtable[32] =
3660 { 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 };
3663 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);
3665 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3666 uint32 res = PRN - r1;
3667 SET_ZNC_SUB(PRN, r1, res);
3671 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3675 static void DSP_div(void)
3677 uint32 _Rm = PRM, _Rn = PRN;
3681 if (dsp_div_control & 1)
3683 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3684 if (dsp_remain & 0x80000000)
3686 PRES = (((uint64)_Rn) << 16) / _Rm;
3690 dsp_remain = _Rn % _Rm;
3691 if (dsp_remain & 0x80000000)
3700 static void DSP_imacn(void)
3702 #ifdef DSP_DIS_IMACN
3704 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);
3706 int32 res = (int16)PRM * (int16)PRN;
3707 dsp_acc += (int64)res;
3708 //Should we AND the result to fit into 40 bits here???
3710 #ifdef DSP_DIS_IMACN
3712 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));
3716 static void DSP_imult(void)
3718 #ifdef DSP_DIS_IMULT
3720 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);
3722 PRES = (int16)PRN * (int16)PRM;
3724 #ifdef DSP_DIS_IMULT
3726 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);
3730 static void DSP_imultn(void)
3732 #ifdef DSP_DIS_IMULTN
3734 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);
3736 // This is OK, since this multiply won't overflow 32 bits...
3737 int32 res = (int32)((int16)PRN * (int16)PRM);
3738 dsp_acc = (int64)res;
3741 #ifdef DSP_DIS_IMULTN
3743 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));
3747 static void DSP_illegal(void)
3749 #ifdef DSP_DIS_ILLEGAL
3751 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3756 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3757 // can cause trouble because an interrupt can occur *before* the instruction following the
3758 // jump can execute... !!! FIX !!!
3759 // This can probably be solved by judicious coding in the pipeline execution core...
3760 // And should be fixed now...
3761 static void DSP_jr(void)
3764 const char * condition[32] =
3765 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3766 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3767 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3768 "???", "???", "???", "F" };
3770 //How come this is always off by 2???
3771 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);
3773 // KLUDGE: Used by BRANCH_CONDITION macro
3774 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3776 if (BRANCH_CONDITION(PIMM2))
3780 WriteLog("Branched!\n");
3782 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3783 //Account for pipeline effects...
3784 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3785 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3787 // Now that we've branched, we have to make sure that the following instruction
3788 // is executed atomically with this one and then flush the pipeline before setting
3791 // Step 1: Handle writebacks at stage 3 of pipeline
3792 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3794 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3795 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3797 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3798 scoreboard[pipeline[plPtrWrite].operand2] = false;
3800 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3802 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3804 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3805 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3808 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3809 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3810 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3811 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3813 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3817 #ifndef NEW_SCOREBOARD
3818 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3819 scoreboard[pipeline[plPtrWrite].operand2] = false;
3821 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3822 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3823 if (scoreboard[pipeline[plPtrWrite].operand2])
3824 scoreboard[pipeline[plPtrWrite].operand2]--;
3828 // Step 2: Push instruction through pipeline & execute following instruction
3829 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3830 // we effectively handle the final push of the instruction through the
3831 // pipeline when the new PC takes effect (since when we return, the
3832 // pipeline code will be executing the writeback stage. If we reverse
3833 // the execution order of the pipeline stages, this will no longer be
3835 pipeline[plPtrExec] = pipeline[plPtrRead];
3836 //This is BAD. We need to get that next opcode and execute it!
3837 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3838 // remove this crap.
3839 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3841 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3842 pipeline[plPtrExec].opcode = instruction >> 10;
3843 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3844 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3845 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3846 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3847 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3849 dsp_pc += 2; // For DSP_DIS_* accuracy
3850 DSPOpcode[pipeline[plPtrExec].opcode]();
3851 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3852 pipeline[plPtrWrite] = pipeline[plPtrExec];
3854 // Step 3: Flush pipeline & set new PC
3855 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3862 WriteLog("Branch NOT taken.\n");
3868 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3871 static void DSP_jump(void)
3874 const char * condition[32] =
3875 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3876 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3877 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3878 "???", "???", "???", "F" };
3880 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);
3882 // KLUDGE: Used by BRANCH_CONDITION macro
3883 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3885 if (BRANCH_CONDITION(PIMM2))
3889 WriteLog("Branched!\n");
3891 uint32 PCSave = PRM;
3892 // Now that we've branched, we have to make sure that the following instruction
3893 // is executed atomically with this one and then flush the pipeline before setting
3896 // Step 1: Handle writebacks at stage 3 of pipeline
3897 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3899 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3900 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3902 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3903 scoreboard[pipeline[plPtrWrite].operand2] = false;
3905 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3907 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3909 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3910 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3913 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3914 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3915 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3916 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3918 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3922 #ifndef NEW_SCOREBOARD
3923 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3924 scoreboard[pipeline[plPtrWrite].operand2] = false;
3926 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3927 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3928 if (scoreboard[pipeline[plPtrWrite].operand2])
3929 scoreboard[pipeline[plPtrWrite].operand2]--;
3933 // Step 2: Push instruction through pipeline & execute following instruction
3934 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3935 // we effectively handle the final push of the instruction through the
3936 // pipeline when the new PC takes effect (since when we return, the
3937 // pipeline code will be executing the writeback stage. If we reverse
3938 // the execution order of the pipeline stages, this will no longer be
3940 pipeline[plPtrExec] = pipeline[plPtrRead];
3941 //This is BAD. We need to get that next opcode and execute it!
3942 //Also, same problem in JR!
3943 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3944 // remove this crap.
3945 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3947 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3948 pipeline[plPtrExec].opcode = instruction >> 10;
3949 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3950 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3951 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3952 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3953 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3955 dsp_pc += 2; // For DSP_DIS_* accuracy
3956 DSPOpcode[pipeline[plPtrExec].opcode]();
3957 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3958 pipeline[plPtrWrite] = pipeline[plPtrExec];
3960 // Step 3: Flush pipeline & set new PC
3961 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3968 WriteLog("Branch NOT taken.\n");
3976 static void DSP_load(void)
3980 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);
3982 #ifdef DSP_CORRECT_ALIGNMENT
3983 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3985 PRES = DSPReadLong(PRM, DSP);
3989 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3993 static void DSP_loadb(void)
3995 #ifdef DSP_DIS_LOADB
3997 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);
3999 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4000 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4002 PRES = JaguarReadByte(PRM, DSP);
4003 #ifdef DSP_DIS_LOADB
4005 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4009 static void DSP_loadw(void)
4011 #ifdef DSP_DIS_LOADW
4013 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);
4015 #ifdef DSP_CORRECT_ALIGNMENT
4016 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4017 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4019 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4021 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4022 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4024 PRES = JaguarReadWord(PRM, DSP);
4026 #ifdef DSP_DIS_LOADW
4028 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4032 static void DSP_load_r14_i(void)
4034 #ifdef DSP_DIS_LOAD14I
4036 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);
4038 #ifdef DSP_CORRECT_ALIGNMENT
4039 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4041 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4043 #ifdef DSP_DIS_LOAD14I
4045 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4049 static void DSP_load_r14_r(void)
4051 #ifdef DSP_DIS_LOAD14R
4053 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);
4055 #ifdef DSP_CORRECT_ALIGNMENT
4056 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4058 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4060 #ifdef DSP_DIS_LOAD14R
4062 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4066 static void DSP_load_r15_i(void)
4068 #ifdef DSP_DIS_LOAD15I
4070 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);
4072 #ifdef DSP_CORRECT_ALIGNMENT
4073 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4075 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4077 #ifdef DSP_DIS_LOAD15I
4079 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4083 static void DSP_load_r15_r(void)
4085 #ifdef DSP_DIS_LOAD15R
4087 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);
4089 #ifdef DSP_CORRECT_ALIGNMENT
4090 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4092 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4094 #ifdef DSP_DIS_LOAD15R
4096 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4100 static void DSP_mirror(void)
4103 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4107 static void DSP_mmult(void)
4109 int count = dsp_matrix_control&0x0f;
4110 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4114 if (!(dsp_matrix_control & 0x10))
4116 for (int i = 0; i < count; i++)
4120 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4122 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4123 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4130 for (int i = 0; i < count; i++)
4134 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4136 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4137 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4143 PRES = res = (int32)accum;
4145 //NOTE: The flags are set based upon the last add/multiply done...
4149 static void DSP_move(void)
4153 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);
4158 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);
4162 static void DSP_movefa(void)
4164 #ifdef DSP_DIS_MOVEFA
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, ALTERNATE_RM, PIMM2, PRN);
4167 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);
4169 // PRES = ALTERNATE_RM;
4170 PRES = dsp_alternate_reg[PIMM1];
4171 #ifdef DSP_DIS_MOVEFA
4173 // 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);
4174 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);
4178 static void DSP_movei(void)
4180 #ifdef DSP_DIS_MOVEI
4182 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);
4184 // // This instruction is followed by 32-bit value in LSW / MSW format...
4185 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4187 #ifdef DSP_DIS_MOVEI
4189 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4193 static void DSP_movepc(void)
4195 #ifdef DSP_DIS_MOVEPC
4197 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);
4199 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4200 // PRES = dsp_pc - 2;
4201 //Account for pipeline effects...
4202 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4203 #ifdef DSP_DIS_MOVEPC
4205 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4209 static void DSP_moveq(void)
4211 #ifdef DSP_DIS_MOVEQ
4213 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);
4216 #ifdef DSP_DIS_MOVEQ
4218 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4222 static void DSP_moveta(void)
4224 #ifdef DSP_DIS_MOVETA
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, ALTERNATE_RN);
4227 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]);
4229 // ALTERNATE_RN = PRM;
4230 dsp_alternate_reg[PIMM2] = PRM;
4232 #ifdef DSP_DIS_MOVETA
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, ALTERNATE_RN);
4235 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]);
4239 static void DSP_mtoi(void)
4241 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4245 static void DSP_mult(void)
4249 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);
4251 PRES = (uint16)PRM * (uint16)PRN;
4255 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);
4259 static void DSP_neg(void)
4263 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);
4266 SET_ZNC_SUB(0, PRN, res);
4270 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4274 static void DSP_nop(void)
4278 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4283 static void DSP_normi(void)
4290 while ((_Rm & 0xffc00000) == 0)
4295 while ((_Rm & 0xff800000) != 0)
4305 static void DSP_not(void)
4309 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);
4315 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4319 static void DSP_or(void)
4323 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);
4329 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);
4333 static void DSP_resmac(void)
4335 #ifdef DSP_DIS_RESMAC
4337 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));
4339 PRES = (uint32)dsp_acc;
4340 #ifdef DSP_DIS_RESMAC
4342 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4346 static void DSP_ror(void)
4350 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);
4352 uint32 r1 = PRM & 0x1F;
4353 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4354 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4358 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);
4362 static void DSP_rorq(void)
4366 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);
4368 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4370 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4372 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4375 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4379 static void DSP_sat16s(void)
4382 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4387 static void DSP_sat32s(void)
4389 int32 r2 = (uint32)PRN;
4390 int32 temp = dsp_acc >> 32;
4391 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4396 static void DSP_sh(void)
4398 int32 sRm = (int32)PRM;
4403 uint32 shift = -sRm;
4408 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4423 dsp_flag_c = _Rn & 0x1;
4436 static void DSP_sha(void)
4438 int32 sRm = (int32)PRM;
4443 uint32 shift = -sRm;
4448 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4463 dsp_flag_c = _Rn & 0x1;
4467 _Rn = ((int32)_Rn) >> 1;
4476 static void DSP_sharq(void)
4478 #ifdef DSP_DIS_SHARQ
4480 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);
4482 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4483 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4485 #ifdef DSP_DIS_SHARQ
4487 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4491 static void DSP_shlq(void)
4495 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);
4497 int32 r1 = 32 - PIMM1;
4498 uint32 res = PRN << r1;
4499 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4503 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4507 static void DSP_shrq(void)
4511 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);
4513 int32 r1 = dsp_convert_zero[PIMM1];
4514 uint32 res = PRN >> r1;
4515 SET_ZN(res); dsp_flag_c = PRN & 1;
4519 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4523 static void DSP_store(void)
4525 #ifdef DSP_DIS_STORE
4527 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);
4529 // DSPWriteLong(PRM, PRN, DSP);
4531 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4532 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4534 pipeline[plPtrExec].address = PRM;
4536 pipeline[plPtrExec].value = PRN;
4537 pipeline[plPtrExec].type = TYPE_DWORD;
4541 static void DSP_storeb(void)
4543 #ifdef DSP_DIS_STOREB
4545 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);
4547 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4548 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4550 // JaguarWriteByte(PRM, PRN, DSP);
4553 pipeline[plPtrExec].address = PRM;
4555 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4557 pipeline[plPtrExec].value = PRN & 0xFF;
4558 pipeline[plPtrExec].type = TYPE_DWORD;
4562 pipeline[plPtrExec].value = PRN;
4563 pipeline[plPtrExec].type = TYPE_BYTE;
4569 static void DSP_storew(void)
4571 #ifdef DSP_DIS_STOREW
4573 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);
4575 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4576 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4578 // JaguarWriteWord(PRM, PRN, DSP);
4581 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4582 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4584 pipeline[plPtrExec].address = PRM;
4587 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4589 pipeline[plPtrExec].value = PRN & 0xFFFF;
4590 pipeline[plPtrExec].type = TYPE_DWORD;
4594 pipeline[plPtrExec].value = PRN;
4595 pipeline[plPtrExec].type = TYPE_WORD;
4600 static void DSP_store_r14_i(void)
4602 #ifdef DSP_DIS_STORE14I
4604 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));
4606 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4608 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4609 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4611 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4613 pipeline[plPtrExec].value = PRN;
4614 pipeline[plPtrExec].type = TYPE_DWORD;
4618 static void DSP_store_r14_r(void)
4620 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4622 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4623 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4625 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4627 pipeline[plPtrExec].value = PRN;
4628 pipeline[plPtrExec].type = TYPE_DWORD;
4632 static void DSP_store_r15_i(void)
4634 #ifdef DSP_DIS_STORE15I
4636 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));
4638 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4640 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4641 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4643 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4645 pipeline[plPtrExec].value = PRN;
4646 pipeline[plPtrExec].type = TYPE_DWORD;
4650 static void DSP_store_r15_r(void)
4652 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4654 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4655 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4657 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4659 pipeline[plPtrExec].value = PRN;
4660 pipeline[plPtrExec].type = TYPE_DWORD;
4664 static void DSP_sub(void)
4668 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);
4670 uint32 res = PRN - PRM;
4671 SET_ZNC_SUB(PRN, PRM, res);
4675 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);
4679 static void DSP_subc(void)
4683 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);
4685 uint32 res = PRN - PRM - dsp_flag_c;
4686 uint32 borrow = dsp_flag_c;
4687 SET_ZNC_SUB(PRN - borrow, PRM, res);
4691 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);
4695 static void DSP_subq(void)
4699 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);
4701 uint32 r1 = dsp_convert_zero[PIMM1];
4702 uint32 res = PRN - r1;
4703 SET_ZNC_SUB(PRN, r1, res);
4707 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4711 static void DSP_subqmod(void)
4713 uint32 r1 = dsp_convert_zero[PIMM1];
4715 uint32 res = r2 - r1;
4716 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4718 SET_ZNC_SUB(r2, r1, res);
4721 static void DSP_subqt(void)
4723 #ifdef DSP_DIS_SUBQT
4725 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);
4727 PRES = PRN - dsp_convert_zero[PIMM1];
4728 #ifdef DSP_DIS_SUBQT
4730 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4734 static void DSP_xor(void)
4738 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);
4744 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);