4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James 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...
32 // Seems alignment in loads & stores was off...
33 #define DSP_CORRECT_ALIGNMENT
34 //#define DSP_CORRECT_ALIGNMENT_STORE
37 //#define DSP_DEBUG_IRQ
38 //#define DSP_DEBUG_PL2
39 //#define DSP_DEBUG_STALL
40 //#define DSP_DEBUG_CC
41 #define NEW_SCOREBOARD
43 // Disassembly definitions
50 #define DSP_DIS_ADDQMOD
60 #define DSP_DIS_IMULTN
61 #define DSP_DIS_ILLEGAL
65 #define DSP_DIS_LOAD14I
66 #define DSP_DIS_LOAD14R
67 #define DSP_DIS_LOAD15I
68 #define DSP_DIS_LOAD15R
74 #define DSP_DIS_MOVEFA
75 #define DSP_DIS_MOVEPC // Pipeline only!
76 #define DSP_DIS_MOVETA
82 #define DSP_DIS_RESMAC
89 #define DSP_DIS_STORE14I
90 #define DSP_DIS_STORE15I
91 #define DSP_DIS_STOREB
92 #define DSP_DIS_STOREW
99 bool doDSPDis = false;
100 //bool doDSPDis = true;
135 + load_r15_indexed 284500
137 + store_r15_indexed 47416
141 + load_r14_ri 1229448
144 // Pipeline structures
146 const bool affectsScoreboard[64] =
148 true, true, true, true,
149 true, true, true, true,
150 true, true, true, true,
151 true, false, true, true,
153 true, true, false, true,
154 false, true, true, true,
155 true, true, true, true,
156 true, true, false, false,
158 true, true, true, true,
159 false, true, true, true,
160 true, true, true, true,
161 true, false, false, false,
163 true, false, false, true,
164 false, false, true, true,
165 true, false, true, true,
166 false, false, false, true
172 uint8 opcode, operand1, operand2;
173 uint32 reg1, reg2, areg1, areg2;
175 uint8 writebackRegister;
176 // General memory store...
185 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
186 #ifndef NEW_SCOREBOARD
189 uint8 scoreboard[32];
191 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
192 PipelineStage pipeline[4];
193 bool IMASKCleared = false;
195 // DSP flags (old--have to get rid of this crap)
197 #define CINT0FLAG 0x00200
198 #define CINT1FLAG 0x00400
199 #define CINT2FLAG 0x00800
200 #define CINT3FLAG 0x01000
201 #define CINT4FLAG 0x02000
202 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
203 #define CINT5FLAG 0x20000 /* DSP only */
207 #define ZERO_FLAG 0x00001
208 #define CARRY_FLAG 0x00002
209 #define NEGA_FLAG 0x00004
210 #define IMASK 0x00008
211 #define INT_ENA0 0x00010
212 #define INT_ENA1 0x00020
213 #define INT_ENA2 0x00040
214 #define INT_ENA3 0x00080
215 #define INT_ENA4 0x00100
216 #define INT_CLR0 0x00200
217 #define INT_CLR1 0x00400
218 #define INT_CLR2 0x00800
219 #define INT_CLR3 0x01000
220 #define INT_CLR4 0x02000
221 #define REGPAGE 0x04000
222 #define DMAEN 0x08000
223 #define INT_ENA5 0x10000
224 #define INT_CLR5 0x20000
228 #define DSPGO 0x00001
229 #define CPUINT 0x00002
230 #define DSPINT0 0x00004
231 #define SINGLE_STEP 0x00008
232 #define SINGLE_GO 0x00010
234 #define INT_LAT0 0x00040
235 #define INT_LAT1 0x00080
236 #define INT_LAT2 0x00100
237 #define INT_LAT3 0x00200
238 #define INT_LAT4 0x00400
239 #define BUS_HOG 0x00800
240 #define VERSION 0x0F000
241 #define INT_LAT5 0x10000
243 extern uint32 jaguar_mainRom_crc32;
245 // Is opcode 62 *really* a NOP? Seems like it...
246 static void dsp_opcode_abs(void);
247 static void dsp_opcode_add(void);
248 static void dsp_opcode_addc(void);
249 static void dsp_opcode_addq(void);
250 static void dsp_opcode_addqmod(void);
251 static void dsp_opcode_addqt(void);
252 static void dsp_opcode_and(void);
253 static void dsp_opcode_bclr(void);
254 static void dsp_opcode_bset(void);
255 static void dsp_opcode_btst(void);
256 static void dsp_opcode_cmp(void);
257 static void dsp_opcode_cmpq(void);
258 static void dsp_opcode_div(void);
259 static void dsp_opcode_imacn(void);
260 static void dsp_opcode_imult(void);
261 static void dsp_opcode_imultn(void);
262 static void dsp_opcode_jr(void);
263 static void dsp_opcode_jump(void);
264 static void dsp_opcode_load(void);
265 static void dsp_opcode_loadb(void);
266 static void dsp_opcode_loadw(void);
267 static void dsp_opcode_load_r14_indexed(void);
268 static void dsp_opcode_load_r14_ri(void);
269 static void dsp_opcode_load_r15_indexed(void);
270 static void dsp_opcode_load_r15_ri(void);
271 static void dsp_opcode_mirror(void);
272 static void dsp_opcode_mmult(void);
273 static void dsp_opcode_move(void);
274 static void dsp_opcode_movei(void);
275 static void dsp_opcode_movefa(void);
276 static void dsp_opcode_move_pc(void);
277 static void dsp_opcode_moveq(void);
278 static void dsp_opcode_moveta(void);
279 static void dsp_opcode_mtoi(void);
280 static void dsp_opcode_mult(void);
281 static void dsp_opcode_neg(void);
282 static void dsp_opcode_nop(void);
283 static void dsp_opcode_normi(void);
284 static void dsp_opcode_not(void);
285 static void dsp_opcode_or(void);
286 static void dsp_opcode_resmac(void);
287 static void dsp_opcode_ror(void);
288 static void dsp_opcode_rorq(void);
289 static void dsp_opcode_xor(void);
290 static void dsp_opcode_sat16s(void);
291 static void dsp_opcode_sat32s(void);
292 static void dsp_opcode_sh(void);
293 static void dsp_opcode_sha(void);
294 static void dsp_opcode_sharq(void);
295 static void dsp_opcode_shlq(void);
296 static void dsp_opcode_shrq(void);
297 static void dsp_opcode_store(void);
298 static void dsp_opcode_storeb(void);
299 static void dsp_opcode_storew(void);
300 static void dsp_opcode_store_r14_indexed(void);
301 static void dsp_opcode_store_r14_ri(void);
302 static void dsp_opcode_store_r15_indexed(void);
303 static void dsp_opcode_store_r15_ri(void);
304 static void dsp_opcode_sub(void);
305 static void dsp_opcode_subc(void);
306 static void dsp_opcode_subq(void);
307 static void dsp_opcode_subqmod(void);
308 static void dsp_opcode_subqt(void);
310 uint8 dsp_opcode_cycles[64] =
312 3, 3, 3, 3, 3, 3, 3, 3,
313 3, 3, 3, 3, 3, 3, 3, 3,
314 3, 3, 1, 3, 1, 18, 3, 3,
315 3, 3, 3, 3, 3, 3, 3, 3,
316 3, 3, 2, 2, 2, 2, 3, 4,
317 5, 4, 5, 6, 6, 1, 1, 1,
318 1, 2, 2, 2, 1, 1, 9, 3,
319 3, 1, 6, 6, 2, 2, 3, 3
321 //Here's a QnD kludge...
322 //This is wrong, wrong, WRONG, but it seems to work for the time being...
323 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
324 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
325 /*uint8 dsp_opcode_cycles[64] =
327 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 1,
329 1, 1, 1, 1, 1, 9, 1, 1,
330 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 2,
332 2, 2, 2, 3, 3, 1, 1, 1,
333 1, 1, 1, 1, 1, 1, 4, 1,
334 1, 1, 3, 3, 1, 1, 1, 1
337 void (* dsp_opcode[64])() =
339 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
340 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
341 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
342 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
343 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
344 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
345 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
346 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
347 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
348 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
349 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
350 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
351 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
352 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
353 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
354 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
357 uint32 dsp_opcode_use[65];
359 const char * dsp_opcode_str[65]=
361 "add", "addc", "addq", "addqt",
362 "sub", "subc", "subq", "subqt",
363 "neg", "and", "or", "xor",
364 "not", "btst", "bset", "bclr",
365 "mult", "imult", "imultn", "resmac",
366 "imacn", "div", "abs", "sh",
367 "shlq", "shrq", "sha", "sharq",
368 "ror", "rorq", "cmp", "cmpq",
369 "subqmod", "sat16s", "move", "moveq",
370 "moveta", "movefa", "movei", "loadb",
371 "loadw", "load", "sat32s", "load_r14_indexed",
372 "load_r15_indexed", "storeb", "storew", "store",
373 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
374 "jump", "jr", "mmult", "mtoi",
375 "normi", "nop", "load_r14_ri", "load_r15_ri",
376 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
381 static uint64 dsp_acc; // 40 bit register, NOT 32!
382 static uint32 dsp_remain;
383 static uint32 dsp_modulo;
384 static uint32 dsp_flags;
385 static uint32 dsp_matrix_control;
386 static uint32 dsp_pointer_to_matrix;
387 static uint32 dsp_data_organization;
389 static uint32 dsp_div_control;
390 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
391 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
392 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
394 static uint32 dsp_opcode_first_parameter;
395 static uint32 dsp_opcode_second_parameter;
397 #define DSP_RUNNING (dsp_control & 0x01)
399 #define RM dsp_reg[dsp_opcode_first_parameter]
400 #define RN dsp_reg[dsp_opcode_second_parameter]
401 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
402 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
403 #define IMM_1 dsp_opcode_first_parameter
404 #define IMM_2 dsp_opcode_second_parameter
406 #define CLR_Z (dsp_flag_z = 0)
407 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
408 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
409 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
410 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
411 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
412 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
413 #define SET_ZN(r) SET_N(r); SET_Z(r)
414 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
415 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
417 uint32 dsp_convert_zero[32] = {
418 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
419 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
421 uint8 dsp_branch_condition_table[32 * 8];
422 static uint16 mirror_table[65536];
423 static uint8 dsp_ram_8[0x2000];
425 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
427 static uint32 dsp_in_exec = 0;
428 static uint32 dsp_releaseTimeSlice_flag = 0;
433 // Comparison core vars (used only for core comparison! :-)
434 static uint64 count = 0;
435 static uint8 ram1[0x2000], ram2[0x2000];
436 static uint32 regs1[64], regs2[64];
437 static uint32 ctrl1[14], ctrl2[14];
440 // Private function prototypes
442 void DSPDumpRegisters(void);
443 void DSPDumpDisassembly(void);
444 void FlushDSPPipeline(void);
447 void dsp_reset_stats(void)
449 for(int i=0; i<65; i++)
450 dsp_opcode_use[i] = 0;
453 void DSPReleaseTimeslice(void)
455 //This does absolutely nothing!!! !!! FIX !!!
456 dsp_releaseTimeSlice_flag = 1;
459 void dsp_build_branch_condition_table(void)
461 // Fill in the mirror table
462 for(int i=0; i<65536; i++)
464 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
465 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
466 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
467 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
468 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
469 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
470 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
471 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
474 // Fill in the condition table
475 for(int i=0; i<8; i++)
477 for(int j=0; j<32; j++)
481 if ((j & 1) && (i & ZERO_FLAG))
484 if ((j & 2) && (!(i & ZERO_FLAG)))
487 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
490 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
493 dsp_branch_condition_table[i * 32 + j] = result;
498 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
500 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
501 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
503 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
506 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
508 if (offset==0xF1CFE0)
511 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
512 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
514 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
516 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
518 if ((offset&0x03)==0)
521 if ((offset&0x03)==1)
522 return((data>>16)&0xff);
524 if ((offset&0x03)==2)
525 return((data>>8)&0xff);
527 if ((offset&0x03)==3)
531 return JaguarReadByte(offset, who);
534 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
536 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
537 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
539 offset &= 0xFFFFFFFE;
541 /* if (jaguar_mainRom_crc32==0xa74a97cd)
543 if (offset==0xF1A114) return(0x0000);
544 if (offset==0xF1A116) return(0x0000);
545 if (offset==0xF1B000) return(0x1234);
546 if (offset==0xF1B002) return(0x5678);
549 if (jaguar_mainRom_crc32==0x7ae20823)
551 if (offset==0xF1B9D8) return(0x0000);
552 if (offset==0xF1B9Da) return(0x0000);
553 if (offset==0xF1B2C0) return(0x0000);
554 if (offset==0xF1B2C2) return(0x0000);
557 // pour permettre � wolfenstein 3d de tourner sans le dsp
558 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
562 // pour permettre � nba jam de tourner sans le dsp
563 /* if (jaguar_mainRom_crc32==0x4faddb18)
565 if (offset==0xf1b2c0) return(0);
566 if (offset==0xf1b2c2) return(0);
567 if (offset==0xf1b240) return(0);
568 if (offset==0xf1b242) return(0);
569 if (offset==0xF1B340) return(0);
570 if (offset==0xF1B342) return(0);
571 if (offset==0xF1BAD8) return(0);
572 if (offset==0xF1BADA) return(0);
573 if (offset==0xF1B040) return(0);
574 if (offset==0xF1B042) return(0);
575 if (offset==0xF1B0C0) return(0);
576 if (offset==0xF1B0C2) return(0);
577 if (offset==0xF1B140) return(0);
578 if (offset==0xF1B142) return(0);
579 if (offset==0xF1B1C0) return(0);
580 if (offset==0xF1B1C2) return(0);
583 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
585 offset -= DSP_WORK_RAM_BASE;
586 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
588 return GET16(dsp_ram_8, offset);
590 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
592 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
595 return data & 0xFFFF;
600 return JaguarReadWord(offset, who);
603 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
605 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
606 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
609 offset &= 0xFFFFFFFC;
610 /*if (offset == 0xF1BCF4)
612 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));
613 DSPDumpDisassembly();
615 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
617 offset -= DSP_WORK_RAM_BASE;
618 return GET32(dsp_ram_8, offset);
620 //NOTE: Didn't return DSP_ACCUM!!!
621 //Mebbe it's not 'spose to! Yes, it is!
622 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
627 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
628 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
629 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
631 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
632 return dsp_flags & 0xFFFFC1FF;
633 case 0x04: return dsp_matrix_control;
634 case 0x08: return dsp_pointer_to_matrix;
635 case 0x0C: return dsp_data_organization;
636 case 0x10: return dsp_pc;
637 case 0x14: return dsp_control;
638 case 0x18: return dsp_modulo;
639 case 0x1C: return dsp_remain;
641 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
643 // unaligned long read-- !!! FIX !!!
647 return JaguarReadLong(offset, who);
650 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
652 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
653 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
655 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
657 offset -= DSP_WORK_RAM_BASE;
658 dsp_ram_8[offset] = data;
659 //This is rather stupid! !!! FIX !!!
660 /* if (dsp_in_exec == 0)
662 m68k_end_timeslice();
663 dsp_releaseTimeslice();
667 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
669 uint32 reg = offset & 0x1C;
670 int bytenum = offset & 0x03;
672 if ((reg >= 0x1C) && (reg <= 0x1F))
673 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
676 //This looks funky. !!! FIX !!!
677 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
678 bytenum = 3 - bytenum; // convention motorola !!!
679 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
680 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
684 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
685 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
686 JaguarWriteByte(offset, data, who);
689 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
691 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
692 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
693 offset &= 0xFFFFFFFE;
694 /*if (offset == 0xF1BCF4)
696 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
698 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
699 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
701 /*if (offset == 0xF1B2F4)
703 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
705 offset -= DSP_WORK_RAM_BASE;
706 dsp_ram_8[offset] = data >> 8;
707 dsp_ram_8[offset+1] = data & 0xFF;
708 //This is rather stupid! !!! FIX !!!
709 /* if (dsp_in_exec == 0)
711 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
712 m68k_end_timeslice();
713 dsp_releaseTimeslice();
717 SET16(ram1, offset, data),
718 SET16(ram2, offset, data);
723 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
725 if ((offset & 0x1C) == 0x1C)
728 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
730 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
734 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
736 old_data = (old_data&0xffff0000)|(data&0xffff);
738 old_data = (old_data&0xffff)|((data&0xffff)<<16);
739 DSPWriteLong(offset & 0xffffffc, old_data, who);
744 JaguarWriteWord(offset, data, who);
747 //bool badWrite = false;
748 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
750 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
751 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
753 offset &= 0xFFFFFFFC;
754 /*if (offset == 0xF1BCF4)
756 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
758 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
759 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
761 /*if (offset == 0xF1BE2C)
763 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
765 offset -= DSP_WORK_RAM_BASE;
766 SET32(dsp_ram_8, offset, data);
769 SET32(ram1, offset, data),
770 SET32(ram2, offset, data);
775 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
783 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
785 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
786 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
788 dsp_flag_z = dsp_flags & 0x01;
789 dsp_flag_c = (dsp_flags >> 1) & 0x01;
790 dsp_flag_n = (dsp_flags >> 2) & 0x01;
791 DSPUpdateRegisterBanks();
792 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
793 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
795 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
796 // It can be timed to anything really, anything that writes to L/RTXD at a regular
797 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
798 // interrupt, so that's what we check for here. Just know that this approach
799 // can be easily fooled!
800 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
803 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
804 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
805 // So, while this works, it's a by-product of the lame way in which audio is currently
806 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
807 // go away of its own accord. :-P
808 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
809 // weird is going on here...
810 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
811 // So subsequent interrupts come into the chip, but they're never serviced but the
812 // I2S subsystem keeps going.
813 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
814 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
815 // It seems that it's only stable for values of SCLK <= 9.
817 if (data & INT_ENA1) // I2S interrupt
819 int freq = GetCalculatedFrequency();
820 //This happens too often to be useful...
821 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
822 DACSetNewFrequency(freq);
824 else if (data & INT_ENA2) // TIMER 0 interrupt
826 int freq = JERRYGetPIT1Frequency();
827 //This happens too often to be useful...
828 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
829 DACSetNewFrequency(freq);
832 /* if (IMASKCleared) // If IMASK was cleared,
835 WriteLog("DSP: Finished interrupt.\n");
837 DSPHandleIRQs(); // see if any other interrupts need servicing!
842 if (/*4-8, 16*/data & 0x101F0)
843 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
844 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
845 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
846 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
847 /*if (data & 0x00020) // CD BIOS DSP code...
849 //001AC1BA: movea.l #$1AC200, A0
850 //001AC1C0: move.l #$1AC68C, D0
853 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
854 uint32 j = 0xF1B97C;//0x1AC200;
855 while (j <= 0xF1BE08)//0x1AC68C)
858 j += dasmjag(JAGUAR_DSP, buffer, j);
859 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
860 WriteLog("\t%08X: %s\n", oldj, buffer);
867 dsp_matrix_control = data;
870 // According to JTRM, only lines 2-11 are addressable, the rest being
871 // hardwired to $F1Bxxx.
872 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
875 dsp_data_organization = data;
880 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
885 ctrl1[0] = ctrl2[0] = data;
892 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
894 bool wasRunning = DSP_RUNNING;
895 // uint32 dsp_was_running = DSP_RUNNING;
896 // Check for DSP -> CPU interrupt
900 WriteLog("DSP: DSP -> CPU interrupt\n");
903 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
904 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
905 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
907 JERRYSetPendingIRQ(IRQ2_DSP);
908 DSPReleaseTimeslice();
909 m68k_set_irq(2); // Set 68000 IPL 2...
913 // Check for CPU -> DSP interrupt
917 WriteLog("DSP: CPU -> DSP interrupt\n");
919 m68k_end_timeslice();
920 DSPReleaseTimeslice();
921 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
925 if (data & SINGLE_STEP)
927 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
930 // Protect writes to VERSION and the interrupt latches...
931 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
932 dsp_control = (dsp_control & mask) | (data & ~mask);
936 ctrl1[8] = ctrl2[8] = dsp_control;
940 // if dsp wasn't running but is now running
941 // execute a few cycles
942 //This is just plain wrong, wrong, WRONG!
943 #ifndef DSP_SINGLE_STEPPING
944 /* if (!dsp_was_running && DSP_RUNNING)
949 //This is WRONG! !!! FIX !!!
950 if (dsp_control & 0x18)
955 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
957 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
960 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
961 // !!! FIX !!! [DONE]
965 m68k_end_timeslice();
967 DSPReleaseTimeslice();
971 //DSPDumpDisassembly();
979 dsp_div_control = data;
981 // default: // unaligned long read
987 //We don't have to break this up like this! We CAN do 32 bit writes!
988 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
989 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
990 //if (offset > 0xF1FFFF)
992 JaguarWriteLong(offset, data, who);
996 // Update the DSP register file pointers depending on REGPAGE bit
998 void DSPUpdateRegisterBanks(void)
1000 int bank = (dsp_flags & REGPAGE);
1002 if (dsp_flags & IMASK)
1003 bank = 0; // IMASK forces main bank to be bank 0
1006 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1008 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1012 // Check for and handle any asserted DSP IRQs
1014 void DSPHandleIRQs(void)
1016 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1019 // Get the active interrupt bits (latches) & interrupt mask (enables)
1020 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1021 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1023 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1026 if (!bits) // Bail if nothing is enabled
1029 int which = 0; // Determine which interrupt
1043 #ifdef DSP_DEBUG_IRQ
1044 WriteLog("DSP: Generating interrupt #%i...", which);
1047 //if (which == 0) doDSPDis = true;
1049 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1050 // directly into the pipeline, it has the side effect of ensuring that the
1051 // instruction interrupted also gets to do its writeback. We simulate that
1053 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1055 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1056 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1058 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1059 scoreboard[pipeline[plPtrWrite].operand2] = false;
1061 //This should be execute (or should it?--not sure now!)
1062 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1063 //and what just executed is now in the Write position...). So why didn't it do the
1064 //writeback into register 0?
1065 #ifdef DSP_DEBUG_IRQ
1066 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1067 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]);
1068 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]);
1069 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]);
1071 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1073 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1075 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1076 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1079 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1080 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1081 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1082 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1084 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1088 #ifndef NEW_SCOREBOARD
1089 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1090 scoreboard[pipeline[plPtrWrite].operand2] = false;
1092 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1093 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1094 if (scoreboard[pipeline[plPtrWrite].operand2])
1095 scoreboard[pipeline[plPtrWrite].operand2]--;
1102 ctrl2[4] = dsp_flags;
1105 DSPUpdateRegisterBanks();
1106 #ifdef DSP_DEBUG_IRQ
1107 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1108 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]);
1111 // subqt #4,r31 ; pre-decrement stack pointer
1112 // move pc,r30 ; address of interrupted code
1113 // store r30,(r31) ; store return address
1120 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1121 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1122 //It missed the place that it was supposed to come back to, so this is WRONG!
1124 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1126 // R -> baz (<- PC points here)
1127 // E -> bar (when it should point here!)
1130 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1131 // which means (assuming they're all 2 bytes long) that the code below will come back on
1132 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1133 // instruction stream...
1135 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1136 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1139 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1143 // movei #service_address,r30 ; pointer to ISR entry
1144 // jump (r30) ; jump to ISR
1146 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1149 ctrl2[0] = regs2[30] = dsp_pc;
1156 // Non-pipelined version...
1158 void DSPHandleIRQsNP(void)
1162 memcpy(dsp_ram_8, ram1, 0x2000);
1163 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1164 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1167 dsp_remain = ctrl1[2];
1168 dsp_modulo = ctrl1[3];
1169 dsp_flags = ctrl1[4];
1170 dsp_matrix_control = ctrl1[5];
1171 dsp_pointer_to_matrix = ctrl1[6];
1172 dsp_data_organization = ctrl1[7];
1173 dsp_control = ctrl1[8];
1174 dsp_div_control = ctrl1[9];
1175 IMASKCleared = ctrl1[10];
1176 dsp_flag_z = ctrl1[11];
1177 dsp_flag_n = ctrl1[12];
1178 dsp_flag_c = ctrl1[13];
1179 DSPUpdateRegisterBanks();
1182 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1185 // Get the active interrupt bits (latches) & interrupt mask (enables)
1186 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1187 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1189 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1192 if (!bits) // Bail if nothing is enabled
1195 int which = 0; // Determine which interrupt
1209 #ifdef DSP_DEBUG_IRQ
1210 WriteLog("DSP: Generating interrupt #%i...", which);
1216 ctrl1[4] = dsp_flags;
1219 DSPUpdateRegisterBanks();
1220 #ifdef DSP_DEBUG_IRQ
1221 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1224 // subqt #4,r31 ; pre-decrement stack pointer
1225 // move pc,r30 ; address of interrupted code
1226 // store r30,(r31) ; store return address
1233 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1236 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1240 // movei #service_address,r30 ; pointer to ISR entry
1241 // jump (r30) ; jump to ISR
1243 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1246 ctrl1[0] = regs1[30] = dsp_pc;
1252 // Set the specified DSP IRQ line to a given state
1254 void DSPSetIRQLine(int irqline, int state)
1256 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1257 uint32 mask = INT_LAT0 << irqline;
1258 dsp_control &= ~mask; // Clear the latch bit
1261 ctrl1[8] = ctrl2[8] = dsp_control;
1267 dsp_control |= mask; // Set the latch bit
1271 ctrl1[8] = ctrl2[8] = dsp_control;
1277 // Not sure if this is correct behavior, but according to JTRM,
1278 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1279 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1280 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1283 bool DSPIsRunning(void)
1285 return (DSP_RUNNING ? true : false);
1290 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1291 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1292 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1294 dsp_build_branch_condition_table();
1296 srand(time(NULL)); // For randomizing local RAM
1301 dsp_pc = 0x00F1B000;
1302 dsp_acc = 0x00000000;
1303 dsp_remain = 0x00000000;
1304 dsp_modulo = 0xFFFFFFFF;
1305 dsp_flags = 0x00040000;
1306 dsp_matrix_control = 0x00000000;
1307 dsp_pointer_to_matrix = 0x00000000;
1308 dsp_data_organization = 0xFFFFFFFF;
1309 dsp_control = 0x00002000; // Report DSP version 2
1310 dsp_div_control = 0x00000000;
1313 dsp_reg = dsp_reg_bank_0;
1314 dsp_alternate_reg = dsp_reg_bank_1;
1316 for(int i=0; i<32; i++)
1317 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1320 IMASKCleared = false;
1323 // memset(dsp_ram_8, 0xFF, 0x2000);
1324 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1325 for(uint32 i=0; i<8192; i+=4)
1327 *((uint32 *)(&dsp_ram_8[i])) = rand();
1331 void DSPDumpDisassembly(void)
1335 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1336 uint32 j = 0xF1B000;
1338 while (j <= 0xF1CFFF)
1341 j += dasmjag(JAGUAR_DSP, buffer, j);
1342 WriteLog("\t%08X: %s\n", oldj, buffer);
1346 void DSPDumpRegisters(void)
1348 //Shoud add modulus, etc to dump here...
1349 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1350 WriteLog("\nRegisters bank 0\n");
1352 for(int j=0; j<8; j++)
1354 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1355 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1356 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1357 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1358 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1361 WriteLog("Registers bank 1\n");
1363 for(int j=0; j<8; j++)
1365 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1366 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1367 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1368 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1369 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1376 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1377 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1379 // get the active interrupt bits
1380 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1381 // get the interrupt mask
1382 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1384 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1385 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1386 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1387 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1388 WriteLog("\nRegisters bank 0\n");
1390 for(int j=0; j<8; j++)
1392 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1393 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1394 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1395 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1396 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1399 WriteLog("\nRegisters bank 1\n");
1403 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1404 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1405 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1406 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1407 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1412 static char buffer[512];
1413 j = DSP_WORK_RAM_BASE;
1415 while (j <= 0xF1CFFF)
1418 j += dasmjag(JAGUAR_DSP, buffer, j);
1419 WriteLog("\t%08X: %s\n", oldj, buffer);
1422 WriteLog("DSP opcodes use:\n");
1426 if (dsp_opcode_use[i])
1427 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1430 // memory_free(dsp_ram_8);
1431 // memory_free(dsp_reg_bank_0);
1432 // memory_free(dsp_reg_bank_1);
1433 // if (dsp_branch_condition_table)
1434 // free(dsp_branch_condition_table);
1436 // if (mirror_table)
1437 // free(mirror_table);
1443 // DSP comparison core...
1446 static uint16 lastExec;
1447 void DSPExecComp(int32 cycles)
1449 while (cycles > 0 && DSP_RUNNING)
1451 // Load up vars for non-pipelined core
1452 memcpy(dsp_ram_8, ram1, 0x2000);
1453 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1454 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1457 dsp_remain = ctrl1[2];
1458 dsp_modulo = ctrl1[3];
1459 dsp_flags = ctrl1[4];
1460 dsp_matrix_control = ctrl1[5];
1461 dsp_pointer_to_matrix = ctrl1[6];
1462 dsp_data_organization = ctrl1[7];
1463 dsp_control = ctrl1[8];
1464 dsp_div_control = ctrl1[9];
1465 IMASKCleared = ctrl1[10];
1466 dsp_flag_z = ctrl1[11];
1467 dsp_flag_n = ctrl1[12];
1468 dsp_flag_c = ctrl1[13];
1469 DSPUpdateRegisterBanks();
1471 // Decrement cycles based on non-pipelined core...
1472 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1473 cycles -= dsp_opcode_cycles[instr1 >> 10];
1475 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1476 DSPExec(1); // Do *one* instruction
1479 memcpy(ram1, dsp_ram_8, 0x2000);
1480 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1481 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1484 ctrl1[2] = dsp_remain;
1485 ctrl1[3] = dsp_modulo;
1486 ctrl1[4] = dsp_flags;
1487 ctrl1[5] = dsp_matrix_control;
1488 ctrl1[6] = dsp_pointer_to_matrix;
1489 ctrl1[7] = dsp_data_organization;
1490 ctrl1[8] = dsp_control;
1491 ctrl1[9] = dsp_div_control;
1492 ctrl1[10] = IMASKCleared;
1493 ctrl1[11] = dsp_flag_z;
1494 ctrl1[12] = dsp_flag_n;
1495 ctrl1[13] = dsp_flag_c;
1497 // Load up vars for pipelined core
1498 memcpy(dsp_ram_8, ram2, 0x2000);
1499 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1500 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1503 dsp_remain = ctrl2[2];
1504 dsp_modulo = ctrl2[3];
1505 dsp_flags = ctrl2[4];
1506 dsp_matrix_control = ctrl2[5];
1507 dsp_pointer_to_matrix = ctrl2[6];
1508 dsp_data_organization = ctrl2[7];
1509 dsp_control = ctrl2[8];
1510 dsp_div_control = ctrl2[9];
1511 IMASKCleared = ctrl2[10];
1512 dsp_flag_z = ctrl2[11];
1513 dsp_flag_n = ctrl2[12];
1514 dsp_flag_c = ctrl2[13];
1515 DSPUpdateRegisterBanks();
1517 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1518 DSPExecP2(1); // Do *one* instruction
1521 memcpy(ram2, dsp_ram_8, 0x2000);
1522 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1523 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1526 ctrl2[2] = dsp_remain;
1527 ctrl2[3] = dsp_modulo;
1528 ctrl2[4] = dsp_flags;
1529 ctrl2[5] = dsp_matrix_control;
1530 ctrl2[6] = dsp_pointer_to_matrix;
1531 ctrl2[7] = dsp_data_organization;
1532 ctrl2[8] = dsp_control;
1533 ctrl2[9] = dsp_div_control;
1534 ctrl2[10] = IMASKCleared;
1535 ctrl2[11] = dsp_flag_z;
1536 ctrl2[12] = dsp_flag_n;
1537 ctrl2[13] = dsp_flag_c;
1539 if (instr1 != lastExec)
1541 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1543 // 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));
1544 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1545 // if (ctrl1[0] < ppc) // P ran ahead of NP
1546 //How to test this crap???
1549 DSPExecP2(1); // Do one more instruction
1552 memcpy(ram2, dsp_ram_8, 0x2000);
1553 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1554 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1557 ctrl2[2] = dsp_remain;
1558 ctrl2[3] = dsp_modulo;
1559 ctrl2[4] = dsp_flags;
1560 ctrl2[5] = dsp_matrix_control;
1561 ctrl2[6] = dsp_pointer_to_matrix;
1562 ctrl2[7] = dsp_data_organization;
1563 ctrl2[8] = dsp_control;
1564 ctrl2[9] = dsp_div_control;
1565 ctrl2[10] = IMASKCleared;
1566 ctrl2[11] = dsp_flag_z;
1567 ctrl2[12] = dsp_flag_n;
1568 ctrl2[13] = dsp_flag_c;
1570 // else // NP ran ahead of P
1571 if (instr1 != lastExec) // Must be the other way...
1574 // Load up vars for non-pipelined core
1575 memcpy(dsp_ram_8, ram1, 0x2000);
1576 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1577 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1580 dsp_remain = ctrl1[2];
1581 dsp_modulo = ctrl1[3];
1582 dsp_flags = ctrl1[4];
1583 dsp_matrix_control = ctrl1[5];
1584 dsp_pointer_to_matrix = ctrl1[6];
1585 dsp_data_organization = ctrl1[7];
1586 dsp_control = ctrl1[8];
1587 dsp_div_control = ctrl1[9];
1588 IMASKCleared = ctrl1[10];
1589 dsp_flag_z = ctrl1[11];
1590 dsp_flag_n = ctrl1[12];
1591 dsp_flag_c = ctrl1[13];
1592 DSPUpdateRegisterBanks();
1594 for(int k=0; k<2; k++)
1596 // Decrement cycles based on non-pipelined core...
1597 instr1 = DSPReadWord(dsp_pc, DSP);
1598 cycles -= dsp_opcode_cycles[instr1 >> 10];
1600 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1601 DSPExec(1); // Do *one* instruction
1605 memcpy(ram1, dsp_ram_8, 0x2000);
1606 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1607 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1610 ctrl1[2] = dsp_remain;
1611 ctrl1[3] = dsp_modulo;
1612 ctrl1[4] = dsp_flags;
1613 ctrl1[5] = dsp_matrix_control;
1614 ctrl1[6] = dsp_pointer_to_matrix;
1615 ctrl1[7] = dsp_data_organization;
1616 ctrl1[8] = dsp_control;
1617 ctrl1[9] = dsp_div_control;
1618 ctrl1[10] = IMASKCleared;
1619 ctrl1[11] = dsp_flag_z;
1620 ctrl1[12] = dsp_flag_n;
1621 ctrl1[13] = dsp_flag_c;
1625 if (instr1 != lastExec)
1627 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1629 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1630 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1643 // DSP execution core
1645 //static bool R20Set = false, tripwire = false;
1646 //static uint32 pcQueue[32], ptrPCQ = 0;
1647 void DSPExec(int32 cycles)
1649 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1650 dsp_check_if_i2s_interrupt_needed();*/
1652 #ifdef DSP_SINGLE_STEPPING
1653 if (dsp_control & 0x18)
1656 dsp_control &= ~0x10;
1659 //There is *no* good reason to do this here!
1661 dsp_releaseTimeSlice_flag = 0;
1664 while (cycles > 0 && DSP_RUNNING)
1666 /*extern uint32 totalFrames;
1667 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1668 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1669 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1671 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1674 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1676 if (dsp_pc == 0xF1B092)
1677 doDSPDis = false;//*/
1678 /*if (dsp_pc == 0xF1B140)
1679 doDSPDis = true;//*/
1681 if (IMASKCleared) // If IMASK was cleared,
1683 #ifdef DSP_DEBUG_IRQ
1684 WriteLog("DSP: Finished interrupt.\n");
1686 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1687 IMASKCleared = false;
1692 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1693 for(int i=0; i<80; i+=4)
1694 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1697 /*if (dsp_pc == 0xF1B55E)
1699 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1701 /*if (dsp_pc == 0xF1B7D2) // Start here???
1703 pcQueue[ptrPCQ++] = dsp_pc;
1705 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1706 uint32 index = opcode >> 10;
1707 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1708 dsp_opcode_second_parameter = opcode & 0x1F;
1710 dsp_opcode[index]();
1711 dsp_opcode_use[index]++;
1712 cycles -= dsp_opcode_cycles[index];
1713 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1715 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1718 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1720 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1722 DSPDumpDisassembly();
1725 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1728 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1731 WriteLog("\nBacktrace:\n");
1732 for(int i=0; i<32; i++)
1734 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1735 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1745 // DSP opcode handlers
1748 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1749 // can cause trouble because an interrupt can occur *before* the instruction following the
1750 // jump can execute... !!! FIX !!!
1751 static void dsp_opcode_jump(void)
1754 const char * condition[32] =
1755 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1756 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1757 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1758 "???", "???", "???", "F" };
1760 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);
1763 /* dsp_flag_c=dsp_flag_c?1:0;
1764 dsp_flag_z=dsp_flag_z?1:0;
1765 dsp_flag_n=dsp_flag_n?1:0;*/
1766 // KLUDGE: Used by BRANCH_CONDITION
1767 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1769 if (BRANCH_CONDITION(IMM_2))
1773 WriteLog("Branched!\n");
1775 uint32 delayed_pc = RM;
1777 dsp_pc = delayed_pc;
1782 WriteLog("Branch NOT taken.\n");
1786 static void dsp_opcode_jr(void)
1789 const char * condition[32] =
1790 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1791 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1792 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1793 "???", "???", "???", "F" };
1795 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);
1798 /* dsp_flag_c=dsp_flag_c?1:0;
1799 dsp_flag_z=dsp_flag_z?1:0;
1800 dsp_flag_n=dsp_flag_n?1:0;*/
1801 // KLUDGE: Used by BRANCH_CONDITION
1802 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1804 if (BRANCH_CONDITION(IMM_2))
1808 WriteLog("Branched!\n");
1810 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1811 int32 delayed_pc = dsp_pc + (offset * 2);
1813 dsp_pc = delayed_pc;
1818 WriteLog("Branch NOT taken.\n");
1822 static void dsp_opcode_add(void)
1826 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);
1828 uint32 res = RN + RM;
1829 SET_ZNC_ADD(RN, RM, res);
1833 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);
1837 static void dsp_opcode_addc(void)
1841 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);
1843 uint32 res = RN + RM + dsp_flag_c;
1844 uint32 carry = dsp_flag_c;
1845 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1846 SET_ZNC_ADD(RN + carry, RM, res);
1847 // SET_ZNC_ADD(RN, RM + carry, res);
1851 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);
1855 static void dsp_opcode_addq(void)
1859 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);
1861 uint32 r1 = dsp_convert_zero[IMM_1];
1862 uint32 res = RN + r1;
1863 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1867 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1871 static void dsp_opcode_sub(void)
1875 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);
1877 uint32 res = RN - RM;
1878 SET_ZNC_SUB(RN, RM, res);
1882 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);
1886 static void dsp_opcode_subc(void)
1890 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);
1892 uint32 res = RN - RM - dsp_flag_c;
1893 uint32 borrow = dsp_flag_c;
1894 SET_ZNC_SUB(RN - borrow, RM, res);
1898 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);
1902 static void dsp_opcode_subq(void)
1906 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);
1908 uint32 r1 = dsp_convert_zero[IMM_1];
1909 uint32 res = RN - r1;
1910 SET_ZNC_SUB(RN, r1, res);
1914 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1918 static void dsp_opcode_cmp(void)
1922 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);
1924 uint32 res = RN - RM;
1925 SET_ZNC_SUB(RN, RM, res);
1928 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1932 static void dsp_opcode_cmpq(void)
1934 static int32 sqtable[32] =
1935 { 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 };
1938 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);
1940 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1941 uint32 res = RN - r1;
1942 SET_ZNC_SUB(RN, r1, res);
1945 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1949 static void dsp_opcode_and(void)
1953 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);
1959 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);
1963 static void dsp_opcode_or(void)
1967 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);
1973 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);
1977 static void dsp_opcode_xor(void)
1981 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);
1987 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);
1991 static void dsp_opcode_not(void)
1995 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);
2001 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2005 static void dsp_opcode_move_pc(void)
2010 static void dsp_opcode_store_r14_indexed(void)
2012 #ifdef DSP_DIS_STORE14I
2014 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));
2016 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2017 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2019 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2023 static void dsp_opcode_store_r15_indexed(void)
2025 #ifdef DSP_DIS_STORE15I
2027 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));
2029 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2030 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2032 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2036 static void dsp_opcode_load_r14_ri(void)
2038 #ifdef DSP_DIS_LOAD14R
2040 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);
2042 #ifdef DSP_CORRECT_ALIGNMENT
2043 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2045 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2047 #ifdef DSP_DIS_LOAD14R
2049 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2053 static void dsp_opcode_load_r15_ri(void)
2055 #ifdef DSP_DIS_LOAD15R
2057 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);
2059 #ifdef DSP_CORRECT_ALIGNMENT
2060 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2062 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2064 #ifdef DSP_DIS_LOAD15R
2066 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2070 static void dsp_opcode_store_r14_ri(void)
2072 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2075 static void dsp_opcode_store_r15_ri(void)
2077 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2080 static void dsp_opcode_nop(void)
2084 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2088 static void dsp_opcode_storeb(void)
2090 #ifdef DSP_DIS_STOREB
2092 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);
2094 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2095 DSPWriteLong(RM, RN & 0xFF, DSP);
2097 JaguarWriteByte(RM, RN, DSP);
2100 static void dsp_opcode_storew(void)
2102 #ifdef DSP_DIS_STOREW
2104 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);
2106 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2107 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2108 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2110 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2112 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2113 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2115 JaguarWriteWord(RM, RN, DSP);
2119 static void dsp_opcode_store(void)
2121 #ifdef DSP_DIS_STORE
2123 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);
2125 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2126 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2128 DSPWriteLong(RM, RN, DSP);
2132 static void dsp_opcode_loadb(void)
2134 #ifdef DSP_DIS_LOADB
2136 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);
2138 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2139 RN = DSPReadLong(RM, DSP) & 0xFF;
2141 RN = JaguarReadByte(RM, DSP);
2142 #ifdef DSP_DIS_LOADB
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_loadw(void)
2150 #ifdef DSP_DIS_LOADW
2152 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);
2154 #ifdef DSP_CORRECT_ALIGNMENT
2155 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2156 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2158 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2160 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2161 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2163 RN = JaguarReadWord(RM, DSP);
2165 #ifdef DSP_DIS_LOADW
2167 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2171 static void dsp_opcode_load(void)
2175 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);
2177 #ifdef DSP_CORRECT_ALIGNMENT
2178 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2180 RN = DSPReadLong(RM, DSP);
2184 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2188 static void dsp_opcode_load_r14_indexed(void)
2190 #ifdef DSP_DIS_LOAD14I
2192 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);
2194 #ifdef DSP_CORRECT_ALIGNMENT
2195 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2197 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2199 #ifdef DSP_DIS_LOAD14I
2201 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2205 static void dsp_opcode_load_r15_indexed(void)
2207 #ifdef DSP_DIS_LOAD15I
2209 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);
2211 #ifdef DSP_CORRECT_ALIGNMENT
2212 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2214 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2216 #ifdef DSP_DIS_LOAD15I
2218 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2222 static void dsp_opcode_movei(void)
2224 #ifdef DSP_DIS_MOVEI
2226 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);
2228 // This instruction is followed by 32-bit value in LSW / MSW format...
2229 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2231 #ifdef DSP_DIS_MOVEI
2233 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2237 static void dsp_opcode_moveta(void)
2239 #ifdef DSP_DIS_MOVETA
2241 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);
2244 #ifdef DSP_DIS_MOVETA
2246 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);
2250 static void dsp_opcode_movefa(void)
2252 #ifdef DSP_DIS_MOVEFA
2254 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);
2257 #ifdef DSP_DIS_MOVEFA
2259 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);
2263 static void dsp_opcode_move(void)
2267 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);
2272 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);
2276 static void dsp_opcode_moveq(void)
2278 #ifdef DSP_DIS_MOVEQ
2280 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);
2283 #ifdef DSP_DIS_MOVEQ
2285 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2289 static void dsp_opcode_resmac(void)
2291 #ifdef DSP_DIS_RESMAC
2293 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));
2295 RN = (uint32)dsp_acc;
2296 #ifdef DSP_DIS_RESMAC
2298 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2302 static void dsp_opcode_imult(void)
2304 #ifdef DSP_DIS_IMULT
2306 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);
2308 RN = (int16)RN * (int16)RM;
2310 #ifdef DSP_DIS_IMULT
2312 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);
2316 static void dsp_opcode_mult(void)
2320 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);
2322 RN = (uint16)RM * (uint16)RN;
2326 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);
2330 static void dsp_opcode_bclr(void)
2334 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);
2336 uint32 res = RN & ~(1 << IMM_1);
2341 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2345 static void dsp_opcode_btst(void)
2349 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);
2351 dsp_flag_z = (~RN >> IMM_1) & 1;
2354 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2358 static void dsp_opcode_bset(void)
2362 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);
2364 uint32 res = RN | (1 << IMM_1);
2369 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2373 static void dsp_opcode_subqt(void)
2375 #ifdef DSP_DIS_SUBQT
2377 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);
2379 RN -= dsp_convert_zero[IMM_1];
2380 #ifdef DSP_DIS_SUBQT
2382 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2386 static void dsp_opcode_addqt(void)
2388 #ifdef DSP_DIS_ADDQT
2390 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);
2392 RN += dsp_convert_zero[IMM_1];
2393 #ifdef DSP_DIS_ADDQT
2395 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2399 static void dsp_opcode_imacn(void)
2401 #ifdef DSP_DIS_IMACN
2403 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);
2405 int32 res = (int16)RM * (int16)RN;
2406 dsp_acc += (int64)res;
2407 //Should we AND the result to fit into 40 bits here???
2408 #ifdef DSP_DIS_IMACN
2410 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));
2414 static void dsp_opcode_mtoi(void)
2416 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2420 static void dsp_opcode_normi(void)
2427 while ((_Rm & 0xffc00000) == 0)
2432 while ((_Rm & 0xff800000) != 0)
2442 static void dsp_opcode_mmult(void)
2444 int count = dsp_matrix_control&0x0f;
2445 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2449 if (!(dsp_matrix_control & 0x10))
2451 for (int i = 0; i < count; i++)
2455 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2457 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2458 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2465 for (int i = 0; i < count; i++)
2469 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2471 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2472 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2477 RN = res = (int32)accum;
2479 //NOTE: The flags are set based upon the last add/multiply done...
2483 static void dsp_opcode_abs(void)
2487 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);
2492 if (_Rn == 0x80000000)
2496 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2497 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
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_div(void)
2513 if (dsp_div_control & 1)
2515 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2516 if (dsp_remain&0x80000000)
2518 RN = (((uint64)_Rn) << 16) / _Rm;
2522 dsp_remain = _Rn % _Rm;
2523 if (dsp_remain&0x80000000)
2532 static void dsp_opcode_imultn(void)
2534 #ifdef DSP_DIS_IMULTN
2536 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);
2538 // This is OK, since this multiply won't overflow 32 bits...
2539 int32 res = (int32)((int16)RN * (int16)RM);
2540 dsp_acc = (int64)res;
2542 #ifdef DSP_DIS_IMULTN
2544 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));
2548 static void dsp_opcode_neg(void)
2552 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);
2555 SET_ZNC_SUB(0, RN, res);
2559 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2563 static void dsp_opcode_shlq(void)
2567 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);
2569 int32 r1 = 32 - IMM_1;
2570 uint32 res = RN << r1;
2571 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2575 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2579 static void dsp_opcode_shrq(void)
2583 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);
2585 int32 r1 = dsp_convert_zero[IMM_1];
2586 uint32 res = RN >> r1;
2587 SET_ZN(res); dsp_flag_c = RN & 1;
2591 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2595 static void dsp_opcode_ror(void)
2599 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);
2601 uint32 r1 = RM & 0x1F;
2602 uint32 res = (RN >> r1) | (RN << (32 - r1));
2603 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2607 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);
2611 static void dsp_opcode_rorq(void)
2615 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);
2617 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2619 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2621 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2624 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2628 static void dsp_opcode_sha(void)
2630 int32 sRm=(int32)RM;
2636 if (shift>=32) shift=32;
2637 dsp_flag_c=(_Rn&0x80000000)>>31;
2647 if (shift>=32) shift=32;
2651 _Rn=((int32)_Rn)>>1;
2659 static void dsp_opcode_sharq(void)
2661 #ifdef DSP_DIS_SHARQ
2663 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);
2665 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2666 SET_ZN(res); dsp_flag_c = RN & 0x01;
2668 #ifdef DSP_DIS_SHARQ
2670 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2674 static void dsp_opcode_sh(void)
2676 int32 sRm=(int32)RM;
2681 uint32 shift=(-sRm);
2682 if (shift>=32) shift=32;
2683 dsp_flag_c=(_Rn&0x80000000)>>31;
2693 if (shift>=32) shift=32;
2705 void dsp_opcode_addqmod(void)
2707 #ifdef DSP_DIS_ADDQMOD
2709 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);
2711 uint32 r1 = dsp_convert_zero[IMM_1];
2713 uint32 res = r2 + r1;
2714 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2716 SET_ZNC_ADD(r2, r1, res);
2717 #ifdef DSP_DIS_ADDQMOD
2719 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2723 void dsp_opcode_subqmod(void)
2725 uint32 r1 = dsp_convert_zero[IMM_1];
2727 uint32 res = r2 - r1;
2728 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2731 SET_ZNC_SUB(r2, r1, res);
2734 void dsp_opcode_mirror(void)
2737 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2741 void dsp_opcode_sat32s(void)
2743 int32 r2 = (uint32)RN;
2744 int32 temp = dsp_acc >> 32;
2745 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2750 void dsp_opcode_sat16s(void)
2753 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2759 // New pipelined DSP core
2762 static void DSP_abs(void);
2763 static void DSP_add(void);
2764 static void DSP_addc(void);
2765 static void DSP_addq(void);
2766 static void DSP_addqmod(void);
2767 static void DSP_addqt(void);
2768 static void DSP_and(void);
2769 static void DSP_bclr(void);
2770 static void DSP_bset(void);
2771 static void DSP_btst(void);
2772 static void DSP_cmp(void);
2773 static void DSP_cmpq(void);
2774 static void DSP_div(void);
2775 static void DSP_imacn(void);
2776 static void DSP_imult(void);
2777 static void DSP_imultn(void);
2778 static void DSP_illegal(void);
2779 static void DSP_jr(void);
2780 static void DSP_jump(void);
2781 static void DSP_load(void);
2782 static void DSP_loadb(void);
2783 static void DSP_loadw(void);
2784 static void DSP_load_r14_i(void);
2785 static void DSP_load_r14_r(void);
2786 static void DSP_load_r15_i(void);
2787 static void DSP_load_r15_r(void);
2788 static void DSP_mirror(void);
2789 static void DSP_mmult(void);
2790 static void DSP_move(void);
2791 static void DSP_movefa(void);
2792 static void DSP_movei(void);
2793 static void DSP_movepc(void);
2794 static void DSP_moveq(void);
2795 static void DSP_moveta(void);
2796 static void DSP_mtoi(void);
2797 static void DSP_mult(void);
2798 static void DSP_neg(void);
2799 static void DSP_nop(void);
2800 static void DSP_normi(void);
2801 static void DSP_not(void);
2802 static void DSP_or(void);
2803 static void DSP_resmac(void);
2804 static void DSP_ror(void);
2805 static void DSP_rorq(void);
2806 static void DSP_sat16s(void);
2807 static void DSP_sat32s(void);
2808 static void DSP_sh(void);
2809 static void DSP_sha(void);
2810 static void DSP_sharq(void);
2811 static void DSP_shlq(void);
2812 static void DSP_shrq(void);
2813 static void DSP_store(void);
2814 static void DSP_storeb(void);
2815 static void DSP_storew(void);
2816 static void DSP_store_r14_i(void);
2817 static void DSP_store_r14_r(void);
2818 static void DSP_store_r15_i(void);
2819 static void DSP_store_r15_r(void);
2820 static void DSP_sub(void);
2821 static void DSP_subc(void);
2822 static void DSP_subq(void);
2823 static void DSP_subqmod(void);
2824 static void DSP_subqt(void);
2825 static void DSP_xor(void);
2827 void (* DSPOpcode[64])() =
2829 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2830 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2831 DSP_neg, DSP_and, DSP_or, DSP_xor,
2832 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2834 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2835 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2836 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2837 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2839 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2840 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2841 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2842 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2844 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2845 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2846 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2847 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2850 bool readAffected[64][2] =
2852 { true, true}, { true, true}, {false, true}, {false, true},
2853 { true, true}, { true, true}, {false, true}, {false, true},
2854 {false, true}, { true, true}, { true, true}, { true, true},
2855 {false, true}, {false, true}, {false, true}, {false, true},
2857 { true, true}, { true, true}, { true, true}, {false, true},
2858 { true, true}, { true, true}, {false, true}, { true, true},
2859 {false, true}, {false, true}, { true, true}, {false, true},
2860 { true, true}, {false, true}, { true, true}, {false, true},
2862 {false, true}, {false, true}, { true, false}, {false, false},
2863 { true, false}, {false, false}, {false, false}, { true, false},
2864 { true, false}, { true, false}, {false, true}, { true, false},
2865 { true, false}, { true, true}, { true, true}, { true, true},
2867 {false, true}, { true, true}, { true, true}, {false, true},
2868 { true, false}, { true, false}, { true, true}, { true, false},
2869 { true, false}, {false, false}, { true, false}, { true, false},
2870 { true, true}, { true, true}, {false, false}, {false, true}
2873 bool isLoadStore[65] =
2875 false, false, false, false, false, false, false, false,
2876 false, false, false, false, false, false, false, false,
2878 false, false, false, false, false, false, false, false,
2879 false, false, false, false, false, false, false, false,
2881 false, false, false, false, false, false, false, true,
2882 true, true, false, true, true, true, true, true,
2884 false, true, true, false, false, false, false, false,
2885 false, false, true, true, true, true, false, false, false
2888 void FlushDSPPipeline(void)
2890 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2892 for(int i=0; i<4; i++)
2893 pipeline[i].opcode = PIPELINE_STALL;
2895 for(int i=0; i<32; i++)
2900 // New pipelined DSP execution core
2902 /*void DSPExecP(int32 cycles)
2904 // bool inhibitFetch = false;
2906 dsp_releaseTimeSlice_flag = 0;
2909 while (cycles > 0 && DSP_RUNNING)
2911 WriteLog("DSPExecP: Pipeline status...\n");
2912 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2913 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2914 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2915 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2916 WriteLog(" --> Scoreboard: ");
2917 for(int i=0; i<32; i++)
2918 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2920 // Stage 1: Instruction fetch
2921 // if (!inhibitFetch)
2923 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2924 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2925 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2926 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2927 if (pipeline[plPtrFetch].opcode == 38)
2928 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2929 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2932 // inhibitFetch = false;
2933 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2935 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2936 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);
2937 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);
2938 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);
2939 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);
2940 // Stage 2: Read registers
2941 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2942 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2943 if (scoreboard[pipeline[plPtrRead].operand2])
2944 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2945 // We have a hit in the scoreboard, so we have to stall the pipeline...
2947 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2948 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2949 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2950 pipeline[plPtrFetch] = pipeline[plPtrRead];
2951 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2955 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2956 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2957 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2959 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2960 // Shouldn't we be more selective with the register scoreboarding?
2961 // Yes, we should. !!! FIX !!!
2962 scoreboard[pipeline[plPtrRead].operand2] = true;
2963 //Advance PC here??? Yes.
2964 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2965 //This is a mangling of the pipeline stages, but what else to do???
2966 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2969 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2970 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);
2971 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);
2972 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);
2973 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);
2975 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2977 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2978 DSPOpcode[pipeline[plPtrExec].opcode]();
2979 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2980 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2985 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2986 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);
2987 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);
2988 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);
2989 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);
2990 // Stage 4: Write back register
2991 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2993 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2994 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2996 scoreboard[pipeline[plPtrWrite].operand1]
2997 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3000 // Push instructions through the pipeline...
3001 plPtrFetch = (++plPtrFetch) & 0x03;
3002 plPtrRead = (++plPtrRead) & 0x03;
3003 plPtrExec = (++plPtrExec) & 0x03;
3004 plPtrWrite = (++plPtrWrite) & 0x03;
3011 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3013 // Should be fixed now. Another problem is figuring how to do the sequence following
3014 // a branch followed with the JR & JUMP instructions...
3016 // There are two conflicting problems:
3019 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3020 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3021 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3022 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3023 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3024 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3025 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3026 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3027 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3028 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3029 DSP: Finished interrupt.
3030 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3031 ; bank 0 (where is was prepared)!
3032 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3033 F1B252: NOP [NCZ:001]
3036 // The other is when you see this at the end of an IRQ:
3039 JUMP T, (R29) ; R29 = Previous stack + 2
3040 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3042 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3043 ; 1) The STORE goes through the pipeline and is executed/written back
3044 ; 2) The pipeline is flushed
3045 ; 3) The DSP_PC is set to the new address
3046 ; 4) Execution resumes
3048 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3049 ; bank 0 instead of the current bank 1 and so goes astray!
3052 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3053 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3057 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3058 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3059 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3060 If it were done properly, the STORE write back would occur *after* (well, technically,
3061 during) the execution of the the JUMP that follows it.
3065 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3066 F1B08A: NOP [NCZ:001]
3068 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3071 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3074 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3075 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3076 F1B08A: NOP [NCZ:001]
3078 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3081 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3082 DSP: CPU -> DSP interrupt
3083 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3084 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3086 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3089 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3090 F1B006: NOP [NCZ:001]
3092 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3095 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3096 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3099 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3100 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3103 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3104 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3107 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3108 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3111 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3114 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3117 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3118 F1B0FE: NOP [NCZ:000]
3120 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3123 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3126 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3127 F1B138: NOP [NCZ:000]
3129 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3132 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3133 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3134 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3137 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3138 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3141 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3142 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3143 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3145 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3146 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3149 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3150 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3151 DSP: Finished interrupt.
3152 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3154 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3157 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3158 F1B016: NOP [NCZ:001]
3160 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3163 uint32 pcQueue1[0x400];
3165 static uint32 prevR1;
3166 //Let's try a 3 stage pipeline....
3167 //Looks like 3 stage is correct, otherwise bad things happen...
3168 void DSPExecP2(int32 cycles)
3170 dsp_releaseTimeSlice_flag = 0;
3173 while (cycles > 0 && DSP_RUNNING)
3175 /*extern uint32 totalFrames;
3176 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3177 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3178 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3180 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3183 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3185 if (dsp_pc == 0xF1B092)
3186 doDSPDis = false;//*/
3187 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3188 doDSPDis = true;//*/
3189 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3190 doDSPDis = true;//*/
3191 /*if (dsp_pc == 0xF1B0A0)
3192 doDSPDis = true;//*/
3193 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3194 doDSPDis = true;//*/
3195 //Two parter... (not sure how to write this)
3196 //if (dsp_pc == 0xF1B0D2)
3197 // prevR1 = dsp_reg[1];
3199 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3200 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3203 pcQueue1[pcQPtr1++] = dsp_pc;
3206 #ifdef DSP_DEBUG_PL2
3207 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3209 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3214 for(int i=0; i<0x400; i++)
3216 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3217 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3223 if (IMASKCleared) // If IMASK was cleared,
3225 #ifdef DSP_DEBUG_IRQ
3226 WriteLog("DSP: Finished interrupt.\n");
3228 DSPHandleIRQs(); // See if any other interrupts are pending!
3229 IMASKCleared = false;
3232 //if (dsp_flags & REGPAGE)
3233 // WriteLog(" --> REGPAGE has just been set!\n");
3234 #ifdef DSP_DEBUG_PL2
3237 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3238 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]);
3239 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]);
3240 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]);
3241 WriteLog(" --> Scoreboard: ");
3242 for(int i=0; i<32; i++)
3243 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3247 // Stage 1a: Instruction fetch
3248 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3249 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3250 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3251 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3252 if (pipeline[plPtrRead].opcode == 38)
3253 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3254 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3255 #ifdef DSP_DEBUG_PL2
3258 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3259 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3260 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
3261 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3262 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
3265 // Stage 1b: Read registers
3266 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3267 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3269 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3270 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3271 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3272 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3273 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3274 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3275 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3277 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3278 // We have a hit in the scoreboard, so we have to stall the pipeline...
3279 #ifdef DSP_DEBUG_PL2
3283 WriteLog(" --> Stalling pipeline: ");
3284 if (readAffected[pipeline[plPtrRead].opcode][0])
3285 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3286 if (readAffected[pipeline[plPtrRead].opcode][1])
3287 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3291 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3292 #ifdef DSP_DEBUG_PL2
3297 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3298 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3299 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3301 // Shouldn't we be more selective with the register scoreboarding?
3302 // Yes, we should. !!! FIX !!! Kinda [DONE]
3303 #ifndef NEW_SCOREBOARD
3304 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3306 //Hopefully this will fix the dual MOVEQ # problem...
3307 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3310 //Advance PC here??? Yes.
3311 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3314 #ifdef DSP_DEBUG_PL2
3317 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3318 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]);
3319 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]);
3320 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]);
3324 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3326 #ifdef DSP_DEBUG_PL2
3328 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"));
3332 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3337 lastExec = pipeline[plPtrExec].instruction;
3338 //WriteLog("[lastExec = %04X]\n", lastExec);
3340 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3341 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3342 DSPOpcode[pipeline[plPtrExec].opcode]();
3343 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3347 //Let's not, until we do the stalling correctly...
3348 //But, we gotta while we're doing the comparison core...!
3349 //Or do we? cycles--;
3350 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3351 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3352 //to model this clock cycle behavior correctly...
3353 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3354 //don't affect the reads at stage 1...
3355 #ifdef DSP_DEBUG_STALL
3357 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3361 #ifdef DSP_DEBUG_PL2
3364 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3365 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]);
3366 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]);
3367 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]);
3371 // Stage 3: Write back register/memory address
3372 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3374 /*if (pipeline[plPtrWrite].writebackRegister == 3
3375 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3378 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3381 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3383 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3384 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3387 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3388 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3389 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3390 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3392 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3396 #ifndef NEW_SCOREBOARD
3397 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3398 scoreboard[pipeline[plPtrWrite].operand2] = false;
3400 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3401 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3402 if (scoreboard[pipeline[plPtrWrite].operand2])
3403 scoreboard[pipeline[plPtrWrite].operand2]--;
3407 // Push instructions through the pipeline...
3408 plPtrRead = (++plPtrRead) & 0x03;
3409 plPtrExec = (++plPtrExec) & 0x03;
3410 plPtrWrite = (++plPtrWrite) & 0x03;
3419 //#define DSP_DEBUG_PL3
3420 //Let's try a 2 stage pipeline....
3421 void DSPExecP3(int32 cycles)
3423 dsp_releaseTimeSlice_flag = 0;
3426 while (cycles > 0 && DSP_RUNNING)
3428 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3430 #ifdef DSP_DEBUG_PL3
3431 WriteLog("DSPExecP: Pipeline status...\n");
3432 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]);
3433 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]);
3434 WriteLog(" --> Scoreboard: ");
3435 for(int i=0; i<32; i++)
3436 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3439 // Stage 1a: Instruction fetch
3440 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3441 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3442 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3443 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3444 if (pipeline[plPtrRead].opcode == 38)
3445 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3446 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3447 #ifdef DSP_DEBUG_PL3
3448 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3449 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3450 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]);
3451 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]);
3453 // Stage 1b: Read registers
3454 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3455 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3456 // We have a hit in the scoreboard, so we have to stall the pipeline...
3457 #ifdef DSP_DEBUG_PL3
3459 WriteLog(" --> Stalling pipeline: ");
3460 if (readAffected[pipeline[plPtrRead].opcode][0])
3461 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3462 if (readAffected[pipeline[plPtrRead].opcode][1])
3463 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3466 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3467 #ifdef DSP_DEBUG_PL3
3472 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3473 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3474 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3476 // Shouldn't we be more selective with the register scoreboarding?
3477 // Yes, we should. !!! FIX !!! [Kinda DONE]
3478 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3480 //Advance PC here??? Yes.
3481 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3484 #ifdef DSP_DEBUG_PL3
3485 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3486 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]);
3487 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]);
3489 // Stage 2a: Execute
3490 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3492 #ifdef DSP_DEBUG_PL3
3493 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3495 DSPOpcode[pipeline[plPtrExec].opcode]();
3496 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3497 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3502 #ifdef DSP_DEBUG_PL3
3503 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3504 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]);
3505 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]);
3508 // Stage 2b: Write back register
3509 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3511 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3512 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3514 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3515 scoreboard[pipeline[plPtrExec].operand2] = false;
3518 // Push instructions through the pipeline...
3519 plPtrRead = (++plPtrRead) & 0x03;
3520 plPtrExec = (++plPtrExec) & 0x03;
3527 // DSP pipelined opcode handlers
3530 #define PRM pipeline[plPtrExec].reg1
3531 #define PRN pipeline[plPtrExec].reg2
3532 #define PIMM1 pipeline[plPtrExec].operand1
3533 #define PIMM2 pipeline[plPtrExec].operand2
3534 #define PRES pipeline[plPtrExec].result
3535 #define PWBR pipeline[plPtrExec].writebackRegister
3536 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3537 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3538 #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))
3539 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3541 static void DSP_abs(void)
3545 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);
3549 if (_Rn == 0x80000000)
3553 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3554 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3555 CLR_ZN; SET_Z(PRES);
3559 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3563 static void DSP_add(void)
3567 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);
3569 uint32 res = PRN + PRM;
3570 SET_ZNC_ADD(PRN, PRM, res);
3574 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);
3578 static void DSP_addc(void)
3582 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);
3584 uint32 res = PRN + PRM + dsp_flag_c;
3585 uint32 carry = dsp_flag_c;
3586 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3587 SET_ZNC_ADD(PRN + carry, PRM, res);
3588 // SET_ZNC_ADD(PRN, PRM + carry, res);
3592 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);
3596 static void DSP_addq(void)
3600 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);
3602 uint32 r1 = dsp_convert_zero[PIMM1];
3603 uint32 res = PRN + r1;
3604 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3608 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3612 static void DSP_addqmod(void)
3614 #ifdef DSP_DIS_ADDQMOD
3616 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);
3618 uint32 r1 = dsp_convert_zero[PIMM1];
3620 uint32 res = r2 + r1;
3621 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3623 SET_ZNC_ADD(r2, r1, res);
3624 #ifdef DSP_DIS_ADDQMOD
3626 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3630 static void DSP_addqt(void)
3632 #ifdef DSP_DIS_ADDQT
3634 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);
3636 PRES = PRN + dsp_convert_zero[PIMM1];
3637 #ifdef DSP_DIS_ADDQT
3639 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3643 static void DSP_and(void)
3647 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);
3653 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);
3657 static void DSP_bclr(void)
3661 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);
3663 PRES = PRN & ~(1 << PIMM1);
3667 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3671 static void DSP_bset(void)
3675 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);
3677 PRES = PRN | (1 << PIMM1);
3681 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3685 static void DSP_btst(void)
3689 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);
3691 dsp_flag_z = (~PRN >> PIMM1) & 1;
3695 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3699 static void DSP_cmp(void)
3703 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);
3705 uint32 res = PRN - PRM;
3706 SET_ZNC_SUB(PRN, PRM, res);
3710 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3714 static void DSP_cmpq(void)
3716 static int32 sqtable[32] =
3717 { 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 };
3720 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);
3722 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3723 uint32 res = PRN - r1;
3724 SET_ZNC_SUB(PRN, r1, res);
3728 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3732 static void DSP_div(void)
3734 uint32 _Rm = PRM, _Rn = PRN;
3738 if (dsp_div_control & 1)
3740 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3741 if (dsp_remain & 0x80000000)
3743 PRES = (((uint64)_Rn) << 16) / _Rm;
3747 dsp_remain = _Rn % _Rm;
3748 if (dsp_remain & 0x80000000)
3757 static void DSP_imacn(void)
3759 #ifdef DSP_DIS_IMACN
3761 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);
3763 int32 res = (int16)PRM * (int16)PRN;
3764 dsp_acc += (int64)res;
3765 //Should we AND the result to fit into 40 bits here???
3767 #ifdef DSP_DIS_IMACN
3769 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));
3773 static void DSP_imult(void)
3775 #ifdef DSP_DIS_IMULT
3777 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);
3779 PRES = (int16)PRN * (int16)PRM;
3781 #ifdef DSP_DIS_IMULT
3783 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);
3787 static void DSP_imultn(void)
3789 #ifdef DSP_DIS_IMULTN
3791 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);
3793 // This is OK, since this multiply won't overflow 32 bits...
3794 int32 res = (int32)((int16)PRN * (int16)PRM);
3795 dsp_acc = (int64)res;
3798 #ifdef DSP_DIS_IMULTN
3800 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));
3804 static void DSP_illegal(void)
3806 #ifdef DSP_DIS_ILLEGAL
3808 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3813 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3814 // can cause trouble because an interrupt can occur *before* the instruction following the
3815 // jump can execute... !!! FIX !!!
3816 // This can probably be solved by judicious coding in the pipeline execution core...
3817 // And should be fixed now...
3818 static void DSP_jr(void)
3821 const char * condition[32] =
3822 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3823 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3824 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3825 "???", "???", "???", "F" };
3827 //How come this is always off by 2???
3828 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);
3830 // KLUDGE: Used by BRANCH_CONDITION macro
3831 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3833 if (BRANCH_CONDITION(PIMM2))
3837 WriteLog("Branched!\n");
3839 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3840 //Account for pipeline effects...
3841 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3842 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3844 // Now that we've branched, we have to make sure that the following instruction
3845 // is executed atomically with this one and then flush the pipeline before setting
3848 // Step 1: Handle writebacks at stage 3 of pipeline
3849 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3851 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3852 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3854 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3855 scoreboard[pipeline[plPtrWrite].operand2] = false;
3857 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3859 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3861 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3862 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3865 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3866 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3867 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3868 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3870 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3874 #ifndef NEW_SCOREBOARD
3875 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3876 scoreboard[pipeline[plPtrWrite].operand2] = false;
3878 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3879 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3880 if (scoreboard[pipeline[plPtrWrite].operand2])
3881 scoreboard[pipeline[plPtrWrite].operand2]--;
3885 // Step 2: Push instruction through pipeline & execute following instruction
3886 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3887 // we effectively handle the final push of the instruction through the
3888 // pipeline when the new PC takes effect (since when we return, the
3889 // pipeline code will be executing the writeback stage. If we reverse
3890 // the execution order of the pipeline stages, this will no longer be
3892 pipeline[plPtrExec] = pipeline[plPtrRead];
3893 //This is BAD. We need to get that next opcode and execute it!
3894 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3895 // remove this crap.
3896 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3898 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3899 pipeline[plPtrExec].opcode = instruction >> 10;
3900 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3901 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3902 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3903 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3904 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3906 dsp_pc += 2; // For DSP_DIS_* accuracy
3907 DSPOpcode[pipeline[plPtrExec].opcode]();
3908 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3909 pipeline[plPtrWrite] = pipeline[plPtrExec];
3911 // Step 3: Flush pipeline & set new PC
3912 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3919 WriteLog("Branch NOT taken.\n");
3925 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3928 static void DSP_jump(void)
3931 const char * condition[32] =
3932 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3933 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3934 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3935 "???", "???", "???", "F" };
3937 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);
3939 // KLUDGE: Used by BRANCH_CONDITION macro
3940 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3942 if (BRANCH_CONDITION(PIMM2))
3946 WriteLog("Branched!\n");
3948 uint32 PCSave = PRM;
3949 // Now that we've branched, we have to make sure that the following instruction
3950 // is executed atomically with this one and then flush the pipeline before setting
3953 // Step 1: Handle writebacks at stage 3 of pipeline
3954 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3956 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3957 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3959 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3960 scoreboard[pipeline[plPtrWrite].operand2] = false;
3962 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3964 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3966 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3967 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3970 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3971 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3972 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3973 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3975 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3979 #ifndef NEW_SCOREBOARD
3980 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3981 scoreboard[pipeline[plPtrWrite].operand2] = false;
3983 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3984 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3985 if (scoreboard[pipeline[plPtrWrite].operand2])
3986 scoreboard[pipeline[plPtrWrite].operand2]--;
3990 // Step 2: Push instruction through pipeline & execute following instruction
3991 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3992 // we effectively handle the final push of the instruction through the
3993 // pipeline when the new PC takes effect (since when we return, the
3994 // pipeline code will be executing the writeback stage. If we reverse
3995 // the execution order of the pipeline stages, this will no longer be
3997 pipeline[plPtrExec] = pipeline[plPtrRead];
3998 //This is BAD. We need to get that next opcode and execute it!
3999 //Also, same problem in JR!
4000 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4001 // remove this crap.
4002 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
4004 uint16 instruction = DSPReadWord(dsp_pc, DSP);
4005 pipeline[plPtrExec].opcode = instruction >> 10;
4006 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4007 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4008 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4009 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4010 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4012 dsp_pc += 2; // For DSP_DIS_* accuracy
4013 DSPOpcode[pipeline[plPtrExec].opcode]();
4014 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4015 pipeline[plPtrWrite] = pipeline[plPtrExec];
4017 // Step 3: Flush pipeline & set new PC
4018 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4025 WriteLog("Branch NOT taken.\n");
4033 static void DSP_load(void)
4037 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);
4039 #ifdef DSP_CORRECT_ALIGNMENT
4040 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4042 PRES = DSPReadLong(PRM, DSP);
4046 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4050 static void DSP_loadb(void)
4052 #ifdef DSP_DIS_LOADB
4054 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);
4056 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4057 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4059 PRES = JaguarReadByte(PRM, DSP);
4060 #ifdef DSP_DIS_LOADB
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_loadw(void)
4068 #ifdef DSP_DIS_LOADW
4070 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);
4072 #ifdef DSP_CORRECT_ALIGNMENT
4073 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4074 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4076 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4078 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4079 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4081 PRES = JaguarReadWord(PRM, DSP);
4083 #ifdef DSP_DIS_LOADW
4085 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4089 static void DSP_load_r14_i(void)
4091 #ifdef DSP_DIS_LOAD14I
4093 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);
4095 #ifdef DSP_CORRECT_ALIGNMENT
4096 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4098 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4100 #ifdef DSP_DIS_LOAD14I
4102 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4106 static void DSP_load_r14_r(void)
4108 #ifdef DSP_DIS_LOAD14R
4110 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);
4112 #ifdef DSP_CORRECT_ALIGNMENT
4113 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4115 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4117 #ifdef DSP_DIS_LOAD14R
4119 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4123 static void DSP_load_r15_i(void)
4125 #ifdef DSP_DIS_LOAD15I
4127 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);
4129 #ifdef DSP_CORRECT_ALIGNMENT
4130 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4132 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4134 #ifdef DSP_DIS_LOAD15I
4136 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4140 static void DSP_load_r15_r(void)
4142 #ifdef DSP_DIS_LOAD15R
4144 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);
4146 #ifdef DSP_CORRECT_ALIGNMENT
4147 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4149 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4151 #ifdef DSP_DIS_LOAD15R
4153 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4157 static void DSP_mirror(void)
4160 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4164 static void DSP_mmult(void)
4166 int count = dsp_matrix_control&0x0f;
4167 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4171 if (!(dsp_matrix_control & 0x10))
4173 for (int i = 0; i < count; i++)
4177 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4179 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4180 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4187 for (int i = 0; i < count; i++)
4191 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4193 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4194 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4200 PRES = res = (int32)accum;
4202 //NOTE: The flags are set based upon the last add/multiply done...
4206 static void DSP_move(void)
4210 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);
4215 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);
4219 static void DSP_movefa(void)
4221 #ifdef DSP_DIS_MOVEFA
4223 // 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);
4224 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);
4226 // PRES = ALTERNATE_RM;
4227 PRES = dsp_alternate_reg[PIMM1];
4228 #ifdef DSP_DIS_MOVEFA
4230 // 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);
4231 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);
4235 static void DSP_movei(void)
4237 #ifdef DSP_DIS_MOVEI
4239 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);
4241 // // This instruction is followed by 32-bit value in LSW / MSW format...
4242 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4244 #ifdef DSP_DIS_MOVEI
4246 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4250 static void DSP_movepc(void)
4252 #ifdef DSP_DIS_MOVEPC
4254 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);
4256 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4257 // PRES = dsp_pc - 2;
4258 //Account for pipeline effects...
4259 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4260 #ifdef DSP_DIS_MOVEPC
4262 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4266 static void DSP_moveq(void)
4268 #ifdef DSP_DIS_MOVEQ
4270 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);
4273 #ifdef DSP_DIS_MOVEQ
4275 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4279 static void DSP_moveta(void)
4281 #ifdef DSP_DIS_MOVETA
4283 // 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);
4284 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]);
4286 // ALTERNATE_RN = PRM;
4287 dsp_alternate_reg[PIMM2] = PRM;
4289 #ifdef DSP_DIS_MOVETA
4291 // 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);
4292 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]);
4296 static void DSP_mtoi(void)
4298 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4302 static void DSP_mult(void)
4306 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);
4308 PRES = (uint16)PRM * (uint16)PRN;
4312 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);
4316 static void DSP_neg(void)
4320 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);
4323 SET_ZNC_SUB(0, PRN, res);
4327 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4331 static void DSP_nop(void)
4335 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4340 static void DSP_normi(void)
4347 while ((_Rm & 0xffc00000) == 0)
4352 while ((_Rm & 0xff800000) != 0)
4362 static void DSP_not(void)
4366 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);
4372 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4376 static void DSP_or(void)
4380 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);
4386 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);
4390 static void DSP_resmac(void)
4392 #ifdef DSP_DIS_RESMAC
4394 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));
4396 PRES = (uint32)dsp_acc;
4397 #ifdef DSP_DIS_RESMAC
4399 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4403 static void DSP_ror(void)
4407 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);
4409 uint32 r1 = PRM & 0x1F;
4410 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4411 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4415 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);
4419 static void DSP_rorq(void)
4423 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);
4425 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4427 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4429 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4432 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4436 static void DSP_sat16s(void)
4439 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4444 static void DSP_sat32s(void)
4446 int32 r2 = (uint32)PRN;
4447 int32 temp = dsp_acc >> 32;
4448 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4453 static void DSP_sh(void)
4455 int32 sRm = (int32)PRM;
4460 uint32 shift = -sRm;
4465 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4480 dsp_flag_c = _Rn & 0x1;
4493 static void DSP_sha(void)
4495 int32 sRm = (int32)PRM;
4500 uint32 shift = -sRm;
4505 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4520 dsp_flag_c = _Rn & 0x1;
4524 _Rn = ((int32)_Rn) >> 1;
4533 static void DSP_sharq(void)
4535 #ifdef DSP_DIS_SHARQ
4537 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);
4539 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4540 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4542 #ifdef DSP_DIS_SHARQ
4544 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4548 static void DSP_shlq(void)
4552 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);
4554 int32 r1 = 32 - PIMM1;
4555 uint32 res = PRN << r1;
4556 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4560 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4564 static void DSP_shrq(void)
4568 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);
4570 int32 r1 = dsp_convert_zero[PIMM1];
4571 uint32 res = PRN >> r1;
4572 SET_ZN(res); dsp_flag_c = PRN & 1;
4576 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4580 static void DSP_store(void)
4582 #ifdef DSP_DIS_STORE
4584 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);
4586 // DSPWriteLong(PRM, PRN, DSP);
4588 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4589 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4591 pipeline[plPtrExec].address = PRM;
4593 pipeline[plPtrExec].value = PRN;
4594 pipeline[plPtrExec].type = TYPE_DWORD;
4598 static void DSP_storeb(void)
4600 #ifdef DSP_DIS_STOREB
4602 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);
4604 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4605 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4607 // JaguarWriteByte(PRM, PRN, DSP);
4610 pipeline[plPtrExec].address = PRM;
4612 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4614 pipeline[plPtrExec].value = PRN & 0xFF;
4615 pipeline[plPtrExec].type = TYPE_DWORD;
4619 pipeline[plPtrExec].value = PRN;
4620 pipeline[plPtrExec].type = TYPE_BYTE;
4626 static void DSP_storew(void)
4628 #ifdef DSP_DIS_STOREW
4630 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);
4632 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4633 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4635 // JaguarWriteWord(PRM, PRN, DSP);
4638 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4639 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4641 pipeline[plPtrExec].address = PRM;
4644 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4646 pipeline[plPtrExec].value = PRN & 0xFFFF;
4647 pipeline[plPtrExec].type = TYPE_DWORD;
4651 pipeline[plPtrExec].value = PRN;
4652 pipeline[plPtrExec].type = TYPE_WORD;
4657 static void DSP_store_r14_i(void)
4659 #ifdef DSP_DIS_STORE14I
4661 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));
4663 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4665 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4666 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4668 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4670 pipeline[plPtrExec].value = PRN;
4671 pipeline[plPtrExec].type = TYPE_DWORD;
4675 static void DSP_store_r14_r(void)
4677 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4679 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4680 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4682 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4684 pipeline[plPtrExec].value = PRN;
4685 pipeline[plPtrExec].type = TYPE_DWORD;
4689 static void DSP_store_r15_i(void)
4691 #ifdef DSP_DIS_STORE15I
4693 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));
4695 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4697 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4698 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4700 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4702 pipeline[plPtrExec].value = PRN;
4703 pipeline[plPtrExec].type = TYPE_DWORD;
4707 static void DSP_store_r15_r(void)
4709 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4711 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4712 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4714 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4716 pipeline[plPtrExec].value = PRN;
4717 pipeline[plPtrExec].type = TYPE_DWORD;
4721 static void DSP_sub(void)
4725 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);
4727 uint32 res = PRN - PRM;
4728 SET_ZNC_SUB(PRN, PRM, res);
4732 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);
4736 static void DSP_subc(void)
4740 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);
4742 uint32 res = PRN - PRM - dsp_flag_c;
4743 uint32 borrow = dsp_flag_c;
4744 SET_ZNC_SUB(PRN - borrow, PRM, res);
4748 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);
4752 static void DSP_subq(void)
4756 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);
4758 uint32 r1 = dsp_convert_zero[PIMM1];
4759 uint32 res = PRN - r1;
4760 SET_ZNC_SUB(PRN, r1, res);
4764 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4768 static void DSP_subqmod(void)
4770 uint32 r1 = dsp_convert_zero[PIMM1];
4772 uint32 res = r2 - r1;
4773 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4775 SET_ZNC_SUB(r2, r1, res);
4778 static void DSP_subqt(void)
4780 #ifdef DSP_DIS_SUBQT
4782 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);
4784 PRES = PRN - dsp_convert_zero[PIMM1];
4785 #ifdef DSP_DIS_SUBQT
4787 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4791 static void DSP_xor(void)
4795 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);
4801 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);