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...
28 #include "m68000/m68kinterface.h"
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)
628 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
629 return dsp_flags & 0xFFFFC1FF;
630 case 0x04: return dsp_matrix_control;
631 case 0x08: return dsp_pointer_to_matrix;
632 case 0x0C: return dsp_data_organization;
633 case 0x10: return dsp_pc;
634 case 0x14: return dsp_control;
635 case 0x18: return dsp_modulo;
636 case 0x1C: return dsp_remain;
638 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
640 // unaligned long read-- !!! FIX !!!
644 return JaguarReadLong(offset, who);
647 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
649 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
650 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
652 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
654 offset -= DSP_WORK_RAM_BASE;
655 dsp_ram_8[offset] = data;
656 //This is rather stupid! !!! FIX !!!
657 /* if (dsp_in_exec == 0)
659 m68k_end_timeslice();
660 dsp_releaseTimeslice();
664 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
666 uint32 reg = offset & 0x1C;
667 int bytenum = offset & 0x03;
669 if ((reg >= 0x1C) && (reg <= 0x1F))
670 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
673 //This looks funky. !!! FIX !!!
674 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
675 bytenum = 3 - bytenum; // convention motorola !!!
676 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
677 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
681 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
682 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
683 JaguarWriteByte(offset, data, who);
686 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
688 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
689 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
690 offset &= 0xFFFFFFFE;
691 /*if (offset == 0xF1BCF4)
693 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
695 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
696 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
698 /*if (offset == 0xF1B2F4)
700 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
702 offset -= DSP_WORK_RAM_BASE;
703 dsp_ram_8[offset] = data >> 8;
704 dsp_ram_8[offset+1] = data & 0xFF;
705 //This is rather stupid! !!! FIX !!!
706 /* if (dsp_in_exec == 0)
708 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
709 m68k_end_timeslice();
710 dsp_releaseTimeslice();
714 SET16(ram1, offset, data),
715 SET16(ram2, offset, data);
720 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
722 if ((offset & 0x1C) == 0x1C)
725 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
727 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
731 uint32 old_data = DSPReadLong(offset & 0xFFFFFFC, who);
734 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
736 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
738 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);
787 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
788 // IRQ logic can set it. So we mask it out here to prevent problems...
789 dsp_flags = data & (~IMASK);
790 dsp_flag_z = dsp_flags & 0x01;
791 dsp_flag_c = (dsp_flags >> 1) & 0x01;
792 dsp_flag_n = (dsp_flags >> 2) & 0x01;
793 DSPUpdateRegisterBanks();
794 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
795 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
797 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
798 // It can be timed to anything really, anything that writes to L/RTXD at a regular
799 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
800 // interrupt, so that's what we check for here. Just know that this approach
801 // can be easily fooled!
802 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
805 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
806 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
807 // So, while this works, it's a by-product of the lame way in which audio is currently
808 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
809 // go away of its own accord. :-P
810 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
811 // weird is going on here...
812 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
813 // So subsequent interrupts come into the chip, but they're never serviced but the
814 // I2S subsystem keeps going.
815 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
816 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
817 // It seems that it's only stable for values of SCLK <= 9.
819 // All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
820 // that we don't actually need this stuff anymore. :-D
822 if (data & INT_ENA1) // I2S interrupt
824 int freq = GetCalculatedFrequency();
825 //This happens too often to be useful...
826 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
827 DACSetNewFrequency(freq);
829 else if (data & INT_ENA2) // TIMER 0 interrupt
831 int freq = JERRYGetPIT1Frequency();
832 //This happens too often to be useful...
833 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
834 DACSetNewFrequency(freq);
838 /* if (IMASKCleared) // If IMASK was cleared,
841 WriteLog("DSP: Finished interrupt.\n");
843 DSPHandleIRQs(); // see if any other interrupts need servicing!
848 if (/*4-8, 16*/data & 0x101F0)
849 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
850 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
851 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
852 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
853 /*if (data & 0x00020) // CD BIOS DSP code...
855 //001AC1BA: movea.l #$1AC200, A0
856 //001AC1C0: move.l #$1AC68C, D0
859 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
860 uint32 j = 0xF1B97C;//0x1AC200;
861 while (j <= 0xF1BE08)//0x1AC68C)
864 j += dasmjag(JAGUAR_DSP, buffer, j);
865 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
866 WriteLog("\t%08X: %s\n", oldj, buffer);
873 dsp_matrix_control = data;
876 // According to JTRM, only lines 2-11 are addressable, the rest being
877 // hardwired to $F1Bxxx.
878 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
881 dsp_data_organization = data;
886 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
891 ctrl1[0] = ctrl2[0] = data;
898 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
900 bool wasRunning = DSP_RUNNING;
901 // uint32 dsp_was_running = DSP_RUNNING;
902 // Check for DSP -> CPU interrupt
906 WriteLog("DSP: DSP -> CPU interrupt\n");
909 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
910 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
911 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
913 JERRYSetPendingIRQ(IRQ2_DSP);
914 DSPReleaseTimeslice();
915 m68k_set_irq(2); // Set 68000 IPL 2...
919 // Check for CPU -> DSP interrupt
923 WriteLog("DSP: CPU -> DSP interrupt\n");
925 m68k_end_timeslice();
926 DSPReleaseTimeslice();
927 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
931 if (data & SINGLE_STEP)
933 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
936 // Protect writes to VERSION and the interrupt latches...
937 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
938 dsp_control = (dsp_control & mask) | (data & ~mask);
942 ctrl1[8] = ctrl2[8] = dsp_control;
946 // if dsp wasn't running but is now running
947 // execute a few cycles
948 //This is just plain wrong, wrong, WRONG!
949 #ifndef DSP_SINGLE_STEPPING
950 /* if (!dsp_was_running && DSP_RUNNING)
955 //This is WRONG! !!! FIX !!!
956 if (dsp_control & 0x18)
961 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
963 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
966 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
967 // !!! FIX !!! [DONE]
971 m68k_end_timeslice();
973 DSPReleaseTimeslice();
977 //DSPDumpDisassembly();
985 dsp_div_control = data;
987 // default: // unaligned long read
993 //We don't have to break this up like this! We CAN do 32 bit writes!
994 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
995 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
996 //if (offset > 0xF1FFFF)
998 JaguarWriteLong(offset, data, who);
1002 // Update the DSP register file pointers depending on REGPAGE bit
1004 void DSPUpdateRegisterBanks(void)
1006 int bank = (dsp_flags & REGPAGE);
1008 if (dsp_flags & IMASK)
1009 bank = 0; // IMASK forces main bank to be bank 0
1012 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1014 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1018 // Check for and handle any asserted DSP IRQs
1020 void DSPHandleIRQs(void)
1022 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1025 // Get the active interrupt bits (latches) & interrupt mask (enables)
1026 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1027 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1029 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1032 if (!bits) // Bail if nothing is enabled
1035 int which = 0; // Determine which interrupt
1049 #ifdef DSP_DEBUG_IRQ
1050 WriteLog("DSP: Generating interrupt #%i...", which);
1053 //if (which == 0) doDSPDis = true;
1055 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1056 // directly into the pipeline, it has the side effect of ensuring that the
1057 // instruction interrupted also gets to do its writeback. We simulate that
1059 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1061 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1062 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1064 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1065 scoreboard[pipeline[plPtrWrite].operand2] = false;
1067 //This should be execute (or should it?--not sure now!)
1068 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1069 //and what just executed is now in the Write position...). So why didn't it do the
1070 //writeback into register 0?
1071 #ifdef DSP_DEBUG_IRQ
1072 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1073 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]);
1074 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]);
1075 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]);
1077 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1079 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1081 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1082 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1085 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1086 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1087 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1088 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1090 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1094 #ifndef NEW_SCOREBOARD
1095 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1096 scoreboard[pipeline[plPtrWrite].operand2] = false;
1098 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1099 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1100 if (scoreboard[pipeline[plPtrWrite].operand2])
1101 scoreboard[pipeline[plPtrWrite].operand2]--;
1108 ctrl2[4] = dsp_flags;
1111 DSPUpdateRegisterBanks();
1112 #ifdef DSP_DEBUG_IRQ
1113 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1114 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]);
1117 // subqt #4,r31 ; pre-decrement stack pointer
1118 // move pc,r30 ; address of interrupted code
1119 // store r30,(r31) ; store return address
1126 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1127 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1128 //It missed the place that it was supposed to come back to, so this is WRONG!
1130 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1132 // R -> baz (<- PC points here)
1133 // E -> bar (when it should point here!)
1136 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1137 // which means (assuming they're all 2 bytes long) that the code below will come back on
1138 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1139 // instruction stream...
1141 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1142 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1145 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1149 // movei #service_address,r30 ; pointer to ISR entry
1150 // jump (r30) ; jump to ISR
1152 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1155 ctrl2[0] = regs2[30] = dsp_pc;
1162 // Non-pipelined version...
1164 void DSPHandleIRQsNP(void)
1168 memcpy(dsp_ram_8, ram1, 0x2000);
1169 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1170 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1173 dsp_remain = ctrl1[2];
1174 dsp_modulo = ctrl1[3];
1175 dsp_flags = ctrl1[4];
1176 dsp_matrix_control = ctrl1[5];
1177 dsp_pointer_to_matrix = ctrl1[6];
1178 dsp_data_organization = ctrl1[7];
1179 dsp_control = ctrl1[8];
1180 dsp_div_control = ctrl1[9];
1181 IMASKCleared = ctrl1[10];
1182 dsp_flag_z = ctrl1[11];
1183 dsp_flag_n = ctrl1[12];
1184 dsp_flag_c = ctrl1[13];
1185 DSPUpdateRegisterBanks();
1188 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1191 // Get the active interrupt bits (latches) & interrupt mask (enables)
1192 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1193 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1195 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1198 if (!bits) // Bail if nothing is enabled
1201 int which = 0; // Determine which interrupt
1215 #ifdef DSP_DEBUG_IRQ
1216 WriteLog("DSP: Generating interrupt #%i...", which);
1222 ctrl1[4] = dsp_flags;
1225 DSPUpdateRegisterBanks();
1226 #ifdef DSP_DEBUG_IRQ
1227 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1230 // subqt #4,r31 ; pre-decrement stack pointer
1231 // move pc,r30 ; address of interrupted code
1232 // store r30,(r31) ; store return address
1239 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1242 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1246 // movei #service_address,r30 ; pointer to ISR entry
1247 // jump (r30) ; jump to ISR
1249 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1252 ctrl1[0] = regs1[30] = dsp_pc;
1258 // Set the specified DSP IRQ line to a given state
1260 void DSPSetIRQLine(int irqline, int state)
1262 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1263 uint32 mask = INT_LAT0 << irqline;
1264 dsp_control &= ~mask; // Clear the latch bit
1267 ctrl1[8] = ctrl2[8] = dsp_control;
1273 dsp_control |= mask; // Set the latch bit
1277 ctrl1[8] = ctrl2[8] = dsp_control;
1283 // Not sure if this is correct behavior, but according to JTRM,
1284 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1285 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1286 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1289 bool DSPIsRunning(void)
1291 return (DSP_RUNNING ? true : false);
1296 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1297 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1298 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1300 dsp_build_branch_condition_table();
1302 srand(time(NULL)); // For randomizing local RAM
1307 dsp_pc = 0x00F1B000;
1308 dsp_acc = 0x00000000;
1309 dsp_remain = 0x00000000;
1310 dsp_modulo = 0xFFFFFFFF;
1311 dsp_flags = 0x00040000;
1312 dsp_matrix_control = 0x00000000;
1313 dsp_pointer_to_matrix = 0x00000000;
1314 dsp_data_organization = 0xFFFFFFFF;
1315 dsp_control = 0x00002000; // Report DSP version 2
1316 dsp_div_control = 0x00000000;
1319 dsp_reg = dsp_reg_bank_0;
1320 dsp_alternate_reg = dsp_reg_bank_1;
1322 for(int i=0; i<32; i++)
1323 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1326 IMASKCleared = false;
1329 // memset(dsp_ram_8, 0xFF, 0x2000);
1330 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1331 for(uint32 i=0; i<8192; i+=4)
1333 *((uint32 *)(&dsp_ram_8[i])) = rand();
1337 void DSPDumpDisassembly(void)
1341 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1342 uint32 j = 0xF1B000;
1344 while (j <= 0xF1CFFF)
1347 j += dasmjag(JAGUAR_DSP, buffer, j);
1348 WriteLog("\t%08X: %s\n", oldj, buffer);
1352 void DSPDumpRegisters(void)
1354 //Shoud add modulus, etc to dump here...
1355 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1356 WriteLog("\nRegisters bank 0\n");
1358 for(int j=0; j<8; j++)
1360 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1361 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1362 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1363 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1364 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1367 WriteLog("Registers bank 1\n");
1369 for(int j=0; j<8; j++)
1371 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1372 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1373 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1374 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1375 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1382 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1383 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1385 // get the active interrupt bits
1386 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1387 // get the interrupt mask
1388 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1390 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1391 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1392 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1393 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1394 WriteLog("\nRegisters bank 0\n");
1396 for(int j=0; j<8; j++)
1398 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1399 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1400 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1401 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1402 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1405 WriteLog("\nRegisters bank 1\n");
1409 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1410 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1411 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1412 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1413 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1418 static char buffer[512];
1419 j = DSP_WORK_RAM_BASE;
1421 while (j <= 0xF1CFFF)
1424 j += dasmjag(JAGUAR_DSP, buffer, j);
1425 WriteLog("\t%08X: %s\n", oldj, buffer);
1428 WriteLog("DSP opcodes use:\n");
1432 if (dsp_opcode_use[i])
1433 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1436 // memory_free(dsp_ram_8);
1437 // memory_free(dsp_reg_bank_0);
1438 // memory_free(dsp_reg_bank_1);
1439 // if (dsp_branch_condition_table)
1440 // free(dsp_branch_condition_table);
1442 // if (mirror_table)
1443 // free(mirror_table);
1449 // DSP comparison core...
1452 static uint16 lastExec;
1453 void DSPExecComp(int32 cycles)
1455 while (cycles > 0 && DSP_RUNNING)
1457 // Load up vars for non-pipelined core
1458 memcpy(dsp_ram_8, ram1, 0x2000);
1459 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1460 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1463 dsp_remain = ctrl1[2];
1464 dsp_modulo = ctrl1[3];
1465 dsp_flags = ctrl1[4];
1466 dsp_matrix_control = ctrl1[5];
1467 dsp_pointer_to_matrix = ctrl1[6];
1468 dsp_data_organization = ctrl1[7];
1469 dsp_control = ctrl1[8];
1470 dsp_div_control = ctrl1[9];
1471 IMASKCleared = ctrl1[10];
1472 dsp_flag_z = ctrl1[11];
1473 dsp_flag_n = ctrl1[12];
1474 dsp_flag_c = ctrl1[13];
1475 DSPUpdateRegisterBanks();
1477 // Decrement cycles based on non-pipelined core...
1478 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1479 cycles -= dsp_opcode_cycles[instr1 >> 10];
1481 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1482 DSPExec(1); // Do *one* instruction
1485 memcpy(ram1, dsp_ram_8, 0x2000);
1486 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1487 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1490 ctrl1[2] = dsp_remain;
1491 ctrl1[3] = dsp_modulo;
1492 ctrl1[4] = dsp_flags;
1493 ctrl1[5] = dsp_matrix_control;
1494 ctrl1[6] = dsp_pointer_to_matrix;
1495 ctrl1[7] = dsp_data_organization;
1496 ctrl1[8] = dsp_control;
1497 ctrl1[9] = dsp_div_control;
1498 ctrl1[10] = IMASKCleared;
1499 ctrl1[11] = dsp_flag_z;
1500 ctrl1[12] = dsp_flag_n;
1501 ctrl1[13] = dsp_flag_c;
1503 // Load up vars for pipelined core
1504 memcpy(dsp_ram_8, ram2, 0x2000);
1505 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1506 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1509 dsp_remain = ctrl2[2];
1510 dsp_modulo = ctrl2[3];
1511 dsp_flags = ctrl2[4];
1512 dsp_matrix_control = ctrl2[5];
1513 dsp_pointer_to_matrix = ctrl2[6];
1514 dsp_data_organization = ctrl2[7];
1515 dsp_control = ctrl2[8];
1516 dsp_div_control = ctrl2[9];
1517 IMASKCleared = ctrl2[10];
1518 dsp_flag_z = ctrl2[11];
1519 dsp_flag_n = ctrl2[12];
1520 dsp_flag_c = ctrl2[13];
1521 DSPUpdateRegisterBanks();
1523 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1524 DSPExecP2(1); // Do *one* instruction
1527 memcpy(ram2, dsp_ram_8, 0x2000);
1528 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1529 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1532 ctrl2[2] = dsp_remain;
1533 ctrl2[3] = dsp_modulo;
1534 ctrl2[4] = dsp_flags;
1535 ctrl2[5] = dsp_matrix_control;
1536 ctrl2[6] = dsp_pointer_to_matrix;
1537 ctrl2[7] = dsp_data_organization;
1538 ctrl2[8] = dsp_control;
1539 ctrl2[9] = dsp_div_control;
1540 ctrl2[10] = IMASKCleared;
1541 ctrl2[11] = dsp_flag_z;
1542 ctrl2[12] = dsp_flag_n;
1543 ctrl2[13] = dsp_flag_c;
1545 if (instr1 != lastExec)
1547 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1549 // 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));
1550 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1551 // if (ctrl1[0] < ppc) // P ran ahead of NP
1552 //How to test this crap???
1555 DSPExecP2(1); // Do one more instruction
1558 memcpy(ram2, dsp_ram_8, 0x2000);
1559 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1560 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1563 ctrl2[2] = dsp_remain;
1564 ctrl2[3] = dsp_modulo;
1565 ctrl2[4] = dsp_flags;
1566 ctrl2[5] = dsp_matrix_control;
1567 ctrl2[6] = dsp_pointer_to_matrix;
1568 ctrl2[7] = dsp_data_organization;
1569 ctrl2[8] = dsp_control;
1570 ctrl2[9] = dsp_div_control;
1571 ctrl2[10] = IMASKCleared;
1572 ctrl2[11] = dsp_flag_z;
1573 ctrl2[12] = dsp_flag_n;
1574 ctrl2[13] = dsp_flag_c;
1576 // else // NP ran ahead of P
1577 if (instr1 != lastExec) // Must be the other way...
1580 // Load up vars for non-pipelined core
1581 memcpy(dsp_ram_8, ram1, 0x2000);
1582 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1583 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1586 dsp_remain = ctrl1[2];
1587 dsp_modulo = ctrl1[3];
1588 dsp_flags = ctrl1[4];
1589 dsp_matrix_control = ctrl1[5];
1590 dsp_pointer_to_matrix = ctrl1[6];
1591 dsp_data_organization = ctrl1[7];
1592 dsp_control = ctrl1[8];
1593 dsp_div_control = ctrl1[9];
1594 IMASKCleared = ctrl1[10];
1595 dsp_flag_z = ctrl1[11];
1596 dsp_flag_n = ctrl1[12];
1597 dsp_flag_c = ctrl1[13];
1598 DSPUpdateRegisterBanks();
1600 for(int k=0; k<2; k++)
1602 // Decrement cycles based on non-pipelined core...
1603 instr1 = DSPReadWord(dsp_pc, DSP);
1604 cycles -= dsp_opcode_cycles[instr1 >> 10];
1606 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1607 DSPExec(1); // Do *one* instruction
1611 memcpy(ram1, dsp_ram_8, 0x2000);
1612 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1613 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1616 ctrl1[2] = dsp_remain;
1617 ctrl1[3] = dsp_modulo;
1618 ctrl1[4] = dsp_flags;
1619 ctrl1[5] = dsp_matrix_control;
1620 ctrl1[6] = dsp_pointer_to_matrix;
1621 ctrl1[7] = dsp_data_organization;
1622 ctrl1[8] = dsp_control;
1623 ctrl1[9] = dsp_div_control;
1624 ctrl1[10] = IMASKCleared;
1625 ctrl1[11] = dsp_flag_z;
1626 ctrl1[12] = dsp_flag_n;
1627 ctrl1[13] = dsp_flag_c;
1631 if (instr1 != lastExec)
1633 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1635 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1636 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1649 // DSP execution core
1651 //static bool R20Set = false, tripwire = false;
1652 //static uint32 pcQueue[32], ptrPCQ = 0;
1653 void DSPExec(int32 cycles)
1655 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1656 dsp_check_if_i2s_interrupt_needed();*/
1658 #ifdef DSP_SINGLE_STEPPING
1659 if (dsp_control & 0x18)
1662 dsp_control &= ~0x10;
1665 //There is *no* good reason to do this here!
1667 dsp_releaseTimeSlice_flag = 0;
1670 while (cycles > 0 && DSP_RUNNING)
1672 /*extern uint32 totalFrames;
1673 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1674 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1675 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1677 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1680 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1682 if (dsp_pc == 0xF1B092)
1683 doDSPDis = false;//*/
1684 /*if (dsp_pc == 0xF1B140)
1685 doDSPDis = true;//*/
1687 if (IMASKCleared) // If IMASK was cleared,
1689 #ifdef DSP_DEBUG_IRQ
1690 WriteLog("DSP: Finished interrupt.\n");
1692 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1693 IMASKCleared = false;
1698 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1699 for(int i=0; i<80; i+=4)
1700 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1703 /*if (dsp_pc == 0xF1B55E)
1705 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1707 /*if (dsp_pc == 0xF1B7D2) // Start here???
1709 pcQueue[ptrPCQ++] = dsp_pc;
1711 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1712 uint32 index = opcode >> 10;
1713 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1714 dsp_opcode_second_parameter = opcode & 0x1F;
1716 dsp_opcode[index]();
1717 dsp_opcode_use[index]++;
1718 cycles -= dsp_opcode_cycles[index];
1719 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1721 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1724 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1726 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1728 DSPDumpDisassembly();
1731 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1734 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1737 WriteLog("\nBacktrace:\n");
1738 for(int i=0; i<32; i++)
1740 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1741 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1751 // DSP opcode handlers
1754 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1755 // can cause trouble because an interrupt can occur *before* the instruction following the
1756 // jump can execute... !!! FIX !!!
1757 static void dsp_opcode_jump(void)
1760 const char * condition[32] =
1761 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1762 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1763 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1764 "???", "???", "???", "F" };
1766 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);
1769 /* dsp_flag_c=dsp_flag_c?1:0;
1770 dsp_flag_z=dsp_flag_z?1:0;
1771 dsp_flag_n=dsp_flag_n?1:0;*/
1772 // KLUDGE: Used by BRANCH_CONDITION
1773 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1775 if (BRANCH_CONDITION(IMM_2))
1779 WriteLog("Branched!\n");
1781 uint32 delayed_pc = RM;
1783 dsp_pc = delayed_pc;
1788 WriteLog("Branch NOT taken.\n");
1792 static void dsp_opcode_jr(void)
1795 const char * condition[32] =
1796 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1797 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1798 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1799 "???", "???", "???", "F" };
1801 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);
1804 /* dsp_flag_c=dsp_flag_c?1:0;
1805 dsp_flag_z=dsp_flag_z?1:0;
1806 dsp_flag_n=dsp_flag_n?1:0;*/
1807 // KLUDGE: Used by BRANCH_CONDITION
1808 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1810 if (BRANCH_CONDITION(IMM_2))
1814 WriteLog("Branched!\n");
1816 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1817 int32 delayed_pc = dsp_pc + (offset * 2);
1819 dsp_pc = delayed_pc;
1824 WriteLog("Branch NOT taken.\n");
1828 static void dsp_opcode_add(void)
1832 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);
1834 uint32 res = RN + RM;
1835 SET_ZNC_ADD(RN, RM, res);
1839 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);
1843 static void dsp_opcode_addc(void)
1847 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);
1849 uint32 res = RN + RM + dsp_flag_c;
1850 uint32 carry = dsp_flag_c;
1851 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1852 SET_ZNC_ADD(RN + carry, RM, res);
1853 // SET_ZNC_ADD(RN, RM + carry, res);
1857 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);
1861 static void dsp_opcode_addq(void)
1865 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);
1867 uint32 r1 = dsp_convert_zero[IMM_1];
1868 uint32 res = RN + r1;
1869 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1873 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1877 static void dsp_opcode_sub(void)
1881 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);
1883 uint32 res = RN - RM;
1884 SET_ZNC_SUB(RN, RM, res);
1888 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);
1892 static void dsp_opcode_subc(void)
1896 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);
1898 uint32 res = RN - RM - dsp_flag_c;
1899 uint32 borrow = dsp_flag_c;
1900 SET_ZNC_SUB(RN - borrow, RM, res);
1904 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);
1908 static void dsp_opcode_subq(void)
1912 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);
1914 uint32 r1 = dsp_convert_zero[IMM_1];
1915 uint32 res = RN - r1;
1916 SET_ZNC_SUB(RN, r1, res);
1920 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1924 static void dsp_opcode_cmp(void)
1928 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);
1930 uint32 res = RN - RM;
1931 SET_ZNC_SUB(RN, RM, res);
1934 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1938 static void dsp_opcode_cmpq(void)
1940 static int32 sqtable[32] =
1941 { 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 };
1944 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);
1946 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1947 uint32 res = RN - r1;
1948 SET_ZNC_SUB(RN, r1, res);
1951 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1955 static void dsp_opcode_and(void)
1959 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);
1965 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);
1969 static void dsp_opcode_or(void)
1973 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);
1979 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);
1983 static void dsp_opcode_xor(void)
1987 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);
1993 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);
1997 static void dsp_opcode_not(void)
2001 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);
2007 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2011 static void dsp_opcode_move_pc(void)
2016 static void dsp_opcode_store_r14_indexed(void)
2018 #ifdef DSP_DIS_STORE14I
2020 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));
2022 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2023 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2025 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2029 static void dsp_opcode_store_r15_indexed(void)
2031 #ifdef DSP_DIS_STORE15I
2033 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));
2035 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2036 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2038 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2042 static void dsp_opcode_load_r14_ri(void)
2044 #ifdef DSP_DIS_LOAD14R
2046 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);
2048 #ifdef DSP_CORRECT_ALIGNMENT
2049 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2051 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2053 #ifdef DSP_DIS_LOAD14R
2055 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2059 static void dsp_opcode_load_r15_ri(void)
2061 #ifdef DSP_DIS_LOAD15R
2063 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);
2065 #ifdef DSP_CORRECT_ALIGNMENT
2066 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2068 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2070 #ifdef DSP_DIS_LOAD15R
2072 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2076 static void dsp_opcode_store_r14_ri(void)
2078 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2081 static void dsp_opcode_store_r15_ri(void)
2083 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2086 static void dsp_opcode_nop(void)
2090 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2094 static void dsp_opcode_storeb(void)
2096 #ifdef DSP_DIS_STOREB
2098 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);
2100 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2101 DSPWriteLong(RM, RN & 0xFF, DSP);
2103 JaguarWriteByte(RM, RN, DSP);
2106 static void dsp_opcode_storew(void)
2108 #ifdef DSP_DIS_STOREW
2110 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);
2112 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2113 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2114 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2116 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2118 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2119 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2121 JaguarWriteWord(RM, RN, DSP);
2125 static void dsp_opcode_store(void)
2127 #ifdef DSP_DIS_STORE
2129 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);
2131 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2132 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2134 DSPWriteLong(RM, RN, DSP);
2138 static void dsp_opcode_loadb(void)
2140 #ifdef DSP_DIS_LOADB
2142 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);
2144 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2145 RN = DSPReadLong(RM, DSP) & 0xFF;
2147 RN = JaguarReadByte(RM, DSP);
2148 #ifdef DSP_DIS_LOADB
2150 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2154 static void dsp_opcode_loadw(void)
2156 #ifdef DSP_DIS_LOADW
2158 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);
2160 #ifdef DSP_CORRECT_ALIGNMENT
2161 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2162 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2164 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2166 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2167 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2169 RN = JaguarReadWord(RM, DSP);
2171 #ifdef DSP_DIS_LOADW
2173 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2177 static void dsp_opcode_load(void)
2181 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);
2183 #ifdef DSP_CORRECT_ALIGNMENT
2184 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2186 RN = DSPReadLong(RM, DSP);
2190 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2194 static void dsp_opcode_load_r14_indexed(void)
2196 #ifdef DSP_DIS_LOAD14I
2198 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);
2200 #ifdef DSP_CORRECT_ALIGNMENT
2201 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2203 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2205 #ifdef DSP_DIS_LOAD14I
2207 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2211 static void dsp_opcode_load_r15_indexed(void)
2213 #ifdef DSP_DIS_LOAD15I
2215 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);
2217 #ifdef DSP_CORRECT_ALIGNMENT
2218 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2220 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2222 #ifdef DSP_DIS_LOAD15I
2224 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2228 static void dsp_opcode_movei(void)
2230 #ifdef DSP_DIS_MOVEI
2232 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);
2234 // This instruction is followed by 32-bit value in LSW / MSW format...
2235 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2237 #ifdef DSP_DIS_MOVEI
2239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2243 static void dsp_opcode_moveta(void)
2245 #ifdef DSP_DIS_MOVETA
2247 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);
2250 #ifdef DSP_DIS_MOVETA
2252 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);
2256 static void dsp_opcode_movefa(void)
2258 #ifdef DSP_DIS_MOVEFA
2260 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);
2263 #ifdef DSP_DIS_MOVEFA
2265 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);
2269 static void dsp_opcode_move(void)
2273 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);
2278 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);
2282 static void dsp_opcode_moveq(void)
2284 #ifdef DSP_DIS_MOVEQ
2286 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);
2289 #ifdef DSP_DIS_MOVEQ
2291 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2295 static void dsp_opcode_resmac(void)
2297 #ifdef DSP_DIS_RESMAC
2299 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));
2301 RN = (uint32)dsp_acc;
2302 #ifdef DSP_DIS_RESMAC
2304 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2308 static void dsp_opcode_imult(void)
2310 #ifdef DSP_DIS_IMULT
2312 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);
2314 RN = (int16)RN * (int16)RM;
2316 #ifdef DSP_DIS_IMULT
2318 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);
2322 static void dsp_opcode_mult(void)
2326 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);
2328 RN = (uint16)RM * (uint16)RN;
2332 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);
2336 static void dsp_opcode_bclr(void)
2340 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);
2342 uint32 res = RN & ~(1 << IMM_1);
2347 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2351 static void dsp_opcode_btst(void)
2355 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);
2357 dsp_flag_z = (~RN >> IMM_1) & 1;
2360 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2364 static void dsp_opcode_bset(void)
2368 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);
2370 uint32 res = RN | (1 << IMM_1);
2375 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2379 static void dsp_opcode_subqt(void)
2381 #ifdef DSP_DIS_SUBQT
2383 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);
2385 RN -= dsp_convert_zero[IMM_1];
2386 #ifdef DSP_DIS_SUBQT
2388 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2392 static void dsp_opcode_addqt(void)
2394 #ifdef DSP_DIS_ADDQT
2396 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);
2398 RN += dsp_convert_zero[IMM_1];
2399 #ifdef DSP_DIS_ADDQT
2401 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2405 static void dsp_opcode_imacn(void)
2407 #ifdef DSP_DIS_IMACN
2409 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);
2411 int32 res = (int16)RM * (int16)RN;
2412 dsp_acc += (int64)res;
2413 //Should we AND the result to fit into 40 bits here???
2414 #ifdef DSP_DIS_IMACN
2416 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));
2420 static void dsp_opcode_mtoi(void)
2422 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2426 static void dsp_opcode_normi(void)
2433 while ((_Rm & 0xffc00000) == 0)
2438 while ((_Rm & 0xff800000) != 0)
2448 static void dsp_opcode_mmult(void)
2450 int count = dsp_matrix_control&0x0f;
2451 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2455 if (!(dsp_matrix_control & 0x10))
2457 for (int i = 0; i < count; i++)
2461 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2463 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2464 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2471 for (int i = 0; i < count; i++)
2475 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2477 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2478 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2483 RN = res = (int32)accum;
2485 //NOTE: The flags are set based upon the last add/multiply done...
2489 static void dsp_opcode_abs(void)
2493 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);
2498 if (_Rn == 0x80000000)
2502 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2503 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2508 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2512 static void dsp_opcode_div(void)
2519 if (dsp_div_control & 1)
2521 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2522 if (dsp_remain&0x80000000)
2524 RN = (((uint64)_Rn) << 16) / _Rm;
2528 dsp_remain = _Rn % _Rm;
2529 if (dsp_remain&0x80000000)
2538 static void dsp_opcode_imultn(void)
2540 #ifdef DSP_DIS_IMULTN
2542 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);
2544 // This is OK, since this multiply won't overflow 32 bits...
2545 int32 res = (int32)((int16)RN * (int16)RM);
2546 dsp_acc = (int64)res;
2548 #ifdef DSP_DIS_IMULTN
2550 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));
2554 static void dsp_opcode_neg(void)
2558 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);
2561 SET_ZNC_SUB(0, RN, res);
2565 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2569 static void dsp_opcode_shlq(void)
2573 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);
2575 int32 r1 = 32 - IMM_1;
2576 uint32 res = RN << r1;
2577 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2581 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2585 static void dsp_opcode_shrq(void)
2589 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);
2591 int32 r1 = dsp_convert_zero[IMM_1];
2592 uint32 res = RN >> r1;
2593 SET_ZN(res); dsp_flag_c = RN & 1;
2597 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2601 static void dsp_opcode_ror(void)
2605 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);
2607 uint32 r1 = RM & 0x1F;
2608 uint32 res = (RN >> r1) | (RN << (32 - r1));
2609 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2613 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);
2617 static void dsp_opcode_rorq(void)
2621 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);
2623 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2625 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2627 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2630 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2634 static void dsp_opcode_sha(void)
2636 int32 sRm=(int32)RM;
2642 if (shift>=32) shift=32;
2643 dsp_flag_c=(_Rn&0x80000000)>>31;
2653 if (shift>=32) shift=32;
2657 _Rn=((int32)_Rn)>>1;
2665 static void dsp_opcode_sharq(void)
2667 #ifdef DSP_DIS_SHARQ
2669 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);
2671 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2672 SET_ZN(res); dsp_flag_c = RN & 0x01;
2674 #ifdef DSP_DIS_SHARQ
2676 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2680 static void dsp_opcode_sh(void)
2682 int32 sRm=(int32)RM;
2687 uint32 shift=(-sRm);
2688 if (shift>=32) shift=32;
2689 dsp_flag_c=(_Rn&0x80000000)>>31;
2699 if (shift>=32) shift=32;
2711 void dsp_opcode_addqmod(void)
2713 #ifdef DSP_DIS_ADDQMOD
2715 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);
2717 uint32 r1 = dsp_convert_zero[IMM_1];
2719 uint32 res = r2 + r1;
2720 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2722 SET_ZNC_ADD(r2, r1, res);
2723 #ifdef DSP_DIS_ADDQMOD
2725 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2729 void dsp_opcode_subqmod(void)
2731 uint32 r1 = dsp_convert_zero[IMM_1];
2733 uint32 res = r2 - r1;
2734 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2737 SET_ZNC_SUB(r2, r1, res);
2740 void dsp_opcode_mirror(void)
2743 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2747 void dsp_opcode_sat32s(void)
2749 int32 r2 = (uint32)RN;
2750 int32 temp = dsp_acc >> 32;
2751 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2756 void dsp_opcode_sat16s(void)
2759 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2765 // New pipelined DSP core
2768 static void DSP_abs(void);
2769 static void DSP_add(void);
2770 static void DSP_addc(void);
2771 static void DSP_addq(void);
2772 static void DSP_addqmod(void);
2773 static void DSP_addqt(void);
2774 static void DSP_and(void);
2775 static void DSP_bclr(void);
2776 static void DSP_bset(void);
2777 static void DSP_btst(void);
2778 static void DSP_cmp(void);
2779 static void DSP_cmpq(void);
2780 static void DSP_div(void);
2781 static void DSP_imacn(void);
2782 static void DSP_imult(void);
2783 static void DSP_imultn(void);
2784 static void DSP_illegal(void);
2785 static void DSP_jr(void);
2786 static void DSP_jump(void);
2787 static void DSP_load(void);
2788 static void DSP_loadb(void);
2789 static void DSP_loadw(void);
2790 static void DSP_load_r14_i(void);
2791 static void DSP_load_r14_r(void);
2792 static void DSP_load_r15_i(void);
2793 static void DSP_load_r15_r(void);
2794 static void DSP_mirror(void);
2795 static void DSP_mmult(void);
2796 static void DSP_move(void);
2797 static void DSP_movefa(void);
2798 static void DSP_movei(void);
2799 static void DSP_movepc(void);
2800 static void DSP_moveq(void);
2801 static void DSP_moveta(void);
2802 static void DSP_mtoi(void);
2803 static void DSP_mult(void);
2804 static void DSP_neg(void);
2805 static void DSP_nop(void);
2806 static void DSP_normi(void);
2807 static void DSP_not(void);
2808 static void DSP_or(void);
2809 static void DSP_resmac(void);
2810 static void DSP_ror(void);
2811 static void DSP_rorq(void);
2812 static void DSP_sat16s(void);
2813 static void DSP_sat32s(void);
2814 static void DSP_sh(void);
2815 static void DSP_sha(void);
2816 static void DSP_sharq(void);
2817 static void DSP_shlq(void);
2818 static void DSP_shrq(void);
2819 static void DSP_store(void);
2820 static void DSP_storeb(void);
2821 static void DSP_storew(void);
2822 static void DSP_store_r14_i(void);
2823 static void DSP_store_r14_r(void);
2824 static void DSP_store_r15_i(void);
2825 static void DSP_store_r15_r(void);
2826 static void DSP_sub(void);
2827 static void DSP_subc(void);
2828 static void DSP_subq(void);
2829 static void DSP_subqmod(void);
2830 static void DSP_subqt(void);
2831 static void DSP_xor(void);
2833 void (* DSPOpcode[64])() =
2835 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2836 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2837 DSP_neg, DSP_and, DSP_or, DSP_xor,
2838 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2840 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2841 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2842 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2843 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2845 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2846 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2847 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2848 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2850 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2851 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2852 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2853 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2856 bool readAffected[64][2] =
2858 { true, true}, { true, true}, {false, true}, {false, true},
2859 { true, true}, { true, true}, {false, true}, {false, true},
2860 {false, true}, { true, true}, { true, true}, { true, true},
2861 {false, true}, {false, true}, {false, true}, {false, true},
2863 { true, true}, { true, true}, { true, true}, {false, true},
2864 { true, true}, { true, true}, {false, true}, { true, true},
2865 {false, true}, {false, true}, { true, true}, {false, true},
2866 { true, true}, {false, true}, { true, true}, {false, true},
2868 {false, true}, {false, true}, { true, false}, {false, false},
2869 { true, false}, {false, false}, {false, false}, { true, false},
2870 { true, false}, { true, false}, {false, true}, { true, false},
2871 { true, false}, { true, true}, { true, true}, { true, true},
2873 {false, true}, { true, true}, { true, true}, {false, true},
2874 { true, false}, { true, false}, { true, true}, { true, false},
2875 { true, false}, {false, false}, { true, false}, { true, false},
2876 { true, true}, { true, true}, {false, false}, {false, true}
2879 bool isLoadStore[65] =
2881 false, false, false, false, false, false, false, false,
2882 false, false, false, false, false, false, false, false,
2884 false, false, false, false, false, false, false, false,
2885 false, false, false, false, false, false, false, false,
2887 false, false, false, false, false, false, false, true,
2888 true, true, false, true, true, true, true, true,
2890 false, true, true, false, false, false, false, false,
2891 false, false, true, true, true, true, false, false, false
2894 void FlushDSPPipeline(void)
2896 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2898 for(int i=0; i<4; i++)
2899 pipeline[i].opcode = PIPELINE_STALL;
2901 for(int i=0; i<32; i++)
2906 // New pipelined DSP execution core
2908 /*void DSPExecP(int32 cycles)
2910 // bool inhibitFetch = false;
2912 dsp_releaseTimeSlice_flag = 0;
2915 while (cycles > 0 && DSP_RUNNING)
2917 WriteLog("DSPExecP: Pipeline status...\n");
2918 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);
2919 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);
2920 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);
2921 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);
2922 WriteLog(" --> Scoreboard: ");
2923 for(int i=0; i<32; i++)
2924 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2926 // Stage 1: Instruction fetch
2927 // if (!inhibitFetch)
2929 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2930 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2931 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2932 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2933 if (pipeline[plPtrFetch].opcode == 38)
2934 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2935 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2938 // inhibitFetch = false;
2939 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2941 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2942 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);
2943 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);
2944 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);
2945 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);
2946 // Stage 2: Read registers
2947 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2948 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2949 if (scoreboard[pipeline[plPtrRead].operand2])
2950 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2951 // We have a hit in the scoreboard, so we have to stall the pipeline...
2953 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2954 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2955 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2956 pipeline[plPtrFetch] = pipeline[plPtrRead];
2957 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2961 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2962 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2963 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2965 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2966 // Shouldn't we be more selective with the register scoreboarding?
2967 // Yes, we should. !!! FIX !!!
2968 scoreboard[pipeline[plPtrRead].operand2] = true;
2969 //Advance PC here??? Yes.
2970 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2971 //This is a mangling of the pipeline stages, but what else to do???
2972 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2975 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2976 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);
2977 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);
2978 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);
2979 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);
2981 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2983 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2984 DSPOpcode[pipeline[plPtrExec].opcode]();
2985 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2986 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2991 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2992 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);
2993 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);
2994 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);
2995 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);
2996 // Stage 4: Write back register
2997 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2999 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3000 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3002 scoreboard[pipeline[plPtrWrite].operand1]
3003 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3006 // Push instructions through the pipeline...
3007 plPtrFetch = (++plPtrFetch) & 0x03;
3008 plPtrRead = (++plPtrRead) & 0x03;
3009 plPtrExec = (++plPtrExec) & 0x03;
3010 plPtrWrite = (++plPtrWrite) & 0x03;
3017 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3019 // Should be fixed now. Another problem is figuring how to do the sequence following
3020 // a branch followed with the JR & JUMP instructions...
3022 // There are two conflicting problems:
3025 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3026 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3027 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3028 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3029 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3030 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3031 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3032 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3033 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3034 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3035 DSP: Finished interrupt.
3036 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3037 ; bank 0 (where is was prepared)!
3038 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3039 F1B252: NOP [NCZ:001]
3042 // The other is when you see this at the end of an IRQ:
3045 JUMP T, (R29) ; R29 = Previous stack + 2
3046 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3048 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3049 ; 1) The STORE goes through the pipeline and is executed/written back
3050 ; 2) The pipeline is flushed
3051 ; 3) The DSP_PC is set to the new address
3052 ; 4) Execution resumes
3054 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3055 ; bank 0 instead of the current bank 1 and so goes astray!
3058 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3059 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3063 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3064 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3065 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3066 If it were done properly, the STORE write back would occur *after* (well, technically,
3067 during) the execution of the the JUMP that follows it.
3071 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3072 F1B08A: NOP [NCZ:001]
3074 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3077 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3080 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3081 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3082 F1B08A: NOP [NCZ:001]
3084 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3087 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3088 DSP: CPU -> DSP interrupt
3089 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3090 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3092 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3095 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3096 F1B006: NOP [NCZ:001]
3098 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3101 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3102 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3105 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3106 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3109 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3110 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3113 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3114 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3117 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3120 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3123 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3124 F1B0FE: NOP [NCZ:000]
3126 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3129 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3132 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3133 F1B138: NOP [NCZ:000]
3135 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3138 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3139 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3140 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3143 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3144 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3147 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3148 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3149 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3151 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3152 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3155 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3156 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3157 DSP: Finished interrupt.
3158 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3160 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3163 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3164 F1B016: NOP [NCZ:001]
3166 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3169 uint32 pcQueue1[0x400];
3171 static uint32 prevR1;
3172 //Let's try a 3 stage pipeline....
3173 //Looks like 3 stage is correct, otherwise bad things happen...
3174 void DSPExecP2(int32 cycles)
3176 dsp_releaseTimeSlice_flag = 0;
3179 while (cycles > 0 && DSP_RUNNING)
3181 /*extern uint32 totalFrames;
3182 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3183 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3184 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3186 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3189 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3191 if (dsp_pc == 0xF1B092)
3192 doDSPDis = false;//*/
3193 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3194 doDSPDis = true;//*/
3195 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3196 doDSPDis = true;//*/
3197 /*if (dsp_pc == 0xF1B0A0)
3198 doDSPDis = true;//*/
3199 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3200 doDSPDis = true;//*/
3201 //Two parter... (not sure how to write this)
3202 //if (dsp_pc == 0xF1B0D2)
3203 // prevR1 = dsp_reg[1];
3205 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3206 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3209 pcQueue1[pcQPtr1++] = dsp_pc;
3212 #ifdef DSP_DEBUG_PL2
3213 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3215 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3220 for(int i=0; i<0x400; i++)
3222 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3223 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3229 if (IMASKCleared) // If IMASK was cleared,
3231 #ifdef DSP_DEBUG_IRQ
3232 WriteLog("DSP: Finished interrupt.\n");
3234 DSPHandleIRQs(); // See if any other interrupts are pending!
3235 IMASKCleared = false;
3238 //if (dsp_flags & REGPAGE)
3239 // WriteLog(" --> REGPAGE has just been set!\n");
3240 #ifdef DSP_DEBUG_PL2
3243 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3244 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]);
3245 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]);
3246 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]);
3247 WriteLog(" --> Scoreboard: ");
3248 for(int i=0; i<32; i++)
3249 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3253 // Stage 1a: Instruction fetch
3254 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3255 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3256 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3257 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3258 if (pipeline[plPtrRead].opcode == 38)
3259 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3260 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3261 #ifdef DSP_DEBUG_PL2
3264 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3265 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3266 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]);
3267 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]);
3268 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]);
3271 // Stage 1b: Read registers
3272 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3273 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3275 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3276 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3277 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3278 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3279 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3280 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3281 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3283 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3284 // We have a hit in the scoreboard, so we have to stall the pipeline...
3285 #ifdef DSP_DEBUG_PL2
3289 WriteLog(" --> Stalling pipeline: ");
3290 if (readAffected[pipeline[plPtrRead].opcode][0])
3291 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3292 if (readAffected[pipeline[plPtrRead].opcode][1])
3293 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3297 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3298 #ifdef DSP_DEBUG_PL2
3303 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3304 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3305 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3307 // Shouldn't we be more selective with the register scoreboarding?
3308 // Yes, we should. !!! FIX !!! Kinda [DONE]
3309 #ifndef NEW_SCOREBOARD
3310 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3312 //Hopefully this will fix the dual MOVEQ # problem...
3313 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3316 //Advance PC here??? Yes.
3317 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3320 #ifdef DSP_DEBUG_PL2
3323 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3324 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]);
3325 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]);
3326 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]);
3330 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3332 #ifdef DSP_DEBUG_PL2
3334 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"));
3338 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3343 lastExec = pipeline[plPtrExec].instruction;
3344 //WriteLog("[lastExec = %04X]\n", lastExec);
3346 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3347 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3348 DSPOpcode[pipeline[plPtrExec].opcode]();
3349 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3353 //Let's not, until we do the stalling correctly...
3354 //But, we gotta while we're doing the comparison core...!
3355 //Or do we? cycles--;
3356 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3357 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3358 //to model this clock cycle behavior correctly...
3359 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3360 //don't affect the reads at stage 1...
3361 #ifdef DSP_DEBUG_STALL
3363 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3367 #ifdef DSP_DEBUG_PL2
3370 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3371 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]);
3372 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]);
3373 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]);
3377 // Stage 3: Write back register/memory address
3378 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3380 /*if (pipeline[plPtrWrite].writebackRegister == 3
3381 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3384 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3387 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3389 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3390 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3393 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3394 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3395 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3396 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3398 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3402 #ifndef NEW_SCOREBOARD
3403 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3404 scoreboard[pipeline[plPtrWrite].operand2] = false;
3406 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3407 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3408 if (scoreboard[pipeline[plPtrWrite].operand2])
3409 scoreboard[pipeline[plPtrWrite].operand2]--;
3413 // Push instructions through the pipeline...
3414 plPtrRead = (++plPtrRead) & 0x03;
3415 plPtrExec = (++plPtrExec) & 0x03;
3416 plPtrWrite = (++plPtrWrite) & 0x03;
3425 //#define DSP_DEBUG_PL3
3426 //Let's try a 2 stage pipeline....
3427 void DSPExecP3(int32 cycles)
3429 dsp_releaseTimeSlice_flag = 0;
3432 while (cycles > 0 && DSP_RUNNING)
3434 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3436 #ifdef DSP_DEBUG_PL3
3437 WriteLog("DSPExecP: Pipeline status...\n");
3438 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]);
3439 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]);
3440 WriteLog(" --> Scoreboard: ");
3441 for(int i=0; i<32; i++)
3442 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3445 // Stage 1a: Instruction fetch
3446 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3447 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3448 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3449 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3450 if (pipeline[plPtrRead].opcode == 38)
3451 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3452 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3453 #ifdef DSP_DEBUG_PL3
3454 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3455 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3456 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]);
3457 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]);
3459 // Stage 1b: Read registers
3460 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3461 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3462 // We have a hit in the scoreboard, so we have to stall the pipeline...
3463 #ifdef DSP_DEBUG_PL3
3465 WriteLog(" --> Stalling pipeline: ");
3466 if (readAffected[pipeline[plPtrRead].opcode][0])
3467 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3468 if (readAffected[pipeline[plPtrRead].opcode][1])
3469 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3472 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3473 #ifdef DSP_DEBUG_PL3
3478 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3479 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3480 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3482 // Shouldn't we be more selective with the register scoreboarding?
3483 // Yes, we should. !!! FIX !!! [Kinda DONE]
3484 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3486 //Advance PC here??? Yes.
3487 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3490 #ifdef DSP_DEBUG_PL3
3491 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3492 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]);
3493 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]);
3495 // Stage 2a: Execute
3496 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3498 #ifdef DSP_DEBUG_PL3
3499 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3501 DSPOpcode[pipeline[plPtrExec].opcode]();
3502 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3503 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3508 #ifdef DSP_DEBUG_PL3
3509 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3510 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]);
3511 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]);
3514 // Stage 2b: Write back register
3515 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3517 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3518 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3520 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3521 scoreboard[pipeline[plPtrExec].operand2] = false;
3524 // Push instructions through the pipeline...
3525 plPtrRead = (++plPtrRead) & 0x03;
3526 plPtrExec = (++plPtrExec) & 0x03;
3533 // DSP pipelined opcode handlers
3536 #define PRM pipeline[plPtrExec].reg1
3537 #define PRN pipeline[plPtrExec].reg2
3538 #define PIMM1 pipeline[plPtrExec].operand1
3539 #define PIMM2 pipeline[plPtrExec].operand2
3540 #define PRES pipeline[plPtrExec].result
3541 #define PWBR pipeline[plPtrExec].writebackRegister
3542 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3543 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3544 #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))
3545 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3547 static void DSP_abs(void)
3551 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);
3555 if (_Rn == 0x80000000)
3559 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3560 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3561 CLR_ZN; SET_Z(PRES);
3565 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3569 static void DSP_add(void)
3573 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);
3575 uint32 res = PRN + PRM;
3576 SET_ZNC_ADD(PRN, PRM, res);
3580 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);
3584 static void DSP_addc(void)
3588 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);
3590 uint32 res = PRN + PRM + dsp_flag_c;
3591 uint32 carry = dsp_flag_c;
3592 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3593 SET_ZNC_ADD(PRN + carry, PRM, res);
3594 // SET_ZNC_ADD(PRN, PRM + carry, res);
3598 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);
3602 static void DSP_addq(void)
3606 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);
3608 uint32 r1 = dsp_convert_zero[PIMM1];
3609 uint32 res = PRN + r1;
3610 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3614 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3618 static void DSP_addqmod(void)
3620 #ifdef DSP_DIS_ADDQMOD
3622 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);
3624 uint32 r1 = dsp_convert_zero[PIMM1];
3626 uint32 res = r2 + r1;
3627 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3629 SET_ZNC_ADD(r2, r1, res);
3630 #ifdef DSP_DIS_ADDQMOD
3632 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3636 static void DSP_addqt(void)
3638 #ifdef DSP_DIS_ADDQT
3640 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);
3642 PRES = PRN + dsp_convert_zero[PIMM1];
3643 #ifdef DSP_DIS_ADDQT
3645 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3649 static void DSP_and(void)
3653 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);
3659 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);
3663 static void DSP_bclr(void)
3667 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);
3669 PRES = PRN & ~(1 << PIMM1);
3673 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3677 static void DSP_bset(void)
3681 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);
3683 PRES = PRN | (1 << PIMM1);
3687 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3691 static void DSP_btst(void)
3695 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);
3697 dsp_flag_z = (~PRN >> PIMM1) & 1;
3701 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3705 static void DSP_cmp(void)
3709 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);
3711 uint32 res = PRN - PRM;
3712 SET_ZNC_SUB(PRN, PRM, res);
3716 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3720 static void DSP_cmpq(void)
3722 static int32 sqtable[32] =
3723 { 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 };
3726 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);
3728 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3729 uint32 res = PRN - r1;
3730 SET_ZNC_SUB(PRN, r1, res);
3734 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3738 static void DSP_div(void)
3740 uint32 _Rm = PRM, _Rn = PRN;
3744 if (dsp_div_control & 1)
3746 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3747 if (dsp_remain & 0x80000000)
3749 PRES = (((uint64)_Rn) << 16) / _Rm;
3753 dsp_remain = _Rn % _Rm;
3754 if (dsp_remain & 0x80000000)
3763 static void DSP_imacn(void)
3765 #ifdef DSP_DIS_IMACN
3767 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);
3769 int32 res = (int16)PRM * (int16)PRN;
3770 dsp_acc += (int64)res;
3771 //Should we AND the result to fit into 40 bits here???
3773 #ifdef DSP_DIS_IMACN
3775 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));
3779 static void DSP_imult(void)
3781 #ifdef DSP_DIS_IMULT
3783 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);
3785 PRES = (int16)PRN * (int16)PRM;
3787 #ifdef DSP_DIS_IMULT
3789 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);
3793 static void DSP_imultn(void)
3795 #ifdef DSP_DIS_IMULTN
3797 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);
3799 // This is OK, since this multiply won't overflow 32 bits...
3800 int32 res = (int32)((int16)PRN * (int16)PRM);
3801 dsp_acc = (int64)res;
3804 #ifdef DSP_DIS_IMULTN
3806 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));
3810 static void DSP_illegal(void)
3812 #ifdef DSP_DIS_ILLEGAL
3814 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3819 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3820 // can cause trouble because an interrupt can occur *before* the instruction following the
3821 // jump can execute... !!! FIX !!!
3822 // This can probably be solved by judicious coding in the pipeline execution core...
3823 // And should be fixed now...
3824 static void DSP_jr(void)
3827 const char * condition[32] =
3828 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3829 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3830 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3831 "???", "???", "???", "F" };
3833 //How come this is always off by 2???
3834 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);
3836 // KLUDGE: Used by BRANCH_CONDITION macro
3837 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3839 if (BRANCH_CONDITION(PIMM2))
3843 WriteLog("Branched!\n");
3845 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3846 //Account for pipeline effects...
3847 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3848 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3850 // Now that we've branched, we have to make sure that the following instruction
3851 // is executed atomically with this one and then flush the pipeline before setting
3854 // Step 1: Handle writebacks at stage 3 of pipeline
3855 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3857 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3858 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3860 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3861 scoreboard[pipeline[plPtrWrite].operand2] = false;
3863 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3865 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3867 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3868 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3871 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3872 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3873 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3874 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3876 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3880 #ifndef NEW_SCOREBOARD
3881 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3882 scoreboard[pipeline[plPtrWrite].operand2] = false;
3884 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3885 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3886 if (scoreboard[pipeline[plPtrWrite].operand2])
3887 scoreboard[pipeline[plPtrWrite].operand2]--;
3891 // Step 2: Push instruction through pipeline & execute following instruction
3892 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3893 // we effectively handle the final push of the instruction through the
3894 // pipeline when the new PC takes effect (since when we return, the
3895 // pipeline code will be executing the writeback stage. If we reverse
3896 // the execution order of the pipeline stages, this will no longer be
3898 pipeline[plPtrExec] = pipeline[plPtrRead];
3899 //This is BAD. We need to get that next opcode and execute it!
3900 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3901 // remove this crap.
3902 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3904 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3905 pipeline[plPtrExec].opcode = instruction >> 10;
3906 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3907 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3908 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3909 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3910 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3912 dsp_pc += 2; // For DSP_DIS_* accuracy
3913 DSPOpcode[pipeline[plPtrExec].opcode]();
3914 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3915 pipeline[plPtrWrite] = pipeline[plPtrExec];
3917 // Step 3: Flush pipeline & set new PC
3918 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3925 WriteLog("Branch NOT taken.\n");
3931 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3934 static void DSP_jump(void)
3937 const char * condition[32] =
3938 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3939 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3940 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3941 "???", "???", "???", "F" };
3943 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);
3945 // KLUDGE: Used by BRANCH_CONDITION macro
3946 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3948 if (BRANCH_CONDITION(PIMM2))
3952 WriteLog("Branched!\n");
3954 uint32 PCSave = PRM;
3955 // Now that we've branched, we have to make sure that the following instruction
3956 // is executed atomically with this one and then flush the pipeline before setting
3959 // Step 1: Handle writebacks at stage 3 of pipeline
3960 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3962 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3963 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3965 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3966 scoreboard[pipeline[plPtrWrite].operand2] = false;
3968 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3970 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3972 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3973 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3976 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3977 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3978 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3979 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3981 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3985 #ifndef NEW_SCOREBOARD
3986 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3987 scoreboard[pipeline[plPtrWrite].operand2] = false;
3989 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3990 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3991 if (scoreboard[pipeline[plPtrWrite].operand2])
3992 scoreboard[pipeline[plPtrWrite].operand2]--;
3996 // Step 2: Push instruction through pipeline & execute following instruction
3997 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3998 // we effectively handle the final push of the instruction through the
3999 // pipeline when the new PC takes effect (since when we return, the
4000 // pipeline code will be executing the writeback stage. If we reverse
4001 // the execution order of the pipeline stages, this will no longer be
4003 pipeline[plPtrExec] = pipeline[plPtrRead];
4004 //This is BAD. We need to get that next opcode and execute it!
4005 //Also, same problem in JR!
4006 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4007 // remove this crap.
4008 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
4010 uint16 instruction = DSPReadWord(dsp_pc, DSP);
4011 pipeline[plPtrExec].opcode = instruction >> 10;
4012 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4013 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4014 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4015 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4016 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4018 dsp_pc += 2; // For DSP_DIS_* accuracy
4019 DSPOpcode[pipeline[plPtrExec].opcode]();
4020 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4021 pipeline[plPtrWrite] = pipeline[plPtrExec];
4023 // Step 3: Flush pipeline & set new PC
4024 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4031 WriteLog("Branch NOT taken.\n");
4039 static void DSP_load(void)
4043 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);
4045 #ifdef DSP_CORRECT_ALIGNMENT
4046 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4048 PRES = DSPReadLong(PRM, DSP);
4052 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4056 static void DSP_loadb(void)
4058 #ifdef DSP_DIS_LOADB
4060 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);
4062 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4063 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4065 PRES = JaguarReadByte(PRM, DSP);
4066 #ifdef DSP_DIS_LOADB
4068 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4072 static void DSP_loadw(void)
4074 #ifdef DSP_DIS_LOADW
4076 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);
4078 #ifdef DSP_CORRECT_ALIGNMENT
4079 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4080 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4082 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4084 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4085 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4087 PRES = JaguarReadWord(PRM, DSP);
4089 #ifdef DSP_DIS_LOADW
4091 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4095 static void DSP_load_r14_i(void)
4097 #ifdef DSP_DIS_LOAD14I
4099 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);
4101 #ifdef DSP_CORRECT_ALIGNMENT
4102 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4104 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4106 #ifdef DSP_DIS_LOAD14I
4108 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4112 static void DSP_load_r14_r(void)
4114 #ifdef DSP_DIS_LOAD14R
4116 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);
4118 #ifdef DSP_CORRECT_ALIGNMENT
4119 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4121 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4123 #ifdef DSP_DIS_LOAD14R
4125 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4129 static void DSP_load_r15_i(void)
4131 #ifdef DSP_DIS_LOAD15I
4133 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);
4135 #ifdef DSP_CORRECT_ALIGNMENT
4136 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4138 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4140 #ifdef DSP_DIS_LOAD15I
4142 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4146 static void DSP_load_r15_r(void)
4148 #ifdef DSP_DIS_LOAD15R
4150 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);
4152 #ifdef DSP_CORRECT_ALIGNMENT
4153 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4155 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4157 #ifdef DSP_DIS_LOAD15R
4159 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4163 static void DSP_mirror(void)
4166 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4170 static void DSP_mmult(void)
4172 int count = dsp_matrix_control&0x0f;
4173 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4177 if (!(dsp_matrix_control & 0x10))
4179 for (int i = 0; i < count; i++)
4183 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4185 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4186 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4193 for (int i = 0; i < count; i++)
4197 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4199 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4200 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4206 PRES = res = (int32)accum;
4208 //NOTE: The flags are set based upon the last add/multiply done...
4212 static void DSP_move(void)
4216 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);
4221 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);
4225 static void DSP_movefa(void)
4227 #ifdef DSP_DIS_MOVEFA
4229 // 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);
4230 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);
4232 // PRES = ALTERNATE_RM;
4233 PRES = dsp_alternate_reg[PIMM1];
4234 #ifdef DSP_DIS_MOVEFA
4236 // 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);
4237 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);
4241 static void DSP_movei(void)
4243 #ifdef DSP_DIS_MOVEI
4245 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);
4247 // // This instruction is followed by 32-bit value in LSW / MSW format...
4248 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4250 #ifdef DSP_DIS_MOVEI
4252 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4256 static void DSP_movepc(void)
4258 #ifdef DSP_DIS_MOVEPC
4260 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);
4262 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4263 // PRES = dsp_pc - 2;
4264 //Account for pipeline effects...
4265 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4266 #ifdef DSP_DIS_MOVEPC
4268 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4272 static void DSP_moveq(void)
4274 #ifdef DSP_DIS_MOVEQ
4276 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);
4279 #ifdef DSP_DIS_MOVEQ
4281 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4285 static void DSP_moveta(void)
4287 #ifdef DSP_DIS_MOVETA
4289 // 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);
4290 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]);
4292 // ALTERNATE_RN = PRM;
4293 dsp_alternate_reg[PIMM2] = PRM;
4295 #ifdef DSP_DIS_MOVETA
4297 // 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);
4298 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]);
4302 static void DSP_mtoi(void)
4304 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4308 static void DSP_mult(void)
4312 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);
4314 PRES = (uint16)PRM * (uint16)PRN;
4318 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);
4322 static void DSP_neg(void)
4326 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);
4329 SET_ZNC_SUB(0, PRN, res);
4333 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4337 static void DSP_nop(void)
4341 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4346 static void DSP_normi(void)
4353 while ((_Rm & 0xffc00000) == 0)
4358 while ((_Rm & 0xff800000) != 0)
4368 static void DSP_not(void)
4372 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);
4378 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4382 static void DSP_or(void)
4386 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);
4392 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);
4396 static void DSP_resmac(void)
4398 #ifdef DSP_DIS_RESMAC
4400 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));
4402 PRES = (uint32)dsp_acc;
4403 #ifdef DSP_DIS_RESMAC
4405 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4409 static void DSP_ror(void)
4413 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);
4415 uint32 r1 = PRM & 0x1F;
4416 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4417 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4421 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);
4425 static void DSP_rorq(void)
4429 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);
4431 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4433 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4435 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4438 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4442 static void DSP_sat16s(void)
4445 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4450 static void DSP_sat32s(void)
4452 int32 r2 = (uint32)PRN;
4453 int32 temp = dsp_acc >> 32;
4454 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4459 static void DSP_sh(void)
4461 int32 sRm = (int32)PRM;
4466 uint32 shift = -sRm;
4471 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4486 dsp_flag_c = _Rn & 0x1;
4499 static void DSP_sha(void)
4501 int32 sRm = (int32)PRM;
4506 uint32 shift = -sRm;
4511 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4526 dsp_flag_c = _Rn & 0x1;
4530 _Rn = ((int32)_Rn) >> 1;
4539 static void DSP_sharq(void)
4541 #ifdef DSP_DIS_SHARQ
4543 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);
4545 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4546 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4548 #ifdef DSP_DIS_SHARQ
4550 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4554 static void DSP_shlq(void)
4558 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);
4560 int32 r1 = 32 - PIMM1;
4561 uint32 res = PRN << r1;
4562 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4570 static void DSP_shrq(void)
4574 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);
4576 int32 r1 = dsp_convert_zero[PIMM1];
4577 uint32 res = PRN >> r1;
4578 SET_ZN(res); dsp_flag_c = PRN & 1;
4582 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4586 static void DSP_store(void)
4588 #ifdef DSP_DIS_STORE
4590 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);
4592 // DSPWriteLong(PRM, PRN, DSP);
4594 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4595 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4597 pipeline[plPtrExec].address = PRM;
4599 pipeline[plPtrExec].value = PRN;
4600 pipeline[plPtrExec].type = TYPE_DWORD;
4604 static void DSP_storeb(void)
4606 #ifdef DSP_DIS_STOREB
4608 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);
4610 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4611 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4613 // JaguarWriteByte(PRM, PRN, DSP);
4616 pipeline[plPtrExec].address = PRM;
4618 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4620 pipeline[plPtrExec].value = PRN & 0xFF;
4621 pipeline[plPtrExec].type = TYPE_DWORD;
4625 pipeline[plPtrExec].value = PRN;
4626 pipeline[plPtrExec].type = TYPE_BYTE;
4632 static void DSP_storew(void)
4634 #ifdef DSP_DIS_STOREW
4636 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);
4638 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4639 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4641 // JaguarWriteWord(PRM, PRN, DSP);
4644 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4645 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4647 pipeline[plPtrExec].address = PRM;
4650 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4652 pipeline[plPtrExec].value = PRN & 0xFFFF;
4653 pipeline[plPtrExec].type = TYPE_DWORD;
4657 pipeline[plPtrExec].value = PRN;
4658 pipeline[plPtrExec].type = TYPE_WORD;
4663 static void DSP_store_r14_i(void)
4665 #ifdef DSP_DIS_STORE14I
4667 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));
4669 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4671 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4672 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4674 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4676 pipeline[plPtrExec].value = PRN;
4677 pipeline[plPtrExec].type = TYPE_DWORD;
4681 static void DSP_store_r14_r(void)
4683 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4685 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4686 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4688 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4690 pipeline[plPtrExec].value = PRN;
4691 pipeline[plPtrExec].type = TYPE_DWORD;
4695 static void DSP_store_r15_i(void)
4697 #ifdef DSP_DIS_STORE15I
4699 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));
4701 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4703 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4704 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4706 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4708 pipeline[plPtrExec].value = PRN;
4709 pipeline[plPtrExec].type = TYPE_DWORD;
4713 static void DSP_store_r15_r(void)
4715 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4717 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4718 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4720 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4722 pipeline[plPtrExec].value = PRN;
4723 pipeline[plPtrExec].type = TYPE_DWORD;
4727 static void DSP_sub(void)
4731 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);
4733 uint32 res = PRN - PRM;
4734 SET_ZNC_SUB(PRN, PRM, res);
4738 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);
4742 static void DSP_subc(void)
4746 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);
4748 uint32 res = PRN - PRM - dsp_flag_c;
4749 uint32 borrow = dsp_flag_c;
4750 SET_ZNC_SUB(PRN - borrow, PRM, res);
4754 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);
4758 static void DSP_subq(void)
4762 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);
4764 uint32 r1 = dsp_convert_zero[PIMM1];
4765 uint32 res = PRN - r1;
4766 SET_ZNC_SUB(PRN, r1, res);
4770 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4774 static void DSP_subqmod(void)
4776 uint32 r1 = dsp_convert_zero[PIMM1];
4778 uint32 res = r2 - r1;
4779 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4781 SET_ZNC_SUB(r2, r1, res);
4784 static void DSP_subqt(void)
4786 #ifdef DSP_DIS_SUBQT
4788 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);
4790 PRES = PRN - dsp_convert_zero[PIMM1];
4791 #ifdef DSP_DIS_SUBQT
4793 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4797 static void DSP_xor(void)
4801 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);
4807 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);