4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 11/26/2011 Added fixes for LOAD/STORE alignment issues
19 #include <SDL.h> // Used only for SDL_GetTicks...
32 // Seems alignment in loads & stores was off...
33 #define DSP_CORRECT_ALIGNMENT
34 //#define DSP_CORRECT_ALIGNMENT_STORE
37 //#define DSP_DEBUG_IRQ
38 //#define DSP_DEBUG_PL2
39 //#define DSP_DEBUG_STALL
40 //#define DSP_DEBUG_CC
41 #define NEW_SCOREBOARD
43 // Disassembly definitions
50 #define DSP_DIS_ADDQMOD
60 #define DSP_DIS_IMULTN
61 #define DSP_DIS_ILLEGAL
65 #define DSP_DIS_LOAD14I
66 #define DSP_DIS_LOAD14R
67 #define DSP_DIS_LOAD15I
68 #define DSP_DIS_LOAD15R
74 #define DSP_DIS_MOVEFA
75 #define DSP_DIS_MOVEPC // Pipeline only!
76 #define DSP_DIS_MOVETA
82 #define DSP_DIS_RESMAC
89 #define DSP_DIS_STORE14I
90 #define DSP_DIS_STORE15I
91 #define DSP_DIS_STOREB
92 #define DSP_DIS_STOREW
99 bool doDSPDis = false;
100 //bool doDSPDis = true;
135 + load_r15_indexed 284500
137 + store_r15_indexed 47416
141 + load_r14_ri 1229448
144 // Pipeline structures
146 const bool affectsScoreboard[64] =
148 true, true, true, true,
149 true, true, true, true,
150 true, true, true, true,
151 true, false, true, true,
153 true, true, false, true,
154 false, true, true, true,
155 true, true, true, true,
156 true, true, false, false,
158 true, true, true, true,
159 false, true, true, true,
160 true, true, true, true,
161 true, false, false, false,
163 true, false, false, true,
164 false, false, true, true,
165 true, false, true, true,
166 false, false, false, true
172 uint8 opcode, operand1, operand2;
173 uint32 reg1, reg2, areg1, areg2;
175 uint8 writebackRegister;
176 // General memory store...
185 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
186 #ifndef NEW_SCOREBOARD
189 uint8 scoreboard[32];
191 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
192 PipelineStage pipeline[4];
193 bool IMASKCleared = false;
195 // DSP flags (old--have to get rid of this crap)
197 #define CINT0FLAG 0x00200
198 #define CINT1FLAG 0x00400
199 #define CINT2FLAG 0x00800
200 #define CINT3FLAG 0x01000
201 #define CINT4FLAG 0x02000
202 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
203 #define CINT5FLAG 0x20000 /* DSP only */
207 #define ZERO_FLAG 0x00001
208 #define CARRY_FLAG 0x00002
209 #define NEGA_FLAG 0x00004
210 #define IMASK 0x00008
211 #define INT_ENA0 0x00010
212 #define INT_ENA1 0x00020
213 #define INT_ENA2 0x00040
214 #define INT_ENA3 0x00080
215 #define INT_ENA4 0x00100
216 #define INT_CLR0 0x00200
217 #define INT_CLR1 0x00400
218 #define INT_CLR2 0x00800
219 #define INT_CLR3 0x01000
220 #define INT_CLR4 0x02000
221 #define REGPAGE 0x04000
222 #define DMAEN 0x08000
223 #define INT_ENA5 0x10000
224 #define INT_CLR5 0x20000
228 #define DSPGO 0x00001
229 #define CPUINT 0x00002
230 #define DSPINT0 0x00004
231 #define SINGLE_STEP 0x00008
232 #define SINGLE_GO 0x00010
234 #define INT_LAT0 0x00040
235 #define INT_LAT1 0x00080
236 #define INT_LAT2 0x00100
237 #define INT_LAT3 0x00200
238 #define INT_LAT4 0x00400
239 #define BUS_HOG 0x00800
240 #define VERSION 0x0F000
241 #define INT_LAT5 0x10000
243 extern uint32 jaguar_mainRom_crc32;
245 // Is opcode 62 *really* a NOP? Seems like it...
246 static void dsp_opcode_abs(void);
247 static void dsp_opcode_add(void);
248 static void dsp_opcode_addc(void);
249 static void dsp_opcode_addq(void);
250 static void dsp_opcode_addqmod(void);
251 static void dsp_opcode_addqt(void);
252 static void dsp_opcode_and(void);
253 static void dsp_opcode_bclr(void);
254 static void dsp_opcode_bset(void);
255 static void dsp_opcode_btst(void);
256 static void dsp_opcode_cmp(void);
257 static void dsp_opcode_cmpq(void);
258 static void dsp_opcode_div(void);
259 static void dsp_opcode_imacn(void);
260 static void dsp_opcode_imult(void);
261 static void dsp_opcode_imultn(void);
262 static void dsp_opcode_jr(void);
263 static void dsp_opcode_jump(void);
264 static void dsp_opcode_load(void);
265 static void dsp_opcode_loadb(void);
266 static void dsp_opcode_loadw(void);
267 static void dsp_opcode_load_r14_indexed(void);
268 static void dsp_opcode_load_r14_ri(void);
269 static void dsp_opcode_load_r15_indexed(void);
270 static void dsp_opcode_load_r15_ri(void);
271 static void dsp_opcode_mirror(void);
272 static void dsp_opcode_mmult(void);
273 static void dsp_opcode_move(void);
274 static void dsp_opcode_movei(void);
275 static void dsp_opcode_movefa(void);
276 static void dsp_opcode_move_pc(void);
277 static void dsp_opcode_moveq(void);
278 static void dsp_opcode_moveta(void);
279 static void dsp_opcode_mtoi(void);
280 static void dsp_opcode_mult(void);
281 static void dsp_opcode_neg(void);
282 static void dsp_opcode_nop(void);
283 static void dsp_opcode_normi(void);
284 static void dsp_opcode_not(void);
285 static void dsp_opcode_or(void);
286 static void dsp_opcode_resmac(void);
287 static void dsp_opcode_ror(void);
288 static void dsp_opcode_rorq(void);
289 static void dsp_opcode_xor(void);
290 static void dsp_opcode_sat16s(void);
291 static void dsp_opcode_sat32s(void);
292 static void dsp_opcode_sh(void);
293 static void dsp_opcode_sha(void);
294 static void dsp_opcode_sharq(void);
295 static void dsp_opcode_shlq(void);
296 static void dsp_opcode_shrq(void);
297 static void dsp_opcode_store(void);
298 static void dsp_opcode_storeb(void);
299 static void dsp_opcode_storew(void);
300 static void dsp_opcode_store_r14_indexed(void);
301 static void dsp_opcode_store_r14_ri(void);
302 static void dsp_opcode_store_r15_indexed(void);
303 static void dsp_opcode_store_r15_ri(void);
304 static void dsp_opcode_sub(void);
305 static void dsp_opcode_subc(void);
306 static void dsp_opcode_subq(void);
307 static void dsp_opcode_subqmod(void);
308 static void dsp_opcode_subqt(void);
310 uint8 dsp_opcode_cycles[64] =
312 3, 3, 3, 3, 3, 3, 3, 3,
313 3, 3, 3, 3, 3, 3, 3, 3,
314 3, 3, 1, 3, 1, 18, 3, 3,
315 3, 3, 3, 3, 3, 3, 3, 3,
316 3, 3, 2, 2, 2, 2, 3, 4,
317 5, 4, 5, 6, 6, 1, 1, 1,
318 1, 2, 2, 2, 1, 1, 9, 3,
319 3, 1, 6, 6, 2, 2, 3, 3
321 //Here's a QnD kludge...
322 //This is wrong, wrong, WRONG, but it seems to work for the time being...
323 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
324 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
325 /*uint8 dsp_opcode_cycles[64] =
327 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 1,
329 1, 1, 1, 1, 1, 9, 1, 1,
330 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 2,
332 2, 2, 2, 3, 3, 1, 1, 1,
333 1, 1, 1, 1, 1, 1, 4, 1,
334 1, 1, 3, 3, 1, 1, 1, 1
337 void (* dsp_opcode[64])() =
339 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
340 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
341 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
342 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
343 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
344 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
345 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
346 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
347 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
348 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
349 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
350 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
351 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
352 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
353 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
354 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
357 uint32 dsp_opcode_use[65];
359 const char * dsp_opcode_str[65]=
361 "add", "addc", "addq", "addqt",
362 "sub", "subc", "subq", "subqt",
363 "neg", "and", "or", "xor",
364 "not", "btst", "bset", "bclr",
365 "mult", "imult", "imultn", "resmac",
366 "imacn", "div", "abs", "sh",
367 "shlq", "shrq", "sha", "sharq",
368 "ror", "rorq", "cmp", "cmpq",
369 "subqmod", "sat16s", "move", "moveq",
370 "moveta", "movefa", "movei", "loadb",
371 "loadw", "load", "sat32s", "load_r14_indexed",
372 "load_r15_indexed", "storeb", "storew", "store",
373 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
374 "jump", "jr", "mmult", "mtoi",
375 "normi", "nop", "load_r14_ri", "load_r15_ri",
376 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
381 static uint64 dsp_acc; // 40 bit register, NOT 32!
382 static uint32 dsp_remain;
383 static uint32 dsp_modulo;
384 static uint32 dsp_flags;
385 static uint32 dsp_matrix_control;
386 static uint32 dsp_pointer_to_matrix;
387 static uint32 dsp_data_organization;
389 static uint32 dsp_div_control;
390 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
391 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
392 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
394 static uint32 dsp_opcode_first_parameter;
395 static uint32 dsp_opcode_second_parameter;
397 #define DSP_RUNNING (dsp_control & 0x01)
399 #define RM dsp_reg[dsp_opcode_first_parameter]
400 #define RN dsp_reg[dsp_opcode_second_parameter]
401 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
402 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
403 #define IMM_1 dsp_opcode_first_parameter
404 #define IMM_2 dsp_opcode_second_parameter
406 #define CLR_Z (dsp_flag_z = 0)
407 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
408 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
409 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
410 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
411 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
412 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
413 #define SET_ZN(r) SET_N(r); SET_Z(r)
414 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
415 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
417 uint32 dsp_convert_zero[32] = {
418 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
419 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
421 uint8 dsp_branch_condition_table[32 * 8];
422 static uint16 mirror_table[65536];
423 static uint8 dsp_ram_8[0x2000];
425 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
427 static uint32 dsp_in_exec = 0;
428 static uint32 dsp_releaseTimeSlice_flag = 0;
433 // Comparison core vars (used only for core comparison! :-)
434 static uint64 count = 0;
435 static uint8 ram1[0x2000], ram2[0x2000];
436 static uint32 regs1[64], regs2[64];
437 static uint32 ctrl1[14], ctrl2[14];
440 // Private function prototypes
442 void DSPDumpRegisters(void);
443 void DSPDumpDisassembly(void);
444 void FlushDSPPipeline(void);
447 void dsp_reset_stats(void)
449 for(int i=0; i<65; i++)
450 dsp_opcode_use[i] = 0;
453 void DSPReleaseTimeslice(void)
455 //This does absolutely nothing!!! !!! FIX !!!
456 dsp_releaseTimeSlice_flag = 1;
459 void dsp_build_branch_condition_table(void)
461 // Fill in the mirror table
462 for(int i=0; i<65536; i++)
464 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
465 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
466 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
467 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
468 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
469 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
470 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
471 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
474 // Fill in the condition table
475 for(int i=0; i<8; i++)
477 for(int j=0; j<32; j++)
481 if ((j & 1) && (i & ZERO_FLAG))
484 if ((j & 2) && (!(i & ZERO_FLAG)))
487 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
490 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
493 dsp_branch_condition_table[i * 32 + j] = result;
498 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
500 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
501 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
503 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
506 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
508 if (offset==0xF1CFE0)
511 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
512 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
514 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
516 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
518 if ((offset&0x03)==0)
521 if ((offset&0x03)==1)
522 return((data>>16)&0xff);
524 if ((offset&0x03)==2)
525 return((data>>8)&0xff);
527 if ((offset&0x03)==3)
531 return JaguarReadByte(offset, who);
534 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
536 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
537 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
539 offset &= 0xFFFFFFFE;
541 /* if (jaguar_mainRom_crc32==0xa74a97cd)
543 if (offset==0xF1A114) return(0x0000);
544 if (offset==0xF1A116) return(0x0000);
545 if (offset==0xF1B000) return(0x1234);
546 if (offset==0xF1B002) return(0x5678);
549 if (jaguar_mainRom_crc32==0x7ae20823)
551 if (offset==0xF1B9D8) return(0x0000);
552 if (offset==0xF1B9Da) return(0x0000);
553 if (offset==0xF1B2C0) return(0x0000);
554 if (offset==0xF1B2C2) return(0x0000);
557 // pour permettre � wolfenstein 3d de tourner sans le dsp
558 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
562 // pour permettre � nba jam de tourner sans le dsp
563 /* if (jaguar_mainRom_crc32==0x4faddb18)
565 if (offset==0xf1b2c0) return(0);
566 if (offset==0xf1b2c2) return(0);
567 if (offset==0xf1b240) return(0);
568 if (offset==0xf1b242) return(0);
569 if (offset==0xF1B340) return(0);
570 if (offset==0xF1B342) return(0);
571 if (offset==0xF1BAD8) return(0);
572 if (offset==0xF1BADA) return(0);
573 if (offset==0xF1B040) return(0);
574 if (offset==0xF1B042) return(0);
575 if (offset==0xF1B0C0) return(0);
576 if (offset==0xF1B0C2) return(0);
577 if (offset==0xF1B140) return(0);
578 if (offset==0xF1B142) return(0);
579 if (offset==0xF1B1C0) return(0);
580 if (offset==0xF1B1C2) return(0);
583 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
585 offset -= DSP_WORK_RAM_BASE;
586 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
588 return GET16(dsp_ram_8, offset);
590 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
592 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
595 return data & 0xFFFF;
600 return JaguarReadWord(offset, who);
603 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
605 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
606 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
609 offset &= 0xFFFFFFFC;
610 /*if (offset == 0xF1BCF4)
612 WriteLog("DSPReadLong: Reading from 0xF1BCF4... -> %08X [%02X %02X %02X %02X][%04X %04X]\n", GET32(dsp_ram_8, 0x0CF4), dsp_ram_8[0x0CF4], dsp_ram_8[0x0CF5], dsp_ram_8[0x0CF6], dsp_ram_8[0x0CF7], JaguarReadWord(0xF1BCF4, DSP), JaguarReadWord(0xF1BCF6, DSP));
613 DSPDumpDisassembly();
615 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
617 offset -= DSP_WORK_RAM_BASE;
618 return GET32(dsp_ram_8, offset);
620 //NOTE: Didn't return DSP_ACCUM!!!
621 //Mebbe it's not 'spose to! Yes, it is!
622 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
627 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
628 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
629 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
631 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
632 return dsp_flags & 0xFFFFC1FF;
633 case 0x04: return dsp_matrix_control;
634 case 0x08: return dsp_pointer_to_matrix;
635 case 0x0C: return dsp_data_organization;
636 case 0x10: return dsp_pc;
637 case 0x14: return dsp_control;
638 case 0x18: return dsp_modulo;
639 case 0x1C: return dsp_remain;
641 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
643 // unaligned long read-- !!! FIX !!!
647 return JaguarReadLong(offset, who);
650 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
652 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
653 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
655 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
657 offset -= DSP_WORK_RAM_BASE;
658 dsp_ram_8[offset] = data;
659 //This is rather stupid! !!! FIX !!!
660 /* if (dsp_in_exec == 0)
662 m68k_end_timeslice();
663 dsp_releaseTimeslice();
667 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
669 uint32 reg = offset & 0x1C;
670 int bytenum = offset & 0x03;
672 if ((reg >= 0x1C) && (reg <= 0x1F))
673 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
676 //This looks funky. !!! FIX !!!
677 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
678 bytenum = 3 - bytenum; // convention motorola !!!
679 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
680 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
684 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
685 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
686 JaguarWriteByte(offset, data, who);
689 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
691 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
692 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
693 offset &= 0xFFFFFFFE;
694 /*if (offset == 0xF1BCF4)
696 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
698 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
699 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
701 /*if (offset == 0xF1B2F4)
703 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
705 offset -= DSP_WORK_RAM_BASE;
706 dsp_ram_8[offset] = data >> 8;
707 dsp_ram_8[offset+1] = data & 0xFF;
708 //This is rather stupid! !!! FIX !!!
709 /* if (dsp_in_exec == 0)
711 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
712 m68k_end_timeslice();
713 dsp_releaseTimeslice();
717 SET16(ram1, offset, data),
718 SET16(ram2, offset, data);
723 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
725 if ((offset & 0x1C) == 0x1C)
728 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
730 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
734 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
736 old_data = (old_data&0xffff0000)|(data&0xffff);
738 old_data = (old_data&0xffff)|((data&0xffff)<<16);
739 DSPWriteLong(offset & 0xffffffc, old_data, who);
744 JaguarWriteWord(offset, data, who);
747 //bool badWrite = false;
748 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
750 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
751 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
753 offset &= 0xFFFFFFFC;
754 /*if (offset == 0xF1BCF4)
756 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
758 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
759 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
761 /*if (offset == 0xF1BE2C)
763 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
765 offset -= DSP_WORK_RAM_BASE;
766 SET32(dsp_ram_8, offset, data);
769 SET32(ram1, offset, data),
770 SET32(ram2, offset, data);
775 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
783 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
785 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
786 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
788 dsp_flag_z = dsp_flags & 0x01;
789 dsp_flag_c = (dsp_flags >> 1) & 0x01;
790 dsp_flag_n = (dsp_flags >> 2) & 0x01;
791 DSPUpdateRegisterBanks();
792 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
793 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
795 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
796 // It can be timed to anything really, anything that writes to L/RTXD at a regular
797 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
798 // interrupt, so that's what we check for here. Just know that this approach
799 // can be easily fooled!
800 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
803 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
804 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
805 // So, while this works, it's a by-product of the lame way in which audio is currently
806 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
807 // go away of its own accord. :-P
808 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
809 // weird is going on here...
810 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
811 // So subsequent interrupts come into the chip, but they're never serviced but the
812 // I2S subsystem keeps going.
813 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
814 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
815 // It seems that it's only stable for values of SCLK <= 9.
817 if (data & INT_ENA1) // I2S interrupt
819 int freq = GetCalculatedFrequency();
820 //This happens too often to be useful...
821 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
822 DACSetNewFrequency(freq);
824 else if (data & INT_ENA2) // TIMER 0 interrupt
826 int freq = JERRYGetPIT1Frequency();
827 //This happens too often to be useful...
828 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
829 DACSetNewFrequency(freq);
832 /* if (IMASKCleared) // If IMASK was cleared,
835 WriteLog("DSP: Finished interrupt.\n");
837 DSPHandleIRQs(); // see if any other interrupts need servicing!
842 if (/*4-8, 16*/data & 0x101F0)
843 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
844 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
845 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
846 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
847 /*if (data & 0x00020) // CD BIOS DSP code...
849 //001AC1BA: movea.l #$1AC200, A0
850 //001AC1C0: move.l #$1AC68C, D0
853 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
854 uint32 j = 0xF1B97C;//0x1AC200;
855 while (j <= 0xF1BE08)//0x1AC68C)
858 j += dasmjag(JAGUAR_DSP, buffer, j);
859 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
860 WriteLog("\t%08X: %s\n", oldj, buffer);
867 dsp_matrix_control = data;
870 // According to JTRM, only lines 2-11 are addressable, the rest being
871 // hardwired to $F1Bxxx.
872 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
875 dsp_data_organization = data;
880 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
885 ctrl1[0] = ctrl2[0] = data;
892 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
894 bool wasRunning = DSP_RUNNING;
895 // uint32 dsp_was_running = DSP_RUNNING;
896 // Check for DSP -> CPU interrupt
900 WriteLog("DSP: DSP -> CPU interrupt\n");
903 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
904 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
905 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
907 JERRYSetPendingIRQ(IRQ2_DSP);
908 DSPReleaseTimeslice();
909 m68k_set_irq(2); // Set 68000 IPL 2...
913 // Check for CPU -> DSP interrupt
917 WriteLog("DSP: CPU -> DSP interrupt\n");
919 m68k_end_timeslice();
920 DSPReleaseTimeslice();
921 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
925 if (data & SINGLE_STEP)
927 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
930 // Protect writes to VERSION and the interrupt latches...
931 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
932 dsp_control = (dsp_control & mask) | (data & ~mask);
936 ctrl1[8] = ctrl2[8] = dsp_control;
940 // if dsp wasn't running but is now running
941 // execute a few cycles
942 //This is just plain wrong, wrong, WRONG!
943 #ifndef DSP_SINGLE_STEPPING
944 /* if (!dsp_was_running && DSP_RUNNING)
949 //This is WRONG! !!! FIX !!!
950 if (dsp_control & 0x18)
955 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
957 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
960 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
961 // !!! FIX !!! [DONE]
965 m68k_end_timeslice();
967 DSPReleaseTimeslice();
971 //DSPDumpDisassembly();
979 dsp_div_control = data;
981 // default: // unaligned long read
987 //We don't have to break this up like this! We CAN do 32 bit writes!
988 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
989 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
990 //if (offset > 0xF1FFFF)
992 JaguarWriteLong(offset, data, who);
996 // Update the DSP register file pointers depending on REGPAGE bit
998 void DSPUpdateRegisterBanks(void)
1000 int bank = (dsp_flags & REGPAGE);
1002 if (dsp_flags & IMASK)
1003 bank = 0; // IMASK forces main bank to be bank 0
1006 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1008 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1012 // Check for and handle any asserted DSP IRQs
1014 void DSPHandleIRQs(void)
1016 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1019 // Get the active interrupt bits (latches) & interrupt mask (enables)
1020 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1021 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1023 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1026 if (!bits) // Bail if nothing is enabled
1029 int which = 0; // Determine which interrupt
1043 #ifdef DSP_DEBUG_IRQ
1044 WriteLog("DSP: Generating interrupt #%i...", which);
1047 //if (which == 0) doDSPDis = true;
1049 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1050 // directly into the pipeline, it has the side effect of ensuring that the
1051 // instruction interrupted also gets to do its writeback. We simulate that
1053 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1055 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1056 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1058 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1059 scoreboard[pipeline[plPtrWrite].operand2] = false;
1061 //This should be execute (or should it?--not sure now!)
1062 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1063 //and what just executed is now in the Write position...). So why didn't it do the
1064 //writeback into register 0?
1065 #ifdef DSP_DEBUG_IRQ
1066 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1067 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
1068 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
1069 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
1071 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1073 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1075 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1076 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1079 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1080 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1081 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1082 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1084 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1088 #ifndef NEW_SCOREBOARD
1089 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1090 scoreboard[pipeline[plPtrWrite].operand2] = false;
1092 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1093 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1094 if (scoreboard[pipeline[plPtrWrite].operand2])
1095 scoreboard[pipeline[plPtrWrite].operand2]--;
1102 ctrl2[4] = dsp_flags;
1105 DSPUpdateRegisterBanks();
1106 #ifdef DSP_DEBUG_IRQ
1107 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1108 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), dsp_reg[31]);
1111 // subqt #4,r31 ; pre-decrement stack pointer
1112 // move pc,r30 ; address of interrupted code
1113 // store r30,(r31) ; store return address
1120 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1121 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1122 //It missed the place that it was supposed to come back to, so this is WRONG!
1124 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1126 // R -> baz (<- PC points here)
1127 // E -> bar (when it should point here!)
1130 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1131 // which means (assuming they're all 2 bytes long) that the code below will come back on
1132 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1133 // instruction stream...
1135 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1136 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1139 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1143 // movei #service_address,r30 ; pointer to ISR entry
1144 // jump (r30) ; jump to ISR
1146 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1149 ctrl2[0] = regs2[30] = dsp_pc;
1156 // Non-pipelined version...
1158 void DSPHandleIRQsNP(void)
1162 memcpy(dsp_ram_8, ram1, 0x2000);
1163 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1164 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1167 dsp_remain = ctrl1[2];
1168 dsp_modulo = ctrl1[3];
1169 dsp_flags = ctrl1[4];
1170 dsp_matrix_control = ctrl1[5];
1171 dsp_pointer_to_matrix = ctrl1[6];
1172 dsp_data_organization = ctrl1[7];
1173 dsp_control = ctrl1[8];
1174 dsp_div_control = ctrl1[9];
1175 IMASKCleared = ctrl1[10];
1176 dsp_flag_z = ctrl1[11];
1177 dsp_flag_n = ctrl1[12];
1178 dsp_flag_c = ctrl1[13];
1179 DSPUpdateRegisterBanks();
1182 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1185 // Get the active interrupt bits (latches) & interrupt mask (enables)
1186 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1187 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1189 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1192 if (!bits) // Bail if nothing is enabled
1195 int which = 0; // Determine which interrupt
1209 #ifdef DSP_DEBUG_IRQ
1210 WriteLog("DSP: Generating interrupt #%i...", which);
1216 ctrl1[4] = dsp_flags;
1219 DSPUpdateRegisterBanks();
1220 #ifdef DSP_DEBUG_IRQ
1221 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1224 // subqt #4,r31 ; pre-decrement stack pointer
1225 // move pc,r30 ; address of interrupted code
1226 // store r30,(r31) ; store return address
1233 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1236 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1240 // movei #service_address,r30 ; pointer to ISR entry
1241 // jump (r30) ; jump to ISR
1243 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1246 ctrl1[0] = regs1[30] = dsp_pc;
1252 // Set the specified DSP IRQ line to a given state
1254 void DSPSetIRQLine(int irqline, int state)
1256 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1257 uint32 mask = INT_LAT0 << irqline;
1258 dsp_control &= ~mask; // Clear the latch bit
1261 ctrl1[8] = ctrl2[8] = dsp_control;
1267 dsp_control |= mask; // Set the latch bit
1271 ctrl1[8] = ctrl2[8] = dsp_control;
1277 // Not sure if this is correct behavior, but according to JTRM,
1278 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1279 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1280 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1285 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1286 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1287 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1289 dsp_build_branch_condition_table();
1291 srand(time(NULL)); // For randomizing local RAM
1296 dsp_pc = 0x00F1B000;
1297 dsp_acc = 0x00000000;
1298 dsp_remain = 0x00000000;
1299 dsp_modulo = 0xFFFFFFFF;
1300 dsp_flags = 0x00040000;
1301 dsp_matrix_control = 0x00000000;
1302 dsp_pointer_to_matrix = 0x00000000;
1303 dsp_data_organization = 0xFFFFFFFF;
1304 dsp_control = 0x00002000; // Report DSP version 2
1305 dsp_div_control = 0x00000000;
1308 dsp_reg = dsp_reg_bank_0;
1309 dsp_alternate_reg = dsp_reg_bank_1;
1311 for(int i=0; i<32; i++)
1312 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1315 IMASKCleared = false;
1318 // memset(dsp_ram_8, 0xFF, 0x2000);
1319 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1320 for(uint32 i=0; i<8192; i+=4)
1322 *((uint32 *)(&dsp_ram_8[i])) = rand();
1326 void DSPDumpDisassembly(void)
1330 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1331 uint32 j = 0xF1B000;
1333 while (j <= 0xF1CFFF)
1336 j += dasmjag(JAGUAR_DSP, buffer, j);
1337 WriteLog("\t%08X: %s\n", oldj, buffer);
1341 void DSPDumpRegisters(void)
1343 //Shoud add modulus, etc to dump here...
1344 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1345 WriteLog("\nRegisters bank 0\n");
1347 for(int j=0; j<8; j++)
1349 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1350 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1351 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1352 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1353 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1356 WriteLog("Registers bank 1\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_1[(j << 2) + 0],
1362 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1363 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1364 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1371 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1372 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1374 // get the active interrupt bits
1375 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1376 // get the interrupt mask
1377 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1379 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1380 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1381 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1382 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1383 WriteLog("\nRegisters bank 0\n");
1385 for(int j=0; j<8; j++)
1387 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1388 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1389 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1390 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1391 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1394 WriteLog("\nRegisters bank 1\n");
1398 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1399 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1400 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1401 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1402 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1407 static char buffer[512];
1408 j = DSP_WORK_RAM_BASE;
1410 while (j <= 0xF1CFFF)
1413 j += dasmjag(JAGUAR_DSP, buffer, j);
1414 WriteLog("\t%08X: %s\n", oldj, buffer);
1417 WriteLog("DSP opcodes use:\n");
1421 if (dsp_opcode_use[i])
1422 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1425 // memory_free(dsp_ram_8);
1426 // memory_free(dsp_reg_bank_0);
1427 // memory_free(dsp_reg_bank_1);
1428 // if (dsp_branch_condition_table)
1429 // free(dsp_branch_condition_table);
1431 // if (mirror_table)
1432 // free(mirror_table);
1438 // DSP comparison core...
1441 static uint16 lastExec;
1442 void DSPExecComp(int32 cycles)
1444 while (cycles > 0 && DSP_RUNNING)
1446 // Load up vars for non-pipelined core
1447 memcpy(dsp_ram_8, ram1, 0x2000);
1448 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1449 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1452 dsp_remain = ctrl1[2];
1453 dsp_modulo = ctrl1[3];
1454 dsp_flags = ctrl1[4];
1455 dsp_matrix_control = ctrl1[5];
1456 dsp_pointer_to_matrix = ctrl1[6];
1457 dsp_data_organization = ctrl1[7];
1458 dsp_control = ctrl1[8];
1459 dsp_div_control = ctrl1[9];
1460 IMASKCleared = ctrl1[10];
1461 dsp_flag_z = ctrl1[11];
1462 dsp_flag_n = ctrl1[12];
1463 dsp_flag_c = ctrl1[13];
1464 DSPUpdateRegisterBanks();
1466 // Decrement cycles based on non-pipelined core...
1467 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1468 cycles -= dsp_opcode_cycles[instr1 >> 10];
1470 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1471 DSPExec(1); // Do *one* instruction
1474 memcpy(ram1, dsp_ram_8, 0x2000);
1475 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1476 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1479 ctrl1[2] = dsp_remain;
1480 ctrl1[3] = dsp_modulo;
1481 ctrl1[4] = dsp_flags;
1482 ctrl1[5] = dsp_matrix_control;
1483 ctrl1[6] = dsp_pointer_to_matrix;
1484 ctrl1[7] = dsp_data_organization;
1485 ctrl1[8] = dsp_control;
1486 ctrl1[9] = dsp_div_control;
1487 ctrl1[10] = IMASKCleared;
1488 ctrl1[11] = dsp_flag_z;
1489 ctrl1[12] = dsp_flag_n;
1490 ctrl1[13] = dsp_flag_c;
1492 // Load up vars for pipelined core
1493 memcpy(dsp_ram_8, ram2, 0x2000);
1494 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1495 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1498 dsp_remain = ctrl2[2];
1499 dsp_modulo = ctrl2[3];
1500 dsp_flags = ctrl2[4];
1501 dsp_matrix_control = ctrl2[5];
1502 dsp_pointer_to_matrix = ctrl2[6];
1503 dsp_data_organization = ctrl2[7];
1504 dsp_control = ctrl2[8];
1505 dsp_div_control = ctrl2[9];
1506 IMASKCleared = ctrl2[10];
1507 dsp_flag_z = ctrl2[11];
1508 dsp_flag_n = ctrl2[12];
1509 dsp_flag_c = ctrl2[13];
1510 DSPUpdateRegisterBanks();
1512 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1513 DSPExecP2(1); // Do *one* instruction
1516 memcpy(ram2, dsp_ram_8, 0x2000);
1517 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1518 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1521 ctrl2[2] = dsp_remain;
1522 ctrl2[3] = dsp_modulo;
1523 ctrl2[4] = dsp_flags;
1524 ctrl2[5] = dsp_matrix_control;
1525 ctrl2[6] = dsp_pointer_to_matrix;
1526 ctrl2[7] = dsp_data_organization;
1527 ctrl2[8] = dsp_control;
1528 ctrl2[9] = dsp_div_control;
1529 ctrl2[10] = IMASKCleared;
1530 ctrl2[11] = dsp_flag_z;
1531 ctrl2[12] = dsp_flag_n;
1532 ctrl2[13] = dsp_flag_c;
1534 if (instr1 != lastExec)
1536 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1538 // 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));
1539 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1540 // if (ctrl1[0] < ppc) // P ran ahead of NP
1541 //How to test this crap???
1544 DSPExecP2(1); // Do one more instruction
1547 memcpy(ram2, dsp_ram_8, 0x2000);
1548 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1549 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1552 ctrl2[2] = dsp_remain;
1553 ctrl2[3] = dsp_modulo;
1554 ctrl2[4] = dsp_flags;
1555 ctrl2[5] = dsp_matrix_control;
1556 ctrl2[6] = dsp_pointer_to_matrix;
1557 ctrl2[7] = dsp_data_organization;
1558 ctrl2[8] = dsp_control;
1559 ctrl2[9] = dsp_div_control;
1560 ctrl2[10] = IMASKCleared;
1561 ctrl2[11] = dsp_flag_z;
1562 ctrl2[12] = dsp_flag_n;
1563 ctrl2[13] = dsp_flag_c;
1565 // else // NP ran ahead of P
1566 if (instr1 != lastExec) // Must be the other way...
1569 // Load up vars for non-pipelined core
1570 memcpy(dsp_ram_8, ram1, 0x2000);
1571 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1572 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1575 dsp_remain = ctrl1[2];
1576 dsp_modulo = ctrl1[3];
1577 dsp_flags = ctrl1[4];
1578 dsp_matrix_control = ctrl1[5];
1579 dsp_pointer_to_matrix = ctrl1[6];
1580 dsp_data_organization = ctrl1[7];
1581 dsp_control = ctrl1[8];
1582 dsp_div_control = ctrl1[9];
1583 IMASKCleared = ctrl1[10];
1584 dsp_flag_z = ctrl1[11];
1585 dsp_flag_n = ctrl1[12];
1586 dsp_flag_c = ctrl1[13];
1587 DSPUpdateRegisterBanks();
1589 for(int k=0; k<2; k++)
1591 // Decrement cycles based on non-pipelined core...
1592 instr1 = DSPReadWord(dsp_pc, DSP);
1593 cycles -= dsp_opcode_cycles[instr1 >> 10];
1595 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1596 DSPExec(1); // Do *one* instruction
1600 memcpy(ram1, dsp_ram_8, 0x2000);
1601 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1602 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1605 ctrl1[2] = dsp_remain;
1606 ctrl1[3] = dsp_modulo;
1607 ctrl1[4] = dsp_flags;
1608 ctrl1[5] = dsp_matrix_control;
1609 ctrl1[6] = dsp_pointer_to_matrix;
1610 ctrl1[7] = dsp_data_organization;
1611 ctrl1[8] = dsp_control;
1612 ctrl1[9] = dsp_div_control;
1613 ctrl1[10] = IMASKCleared;
1614 ctrl1[11] = dsp_flag_z;
1615 ctrl1[12] = dsp_flag_n;
1616 ctrl1[13] = dsp_flag_c;
1620 if (instr1 != lastExec)
1622 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1624 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1625 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1638 // DSP execution core
1640 //static bool R20Set = false, tripwire = false;
1641 //static uint32 pcQueue[32], ptrPCQ = 0;
1642 void DSPExec(int32 cycles)
1644 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1645 dsp_check_if_i2s_interrupt_needed();*/
1647 #ifdef DSP_SINGLE_STEPPING
1648 if (dsp_control & 0x18)
1651 dsp_control &= ~0x10;
1654 //There is *no* good reason to do this here!
1656 dsp_releaseTimeSlice_flag = 0;
1659 while (cycles > 0 && DSP_RUNNING)
1661 /*extern uint32 totalFrames;
1662 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1663 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1664 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1666 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1669 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1671 if (dsp_pc == 0xF1B092)
1672 doDSPDis = false;//*/
1673 /*if (dsp_pc == 0xF1B140)
1674 doDSPDis = true;//*/
1676 if (IMASKCleared) // If IMASK was cleared,
1678 #ifdef DSP_DEBUG_IRQ
1679 WriteLog("DSP: Finished interrupt.\n");
1681 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1682 IMASKCleared = false;
1687 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1688 for(int i=0; i<80; i+=4)
1689 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1692 /*if (dsp_pc == 0xF1B55E)
1694 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1696 /*if (dsp_pc == 0xF1B7D2) // Start here???
1698 pcQueue[ptrPCQ++] = dsp_pc;
1700 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1701 uint32 index = opcode >> 10;
1702 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1703 dsp_opcode_second_parameter = opcode & 0x1F;
1705 dsp_opcode[index]();
1706 dsp_opcode_use[index]++;
1707 cycles -= dsp_opcode_cycles[index];
1708 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1710 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1713 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1715 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1717 DSPDumpDisassembly();
1720 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1723 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1726 WriteLog("\nBacktrace:\n");
1727 for(int i=0; i<32; i++)
1729 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1730 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1740 // DSP opcode handlers
1743 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1744 // can cause trouble because an interrupt can occur *before* the instruction following the
1745 // jump can execute... !!! FIX !!!
1746 static void dsp_opcode_jump(void)
1749 const char * condition[32] =
1750 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1751 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1752 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1753 "???", "???", "???", "F" };
1755 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);
1758 /* dsp_flag_c=dsp_flag_c?1:0;
1759 dsp_flag_z=dsp_flag_z?1:0;
1760 dsp_flag_n=dsp_flag_n?1:0;*/
1761 // KLUDGE: Used by BRANCH_CONDITION
1762 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1764 if (BRANCH_CONDITION(IMM_2))
1768 WriteLog("Branched!\n");
1770 uint32 delayed_pc = RM;
1772 dsp_pc = delayed_pc;
1777 WriteLog("Branch NOT taken.\n");
1781 static void dsp_opcode_jr(void)
1784 const char * condition[32] =
1785 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1786 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1787 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1788 "???", "???", "???", "F" };
1790 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);
1793 /* dsp_flag_c=dsp_flag_c?1:0;
1794 dsp_flag_z=dsp_flag_z?1:0;
1795 dsp_flag_n=dsp_flag_n?1:0;*/
1796 // KLUDGE: Used by BRANCH_CONDITION
1797 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1799 if (BRANCH_CONDITION(IMM_2))
1803 WriteLog("Branched!\n");
1805 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1806 int32 delayed_pc = dsp_pc + (offset * 2);
1808 dsp_pc = delayed_pc;
1813 WriteLog("Branch NOT taken.\n");
1817 static void dsp_opcode_add(void)
1821 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);
1823 uint32 res = RN + RM;
1824 SET_ZNC_ADD(RN, RM, res);
1828 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);
1832 static void dsp_opcode_addc(void)
1836 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);
1838 uint32 res = RN + RM + dsp_flag_c;
1839 uint32 carry = dsp_flag_c;
1840 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1841 SET_ZNC_ADD(RN + carry, RM, res);
1842 // SET_ZNC_ADD(RN, RM + carry, res);
1846 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);
1850 static void dsp_opcode_addq(void)
1854 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);
1856 uint32 r1 = dsp_convert_zero[IMM_1];
1857 uint32 res = RN + r1;
1858 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1862 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1866 static void dsp_opcode_sub(void)
1870 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);
1872 uint32 res = RN - RM;
1873 SET_ZNC_SUB(RN, RM, res);
1877 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);
1881 static void dsp_opcode_subc(void)
1885 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);
1887 uint32 res = RN - RM - dsp_flag_c;
1888 uint32 borrow = dsp_flag_c;
1889 SET_ZNC_SUB(RN - borrow, RM, res);
1893 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);
1897 static void dsp_opcode_subq(void)
1901 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);
1903 uint32 r1 = dsp_convert_zero[IMM_1];
1904 uint32 res = RN - r1;
1905 SET_ZNC_SUB(RN, r1, res);
1909 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1913 static void dsp_opcode_cmp(void)
1917 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);
1919 uint32 res = RN - RM;
1920 SET_ZNC_SUB(RN, RM, res);
1923 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1927 static void dsp_opcode_cmpq(void)
1929 static int32 sqtable[32] =
1930 { 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 };
1933 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);
1935 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1936 uint32 res = RN - r1;
1937 SET_ZNC_SUB(RN, r1, res);
1940 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1944 static void dsp_opcode_and(void)
1948 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);
1954 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);
1958 static void dsp_opcode_or(void)
1962 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);
1968 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);
1972 static void dsp_opcode_xor(void)
1976 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);
1982 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);
1986 static void dsp_opcode_not(void)
1990 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);
1996 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2000 static void dsp_opcode_move_pc(void)
2005 static void dsp_opcode_store_r14_indexed(void)
2007 #ifdef DSP_DIS_STORE14I
2009 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));
2011 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2012 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2014 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2018 static void dsp_opcode_store_r15_indexed(void)
2020 #ifdef DSP_DIS_STORE15I
2022 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));
2024 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2025 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2027 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2031 static void dsp_opcode_load_r14_ri(void)
2033 #ifdef DSP_DIS_LOAD14R
2035 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);
2037 #ifdef DSP_CORRECT_ALIGNMENT
2038 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2040 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2042 #ifdef DSP_DIS_LOAD14R
2044 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2048 static void dsp_opcode_load_r15_ri(void)
2050 #ifdef DSP_DIS_LOAD15R
2052 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);
2054 #ifdef DSP_CORRECT_ALIGNMENT
2055 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2057 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2059 #ifdef DSP_DIS_LOAD15R
2061 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2065 static void dsp_opcode_store_r14_ri(void)
2067 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2070 static void dsp_opcode_store_r15_ri(void)
2072 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2075 static void dsp_opcode_nop(void)
2079 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2083 static void dsp_opcode_storeb(void)
2085 #ifdef DSP_DIS_STOREB
2087 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);
2089 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2090 DSPWriteLong(RM, RN & 0xFF, DSP);
2092 JaguarWriteByte(RM, RN, DSP);
2095 static void dsp_opcode_storew(void)
2097 #ifdef DSP_DIS_STOREW
2099 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);
2101 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2102 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2103 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2105 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2107 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2108 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2110 JaguarWriteWord(RM, RN, DSP);
2114 static void dsp_opcode_store(void)
2116 #ifdef DSP_DIS_STORE
2118 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);
2120 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2121 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2123 DSPWriteLong(RM, RN, DSP);
2127 static void dsp_opcode_loadb(void)
2129 #ifdef DSP_DIS_LOADB
2131 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);
2133 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2134 RN = DSPReadLong(RM, DSP) & 0xFF;
2136 RN = JaguarReadByte(RM, DSP);
2137 #ifdef DSP_DIS_LOADB
2139 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2143 static void dsp_opcode_loadw(void)
2145 #ifdef DSP_DIS_LOADW
2147 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);
2149 #ifdef DSP_CORRECT_ALIGNMENT
2150 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2151 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2153 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2155 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2156 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2158 RN = JaguarReadWord(RM, DSP);
2160 #ifdef DSP_DIS_LOADW
2162 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2166 static void dsp_opcode_load(void)
2170 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);
2172 #ifdef DSP_CORRECT_ALIGNMENT
2173 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2175 RN = DSPReadLong(RM, DSP);
2179 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2183 static void dsp_opcode_load_r14_indexed(void)
2185 #ifdef DSP_DIS_LOAD14I
2187 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);
2189 #ifdef DSP_CORRECT_ALIGNMENT
2190 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2192 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2194 #ifdef DSP_DIS_LOAD14I
2196 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2200 static void dsp_opcode_load_r15_indexed(void)
2202 #ifdef DSP_DIS_LOAD15I
2204 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);
2206 #ifdef DSP_CORRECT_ALIGNMENT
2207 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2209 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2211 #ifdef DSP_DIS_LOAD15I
2213 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2217 static void dsp_opcode_movei(void)
2219 #ifdef DSP_DIS_MOVEI
2221 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);
2223 // This instruction is followed by 32-bit value in LSW / MSW format...
2224 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2226 #ifdef DSP_DIS_MOVEI
2228 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2232 static void dsp_opcode_moveta(void)
2234 #ifdef DSP_DIS_MOVETA
2236 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);
2239 #ifdef DSP_DIS_MOVETA
2241 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);
2245 static void dsp_opcode_movefa(void)
2247 #ifdef DSP_DIS_MOVEFA
2249 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);
2252 #ifdef DSP_DIS_MOVEFA
2254 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);
2258 static void dsp_opcode_move(void)
2262 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);
2267 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);
2271 static void dsp_opcode_moveq(void)
2273 #ifdef DSP_DIS_MOVEQ
2275 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);
2278 #ifdef DSP_DIS_MOVEQ
2280 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2284 static void dsp_opcode_resmac(void)
2286 #ifdef DSP_DIS_RESMAC
2288 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));
2290 RN = (uint32)dsp_acc;
2291 #ifdef DSP_DIS_RESMAC
2293 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2297 static void dsp_opcode_imult(void)
2299 #ifdef DSP_DIS_IMULT
2301 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);
2303 RN = (int16)RN * (int16)RM;
2305 #ifdef DSP_DIS_IMULT
2307 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);
2311 static void dsp_opcode_mult(void)
2315 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);
2317 RN = (uint16)RM * (uint16)RN;
2321 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);
2325 static void dsp_opcode_bclr(void)
2329 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);
2331 uint32 res = RN & ~(1 << IMM_1);
2336 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2340 static void dsp_opcode_btst(void)
2344 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);
2346 dsp_flag_z = (~RN >> IMM_1) & 1;
2349 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2353 static void dsp_opcode_bset(void)
2357 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);
2359 uint32 res = RN | (1 << IMM_1);
2364 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2368 static void dsp_opcode_subqt(void)
2370 #ifdef DSP_DIS_SUBQT
2372 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);
2374 RN -= dsp_convert_zero[IMM_1];
2375 #ifdef DSP_DIS_SUBQT
2377 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2381 static void dsp_opcode_addqt(void)
2383 #ifdef DSP_DIS_ADDQT
2385 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);
2387 RN += dsp_convert_zero[IMM_1];
2388 #ifdef DSP_DIS_ADDQT
2390 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2394 static void dsp_opcode_imacn(void)
2396 #ifdef DSP_DIS_IMACN
2398 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);
2400 int32 res = (int16)RM * (int16)RN;
2401 dsp_acc += (int64)res;
2402 //Should we AND the result to fit into 40 bits here???
2403 #ifdef DSP_DIS_IMACN
2405 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));
2409 static void dsp_opcode_mtoi(void)
2411 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2415 static void dsp_opcode_normi(void)
2422 while ((_Rm & 0xffc00000) == 0)
2427 while ((_Rm & 0xff800000) != 0)
2437 static void dsp_opcode_mmult(void)
2439 int count = dsp_matrix_control&0x0f;
2440 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2444 if (!(dsp_matrix_control & 0x10))
2446 for (int i = 0; i < count; i++)
2450 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2452 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2453 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2460 for (int i = 0; i < count; i++)
2464 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2466 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2467 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2472 RN = res = (int32)accum;
2474 //NOTE: The flags are set based upon the last add/multiply done...
2478 static void dsp_opcode_abs(void)
2482 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);
2487 if (_Rn == 0x80000000)
2491 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2492 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2497 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2501 static void dsp_opcode_div(void)
2508 if (dsp_div_control & 1)
2510 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2511 if (dsp_remain&0x80000000)
2513 RN = (((uint64)_Rn) << 16) / _Rm;
2517 dsp_remain = _Rn % _Rm;
2518 if (dsp_remain&0x80000000)
2527 static void dsp_opcode_imultn(void)
2529 #ifdef DSP_DIS_IMULTN
2531 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);
2533 // This is OK, since this multiply won't overflow 32 bits...
2534 int32 res = (int32)((int16)RN * (int16)RM);
2535 dsp_acc = (int64)res;
2537 #ifdef DSP_DIS_IMULTN
2539 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));
2543 static void dsp_opcode_neg(void)
2547 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);
2550 SET_ZNC_SUB(0, RN, res);
2554 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2558 static void dsp_opcode_shlq(void)
2562 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);
2564 int32 r1 = 32 - IMM_1;
2565 uint32 res = RN << r1;
2566 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2570 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2574 static void dsp_opcode_shrq(void)
2578 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);
2580 int32 r1 = dsp_convert_zero[IMM_1];
2581 uint32 res = RN >> r1;
2582 SET_ZN(res); dsp_flag_c = RN & 1;
2586 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2590 static void dsp_opcode_ror(void)
2594 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);
2596 uint32 r1 = RM & 0x1F;
2597 uint32 res = (RN >> r1) | (RN << (32 - r1));
2598 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2602 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);
2606 static void dsp_opcode_rorq(void)
2610 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);
2612 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2614 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2616 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2619 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2623 static void dsp_opcode_sha(void)
2625 int32 sRm=(int32)RM;
2631 if (shift>=32) shift=32;
2632 dsp_flag_c=(_Rn&0x80000000)>>31;
2642 if (shift>=32) shift=32;
2646 _Rn=((int32)_Rn)>>1;
2654 static void dsp_opcode_sharq(void)
2656 #ifdef DSP_DIS_SHARQ
2658 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);
2660 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2661 SET_ZN(res); dsp_flag_c = RN & 0x01;
2663 #ifdef DSP_DIS_SHARQ
2665 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2669 static void dsp_opcode_sh(void)
2671 int32 sRm=(int32)RM;
2676 uint32 shift=(-sRm);
2677 if (shift>=32) shift=32;
2678 dsp_flag_c=(_Rn&0x80000000)>>31;
2688 if (shift>=32) shift=32;
2700 void dsp_opcode_addqmod(void)
2702 #ifdef DSP_DIS_ADDQMOD
2704 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);
2706 uint32 r1 = dsp_convert_zero[IMM_1];
2708 uint32 res = r2 + r1;
2709 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2711 SET_ZNC_ADD(r2, r1, res);
2712 #ifdef DSP_DIS_ADDQMOD
2714 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2718 void dsp_opcode_subqmod(void)
2720 uint32 r1 = dsp_convert_zero[IMM_1];
2722 uint32 res = r2 - r1;
2723 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2726 SET_ZNC_SUB(r2, r1, res);
2729 void dsp_opcode_mirror(void)
2732 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2736 void dsp_opcode_sat32s(void)
2738 int32 r2 = (uint32)RN;
2739 int32 temp = dsp_acc >> 32;
2740 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2745 void dsp_opcode_sat16s(void)
2748 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2754 // New pipelined DSP core
2757 static void DSP_abs(void);
2758 static void DSP_add(void);
2759 static void DSP_addc(void);
2760 static void DSP_addq(void);
2761 static void DSP_addqmod(void);
2762 static void DSP_addqt(void);
2763 static void DSP_and(void);
2764 static void DSP_bclr(void);
2765 static void DSP_bset(void);
2766 static void DSP_btst(void);
2767 static void DSP_cmp(void);
2768 static void DSP_cmpq(void);
2769 static void DSP_div(void);
2770 static void DSP_imacn(void);
2771 static void DSP_imult(void);
2772 static void DSP_imultn(void);
2773 static void DSP_illegal(void);
2774 static void DSP_jr(void);
2775 static void DSP_jump(void);
2776 static void DSP_load(void);
2777 static void DSP_loadb(void);
2778 static void DSP_loadw(void);
2779 static void DSP_load_r14_i(void);
2780 static void DSP_load_r14_r(void);
2781 static void DSP_load_r15_i(void);
2782 static void DSP_load_r15_r(void);
2783 static void DSP_mirror(void);
2784 static void DSP_mmult(void);
2785 static void DSP_move(void);
2786 static void DSP_movefa(void);
2787 static void DSP_movei(void);
2788 static void DSP_movepc(void);
2789 static void DSP_moveq(void);
2790 static void DSP_moveta(void);
2791 static void DSP_mtoi(void);
2792 static void DSP_mult(void);
2793 static void DSP_neg(void);
2794 static void DSP_nop(void);
2795 static void DSP_normi(void);
2796 static void DSP_not(void);
2797 static void DSP_or(void);
2798 static void DSP_resmac(void);
2799 static void DSP_ror(void);
2800 static void DSP_rorq(void);
2801 static void DSP_sat16s(void);
2802 static void DSP_sat32s(void);
2803 static void DSP_sh(void);
2804 static void DSP_sha(void);
2805 static void DSP_sharq(void);
2806 static void DSP_shlq(void);
2807 static void DSP_shrq(void);
2808 static void DSP_store(void);
2809 static void DSP_storeb(void);
2810 static void DSP_storew(void);
2811 static void DSP_store_r14_i(void);
2812 static void DSP_store_r14_r(void);
2813 static void DSP_store_r15_i(void);
2814 static void DSP_store_r15_r(void);
2815 static void DSP_sub(void);
2816 static void DSP_subc(void);
2817 static void DSP_subq(void);
2818 static void DSP_subqmod(void);
2819 static void DSP_subqt(void);
2820 static void DSP_xor(void);
2822 void (* DSPOpcode[64])() =
2824 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2825 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2826 DSP_neg, DSP_and, DSP_or, DSP_xor,
2827 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2829 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2830 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2831 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2832 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2834 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2835 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2836 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2837 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2839 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2840 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2841 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2842 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2845 bool readAffected[64][2] =
2847 { true, true}, { true, true}, {false, true}, {false, true},
2848 { true, true}, { true, true}, {false, true}, {false, true},
2849 {false, true}, { true, true}, { true, true}, { true, true},
2850 {false, true}, {false, true}, {false, true}, {false, true},
2852 { true, true}, { true, true}, { true, true}, {false, true},
2853 { true, true}, { true, true}, {false, true}, { true, true},
2854 {false, true}, {false, true}, { true, true}, {false, true},
2855 { true, true}, {false, true}, { true, true}, {false, true},
2857 {false, true}, {false, true}, { true, false}, {false, false},
2858 { true, false}, {false, false}, {false, false}, { true, false},
2859 { true, false}, { true, false}, {false, true}, { true, false},
2860 { true, false}, { true, true}, { true, true}, { true, true},
2862 {false, true}, { true, true}, { true, true}, {false, true},
2863 { true, false}, { true, false}, { true, true}, { true, false},
2864 { true, false}, {false, false}, { true, false}, { true, false},
2865 { true, true}, { true, true}, {false, false}, {false, true}
2868 bool isLoadStore[65] =
2870 false, false, false, false, false, false, false, false,
2871 false, false, false, false, false, false, false, false,
2873 false, false, false, false, false, false, false, false,
2874 false, false, false, false, false, false, false, false,
2876 false, false, false, false, false, false, false, true,
2877 true, true, false, true, true, true, true, true,
2879 false, true, true, false, false, false, false, false,
2880 false, false, true, true, true, true, false, false, false
2883 void FlushDSPPipeline(void)
2885 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2887 for(int i=0; i<4; i++)
2888 pipeline[i].opcode = PIPELINE_STALL;
2890 for(int i=0; i<32; i++)
2895 // New pipelined DSP execution core
2897 /*void DSPExecP(int32 cycles)
2899 // bool inhibitFetch = false;
2901 dsp_releaseTimeSlice_flag = 0;
2904 while (cycles > 0 && DSP_RUNNING)
2906 WriteLog("DSPExecP: Pipeline status...\n");
2907 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);
2908 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);
2909 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);
2910 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);
2911 WriteLog(" --> Scoreboard: ");
2912 for(int i=0; i<32; i++)
2913 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2915 // Stage 1: Instruction fetch
2916 // if (!inhibitFetch)
2918 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2919 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2920 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2921 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2922 if (pipeline[plPtrFetch].opcode == 38)
2923 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2924 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2927 // inhibitFetch = false;
2928 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2930 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2931 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);
2932 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);
2933 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);
2934 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);
2935 // Stage 2: Read registers
2936 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2937 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2938 if (scoreboard[pipeline[plPtrRead].operand2])
2939 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2940 // We have a hit in the scoreboard, so we have to stall the pipeline...
2942 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2943 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2944 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2945 pipeline[plPtrFetch] = pipeline[plPtrRead];
2946 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2950 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2951 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2952 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2954 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2955 // Shouldn't we be more selective with the register scoreboarding?
2956 // Yes, we should. !!! FIX !!!
2957 scoreboard[pipeline[plPtrRead].operand2] = true;
2958 //Advance PC here??? Yes.
2959 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2960 //This is a mangling of the pipeline stages, but what else to do???
2961 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2964 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2965 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);
2966 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);
2967 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);
2968 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);
2970 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2972 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2973 DSPOpcode[pipeline[plPtrExec].opcode]();
2974 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2975 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2980 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2981 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);
2982 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);
2983 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);
2984 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);
2985 // Stage 4: Write back register
2986 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2988 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2989 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2991 scoreboard[pipeline[plPtrWrite].operand1]
2992 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2995 // Push instructions through the pipeline...
2996 plPtrFetch = (++plPtrFetch) & 0x03;
2997 plPtrRead = (++plPtrRead) & 0x03;
2998 plPtrExec = (++plPtrExec) & 0x03;
2999 plPtrWrite = (++plPtrWrite) & 0x03;
3006 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3008 // Should be fixed now. Another problem is figuring how to do the sequence following
3009 // a branch followed with the JR & JUMP instructions...
3011 // There are two conflicting problems:
3014 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3015 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3016 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3017 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3018 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3019 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3020 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3021 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3022 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3023 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3024 DSP: Finished interrupt.
3025 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3026 ; bank 0 (where is was prepared)!
3027 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3028 F1B252: NOP [NCZ:001]
3031 // The other is when you see this at the end of an IRQ:
3034 JUMP T, (R29) ; R29 = Previous stack + 2
3035 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3037 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3038 ; 1) The STORE goes through the pipeline and is executed/written back
3039 ; 2) The pipeline is flushed
3040 ; 3) The DSP_PC is set to the new address
3041 ; 4) Execution resumes
3043 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3044 ; bank 0 instead of the current bank 1 and so goes astray!
3047 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3048 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3052 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3053 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3054 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3055 If it were done properly, the STORE write back would occur *after* (well, technically,
3056 during) the execution of the the JUMP that follows it.
3060 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3061 F1B08A: NOP [NCZ:001]
3063 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3066 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3069 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3070 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3071 F1B08A: NOP [NCZ:001]
3073 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3076 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3077 DSP: CPU -> DSP interrupt
3078 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3079 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3081 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3084 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3085 F1B006: NOP [NCZ:001]
3087 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3090 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3091 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3094 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3095 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3098 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3099 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3102 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3103 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3106 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3109 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3112 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3113 F1B0FE: NOP [NCZ:000]
3115 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3118 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3121 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3122 F1B138: NOP [NCZ:000]
3124 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3127 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3128 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3129 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3132 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3133 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3136 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3137 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3138 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3140 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3141 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3144 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3145 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3146 DSP: Finished interrupt.
3147 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3149 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3152 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3153 F1B016: NOP [NCZ:001]
3155 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3158 uint32 pcQueue1[0x400];
3160 static uint32 prevR1;
3161 //Let's try a 3 stage pipeline....
3162 //Looks like 3 stage is correct, otherwise bad things happen...
3163 void DSPExecP2(int32 cycles)
3165 dsp_releaseTimeSlice_flag = 0;
3168 while (cycles > 0 && DSP_RUNNING)
3170 /*extern uint32 totalFrames;
3171 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3172 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3173 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3175 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3178 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3180 if (dsp_pc == 0xF1B092)
3181 doDSPDis = false;//*/
3182 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3183 doDSPDis = true;//*/
3184 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3185 doDSPDis = true;//*/
3186 /*if (dsp_pc == 0xF1B0A0)
3187 doDSPDis = true;//*/
3188 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3189 doDSPDis = true;//*/
3190 //Two parter... (not sure how to write this)
3191 //if (dsp_pc == 0xF1B0D2)
3192 // prevR1 = dsp_reg[1];
3194 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3195 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3198 pcQueue1[pcQPtr1++] = dsp_pc;
3201 #ifdef DSP_DEBUG_PL2
3202 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3204 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3209 for(int i=0; i<0x400; i++)
3211 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3212 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3218 if (IMASKCleared) // If IMASK was cleared,
3220 #ifdef DSP_DEBUG_IRQ
3221 WriteLog("DSP: Finished interrupt.\n");
3223 DSPHandleIRQs(); // See if any other interrupts are pending!
3224 IMASKCleared = false;
3227 //if (dsp_flags & REGPAGE)
3228 // WriteLog(" --> REGPAGE has just been set!\n");
3229 #ifdef DSP_DEBUG_PL2
3232 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3233 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]);
3234 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]);
3235 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]);
3236 WriteLog(" --> Scoreboard: ");
3237 for(int i=0; i<32; i++)
3238 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3242 // Stage 1a: Instruction fetch
3243 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3244 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3245 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3246 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3247 if (pipeline[plPtrRead].opcode == 38)
3248 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3249 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3250 #ifdef DSP_DEBUG_PL2
3253 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3254 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3255 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]);
3256 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]);
3257 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]);
3260 // Stage 1b: Read registers
3261 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3262 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3264 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3265 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3266 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3267 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3268 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3269 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3270 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3272 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3273 // We have a hit in the scoreboard, so we have to stall the pipeline...
3274 #ifdef DSP_DEBUG_PL2
3278 WriteLog(" --> Stalling pipeline: ");
3279 if (readAffected[pipeline[plPtrRead].opcode][0])
3280 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3281 if (readAffected[pipeline[plPtrRead].opcode][1])
3282 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3286 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3287 #ifdef DSP_DEBUG_PL2
3292 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3293 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3294 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3296 // Shouldn't we be more selective with the register scoreboarding?
3297 // Yes, we should. !!! FIX !!! Kinda [DONE]
3298 #ifndef NEW_SCOREBOARD
3299 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3301 //Hopefully this will fix the dual MOVEQ # problem...
3302 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3305 //Advance PC here??? Yes.
3306 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3309 #ifdef DSP_DEBUG_PL2
3312 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3313 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]);
3314 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]);
3315 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]);
3319 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3321 #ifdef DSP_DEBUG_PL2
3323 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"));
3327 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3332 lastExec = pipeline[plPtrExec].instruction;
3333 //WriteLog("[lastExec = %04X]\n", lastExec);
3335 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3336 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3337 DSPOpcode[pipeline[plPtrExec].opcode]();
3338 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3342 //Let's not, until we do the stalling correctly...
3343 //But, we gotta while we're doing the comparison core...!
3344 //Or do we? cycles--;
3345 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3346 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3347 //to model this clock cycle behavior correctly...
3348 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3349 //don't affect the reads at stage 1...
3350 #ifdef DSP_DEBUG_STALL
3352 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3356 #ifdef DSP_DEBUG_PL2
3359 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3360 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]);
3361 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]);
3362 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]);
3366 // Stage 3: Write back register/memory address
3367 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3369 /*if (pipeline[plPtrWrite].writebackRegister == 3
3370 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3373 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3376 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3378 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3379 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3382 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3383 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3384 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3385 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3387 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3391 #ifndef NEW_SCOREBOARD
3392 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3393 scoreboard[pipeline[plPtrWrite].operand2] = false;
3395 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3396 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3397 if (scoreboard[pipeline[plPtrWrite].operand2])
3398 scoreboard[pipeline[plPtrWrite].operand2]--;
3402 // Push instructions through the pipeline...
3403 plPtrRead = (++plPtrRead) & 0x03;
3404 plPtrExec = (++plPtrExec) & 0x03;
3405 plPtrWrite = (++plPtrWrite) & 0x03;
3414 //#define DSP_DEBUG_PL3
3415 //Let's try a 2 stage pipeline....
3416 void DSPExecP3(int32 cycles)
3418 dsp_releaseTimeSlice_flag = 0;
3421 while (cycles > 0 && DSP_RUNNING)
3423 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3425 #ifdef DSP_DEBUG_PL3
3426 WriteLog("DSPExecP: Pipeline status...\n");
3427 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]);
3428 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]);
3429 WriteLog(" --> Scoreboard: ");
3430 for(int i=0; i<32; i++)
3431 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3434 // Stage 1a: Instruction fetch
3435 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3436 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3437 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3438 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3439 if (pipeline[plPtrRead].opcode == 38)
3440 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3441 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3442 #ifdef DSP_DEBUG_PL3
3443 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3444 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3445 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]);
3446 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]);
3448 // Stage 1b: Read registers
3449 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3450 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3451 // We have a hit in the scoreboard, so we have to stall the pipeline...
3452 #ifdef DSP_DEBUG_PL3
3454 WriteLog(" --> Stalling pipeline: ");
3455 if (readAffected[pipeline[plPtrRead].opcode][0])
3456 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3457 if (readAffected[pipeline[plPtrRead].opcode][1])
3458 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3461 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3462 #ifdef DSP_DEBUG_PL3
3467 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3468 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3469 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3471 // Shouldn't we be more selective with the register scoreboarding?
3472 // Yes, we should. !!! FIX !!! [Kinda DONE]
3473 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3475 //Advance PC here??? Yes.
3476 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3479 #ifdef DSP_DEBUG_PL3
3480 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3481 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]);
3482 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]);
3484 // Stage 2a: Execute
3485 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3487 #ifdef DSP_DEBUG_PL3
3488 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3490 DSPOpcode[pipeline[plPtrExec].opcode]();
3491 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3492 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3497 #ifdef DSP_DEBUG_PL3
3498 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3499 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]);
3500 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]);
3503 // Stage 2b: Write back register
3504 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3506 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3507 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3509 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3510 scoreboard[pipeline[plPtrExec].operand2] = false;
3513 // Push instructions through the pipeline...
3514 plPtrRead = (++plPtrRead) & 0x03;
3515 plPtrExec = (++plPtrExec) & 0x03;
3522 // DSP pipelined opcode handlers
3525 #define PRM pipeline[plPtrExec].reg1
3526 #define PRN pipeline[plPtrExec].reg2
3527 #define PIMM1 pipeline[plPtrExec].operand1
3528 #define PIMM2 pipeline[plPtrExec].operand2
3529 #define PRES pipeline[plPtrExec].result
3530 #define PWBR pipeline[plPtrExec].writebackRegister
3531 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3532 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3533 #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))
3534 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3536 static void DSP_abs(void)
3540 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);
3544 if (_Rn == 0x80000000)
3548 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3549 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3550 CLR_ZN; SET_Z(PRES);
3554 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3558 static void DSP_add(void)
3562 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);
3564 uint32 res = PRN + PRM;
3565 SET_ZNC_ADD(PRN, PRM, res);
3569 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);
3573 static void DSP_addc(void)
3577 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);
3579 uint32 res = PRN + PRM + dsp_flag_c;
3580 uint32 carry = dsp_flag_c;
3581 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3582 SET_ZNC_ADD(PRN + carry, PRM, res);
3583 // SET_ZNC_ADD(PRN, PRM + carry, res);
3587 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);
3591 static void DSP_addq(void)
3595 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);
3597 uint32 r1 = dsp_convert_zero[PIMM1];
3598 uint32 res = PRN + r1;
3599 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3603 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3607 static void DSP_addqmod(void)
3609 #ifdef DSP_DIS_ADDQMOD
3611 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);
3613 uint32 r1 = dsp_convert_zero[PIMM1];
3615 uint32 res = r2 + r1;
3616 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3618 SET_ZNC_ADD(r2, r1, res);
3619 #ifdef DSP_DIS_ADDQMOD
3621 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3625 static void DSP_addqt(void)
3627 #ifdef DSP_DIS_ADDQT
3629 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);
3631 PRES = PRN + dsp_convert_zero[PIMM1];
3632 #ifdef DSP_DIS_ADDQT
3634 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3638 static void DSP_and(void)
3642 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);
3648 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);
3652 static void DSP_bclr(void)
3656 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);
3658 PRES = PRN & ~(1 << PIMM1);
3662 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3666 static void DSP_bset(void)
3670 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);
3672 PRES = PRN | (1 << PIMM1);
3676 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3680 static void DSP_btst(void)
3684 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);
3686 dsp_flag_z = (~PRN >> PIMM1) & 1;
3690 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3694 static void DSP_cmp(void)
3698 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);
3700 uint32 res = PRN - PRM;
3701 SET_ZNC_SUB(PRN, PRM, res);
3705 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3709 static void DSP_cmpq(void)
3711 static int32 sqtable[32] =
3712 { 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 };
3715 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);
3717 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3718 uint32 res = PRN - r1;
3719 SET_ZNC_SUB(PRN, r1, res);
3723 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3727 static void DSP_div(void)
3729 uint32 _Rm = PRM, _Rn = PRN;
3733 if (dsp_div_control & 1)
3735 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3736 if (dsp_remain & 0x80000000)
3738 PRES = (((uint64)_Rn) << 16) / _Rm;
3742 dsp_remain = _Rn % _Rm;
3743 if (dsp_remain & 0x80000000)
3752 static void DSP_imacn(void)
3754 #ifdef DSP_DIS_IMACN
3756 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);
3758 int32 res = (int16)PRM * (int16)PRN;
3759 dsp_acc += (int64)res;
3760 //Should we AND the result to fit into 40 bits here???
3762 #ifdef DSP_DIS_IMACN
3764 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));
3768 static void DSP_imult(void)
3770 #ifdef DSP_DIS_IMULT
3772 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);
3774 PRES = (int16)PRN * (int16)PRM;
3776 #ifdef DSP_DIS_IMULT
3778 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);
3782 static void DSP_imultn(void)
3784 #ifdef DSP_DIS_IMULTN
3786 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);
3788 // This is OK, since this multiply won't overflow 32 bits...
3789 int32 res = (int32)((int16)PRN * (int16)PRM);
3790 dsp_acc = (int64)res;
3793 #ifdef DSP_DIS_IMULTN
3795 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));
3799 static void DSP_illegal(void)
3801 #ifdef DSP_DIS_ILLEGAL
3803 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3808 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3809 // can cause trouble because an interrupt can occur *before* the instruction following the
3810 // jump can execute... !!! FIX !!!
3811 // This can probably be solved by judicious coding in the pipeline execution core...
3812 // And should be fixed now...
3813 static void DSP_jr(void)
3816 const char * condition[32] =
3817 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3818 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3819 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3820 "???", "???", "???", "F" };
3822 //How come this is always off by 2???
3823 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);
3825 // KLUDGE: Used by BRANCH_CONDITION macro
3826 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3828 if (BRANCH_CONDITION(PIMM2))
3832 WriteLog("Branched!\n");
3834 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3835 //Account for pipeline effects...
3836 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3837 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3839 // Now that we've branched, we have to make sure that the following instruction
3840 // is executed atomically with this one and then flush the pipeline before setting
3843 // Step 1: Handle writebacks at stage 3 of pipeline
3844 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3846 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3847 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3849 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3850 scoreboard[pipeline[plPtrWrite].operand2] = false;
3852 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3854 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3856 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3857 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3860 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3861 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3862 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3863 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3865 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3869 #ifndef NEW_SCOREBOARD
3870 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3871 scoreboard[pipeline[plPtrWrite].operand2] = false;
3873 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3874 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3875 if (scoreboard[pipeline[plPtrWrite].operand2])
3876 scoreboard[pipeline[plPtrWrite].operand2]--;
3880 // Step 2: Push instruction through pipeline & execute following instruction
3881 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3882 // we effectively handle the final push of the instruction through the
3883 // pipeline when the new PC takes effect (since when we return, the
3884 // pipeline code will be executing the writeback stage. If we reverse
3885 // the execution order of the pipeline stages, this will no longer be
3887 pipeline[plPtrExec] = pipeline[plPtrRead];
3888 //This is BAD. We need to get that next opcode and execute it!
3889 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3890 // remove this crap.
3891 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3893 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3894 pipeline[plPtrExec].opcode = instruction >> 10;
3895 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3896 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3897 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3898 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3899 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3901 dsp_pc += 2; // For DSP_DIS_* accuracy
3902 DSPOpcode[pipeline[plPtrExec].opcode]();
3903 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3904 pipeline[plPtrWrite] = pipeline[plPtrExec];
3906 // Step 3: Flush pipeline & set new PC
3907 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3914 WriteLog("Branch NOT taken.\n");
3920 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3923 static void DSP_jump(void)
3926 const char * condition[32] =
3927 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3928 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3929 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3930 "???", "???", "???", "F" };
3932 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);
3934 // KLUDGE: Used by BRANCH_CONDITION macro
3935 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3937 if (BRANCH_CONDITION(PIMM2))
3941 WriteLog("Branched!\n");
3943 uint32 PCSave = PRM;
3944 // Now that we've branched, we have to make sure that the following instruction
3945 // is executed atomically with this one and then flush the pipeline before setting
3948 // Step 1: Handle writebacks at stage 3 of pipeline
3949 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3951 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3952 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3954 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3955 scoreboard[pipeline[plPtrWrite].operand2] = false;
3957 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3959 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3961 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3962 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3965 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3966 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3967 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3968 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3970 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3974 #ifndef NEW_SCOREBOARD
3975 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3976 scoreboard[pipeline[plPtrWrite].operand2] = false;
3978 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3979 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3980 if (scoreboard[pipeline[plPtrWrite].operand2])
3981 scoreboard[pipeline[plPtrWrite].operand2]--;
3985 // Step 2: Push instruction through pipeline & execute following instruction
3986 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3987 // we effectively handle the final push of the instruction through the
3988 // pipeline when the new PC takes effect (since when we return, the
3989 // pipeline code will be executing the writeback stage. If we reverse
3990 // the execution order of the pipeline stages, this will no longer be
3992 pipeline[plPtrExec] = pipeline[plPtrRead];
3993 //This is BAD. We need to get that next opcode and execute it!
3994 //Also, same problem in JR!
3995 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3996 // remove this crap.
3997 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3999 uint16 instruction = DSPReadWord(dsp_pc, DSP);
4000 pipeline[plPtrExec].opcode = instruction >> 10;
4001 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4002 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4003 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4004 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4005 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4007 dsp_pc += 2; // For DSP_DIS_* accuracy
4008 DSPOpcode[pipeline[plPtrExec].opcode]();
4009 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4010 pipeline[plPtrWrite] = pipeline[plPtrExec];
4012 // Step 3: Flush pipeline & set new PC
4013 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4020 WriteLog("Branch NOT taken.\n");
4028 static void DSP_load(void)
4032 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);
4034 #ifdef DSP_CORRECT_ALIGNMENT
4035 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4037 PRES = DSPReadLong(PRM, DSP);
4041 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4045 static void DSP_loadb(void)
4047 #ifdef DSP_DIS_LOADB
4049 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);
4051 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4052 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4054 PRES = JaguarReadByte(PRM, DSP);
4055 #ifdef DSP_DIS_LOADB
4057 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4061 static void DSP_loadw(void)
4063 #ifdef DSP_DIS_LOADW
4065 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);
4067 #ifdef DSP_CORRECT_ALIGNMENT
4068 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4069 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4071 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4073 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4074 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4076 PRES = JaguarReadWord(PRM, DSP);
4078 #ifdef DSP_DIS_LOADW
4080 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4084 static void DSP_load_r14_i(void)
4086 #ifdef DSP_DIS_LOAD14I
4088 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);
4090 #ifdef DSP_CORRECT_ALIGNMENT
4091 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4093 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4095 #ifdef DSP_DIS_LOAD14I
4097 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4101 static void DSP_load_r14_r(void)
4103 #ifdef DSP_DIS_LOAD14R
4105 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);
4107 #ifdef DSP_CORRECT_ALIGNMENT
4108 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4110 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4112 #ifdef DSP_DIS_LOAD14R
4114 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4118 static void DSP_load_r15_i(void)
4120 #ifdef DSP_DIS_LOAD15I
4122 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);
4124 #ifdef DSP_CORRECT_ALIGNMENT
4125 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4127 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4129 #ifdef DSP_DIS_LOAD15I
4131 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4135 static void DSP_load_r15_r(void)
4137 #ifdef DSP_DIS_LOAD15R
4139 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);
4141 #ifdef DSP_CORRECT_ALIGNMENT
4142 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4144 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4146 #ifdef DSP_DIS_LOAD15R
4148 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4152 static void DSP_mirror(void)
4155 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4159 static void DSP_mmult(void)
4161 int count = dsp_matrix_control&0x0f;
4162 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4166 if (!(dsp_matrix_control & 0x10))
4168 for (int i = 0; i < count; i++)
4172 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4174 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4175 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4182 for (int i = 0; i < count; i++)
4186 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4188 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4189 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4195 PRES = res = (int32)accum;
4197 //NOTE: The flags are set based upon the last add/multiply done...
4201 static void DSP_move(void)
4205 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);
4210 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);
4214 static void DSP_movefa(void)
4216 #ifdef DSP_DIS_MOVEFA
4218 // 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);
4219 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);
4221 // PRES = ALTERNATE_RM;
4222 PRES = dsp_alternate_reg[PIMM1];
4223 #ifdef DSP_DIS_MOVEFA
4225 // 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);
4226 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);
4230 static void DSP_movei(void)
4232 #ifdef DSP_DIS_MOVEI
4234 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);
4236 // // This instruction is followed by 32-bit value in LSW / MSW format...
4237 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4239 #ifdef DSP_DIS_MOVEI
4241 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4245 static void DSP_movepc(void)
4247 #ifdef DSP_DIS_MOVEPC
4249 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);
4251 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4252 // PRES = dsp_pc - 2;
4253 //Account for pipeline effects...
4254 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4255 #ifdef DSP_DIS_MOVEPC
4257 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4261 static void DSP_moveq(void)
4263 #ifdef DSP_DIS_MOVEQ
4265 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);
4268 #ifdef DSP_DIS_MOVEQ
4270 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4274 static void DSP_moveta(void)
4276 #ifdef DSP_DIS_MOVETA
4278 // 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);
4279 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]);
4281 // ALTERNATE_RN = PRM;
4282 dsp_alternate_reg[PIMM2] = PRM;
4284 #ifdef DSP_DIS_MOVETA
4286 // 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);
4287 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]);
4291 static void DSP_mtoi(void)
4293 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4297 static void DSP_mult(void)
4301 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);
4303 PRES = (uint16)PRM * (uint16)PRN;
4307 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);
4311 static void DSP_neg(void)
4315 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);
4318 SET_ZNC_SUB(0, PRN, res);
4322 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4326 static void DSP_nop(void)
4330 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4335 static void DSP_normi(void)
4342 while ((_Rm & 0xffc00000) == 0)
4347 while ((_Rm & 0xff800000) != 0)
4357 static void DSP_not(void)
4361 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);
4367 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4371 static void DSP_or(void)
4375 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);
4381 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);
4385 static void DSP_resmac(void)
4387 #ifdef DSP_DIS_RESMAC
4389 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));
4391 PRES = (uint32)dsp_acc;
4392 #ifdef DSP_DIS_RESMAC
4394 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4398 static void DSP_ror(void)
4402 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);
4404 uint32 r1 = PRM & 0x1F;
4405 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4406 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4410 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);
4414 static void DSP_rorq(void)
4418 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);
4420 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4422 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4424 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4427 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4431 static void DSP_sat16s(void)
4434 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4439 static void DSP_sat32s(void)
4441 int32 r2 = (uint32)PRN;
4442 int32 temp = dsp_acc >> 32;
4443 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4448 static void DSP_sh(void)
4450 int32 sRm = (int32)PRM;
4455 uint32 shift = -sRm;
4460 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4475 dsp_flag_c = _Rn & 0x1;
4488 static void DSP_sha(void)
4490 int32 sRm = (int32)PRM;
4495 uint32 shift = -sRm;
4500 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4515 dsp_flag_c = _Rn & 0x1;
4519 _Rn = ((int32)_Rn) >> 1;
4528 static void DSP_sharq(void)
4530 #ifdef DSP_DIS_SHARQ
4532 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);
4534 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4535 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4537 #ifdef DSP_DIS_SHARQ
4539 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4543 static void DSP_shlq(void)
4547 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);
4549 int32 r1 = 32 - PIMM1;
4550 uint32 res = PRN << r1;
4551 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4555 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4559 static void DSP_shrq(void)
4563 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);
4565 int32 r1 = dsp_convert_zero[PIMM1];
4566 uint32 res = PRN >> r1;
4567 SET_ZN(res); dsp_flag_c = PRN & 1;
4571 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4575 static void DSP_store(void)
4577 #ifdef DSP_DIS_STORE
4579 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);
4581 // DSPWriteLong(PRM, PRN, DSP);
4583 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4584 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4586 pipeline[plPtrExec].address = PRM;
4588 pipeline[plPtrExec].value = PRN;
4589 pipeline[plPtrExec].type = TYPE_DWORD;
4593 static void DSP_storeb(void)
4595 #ifdef DSP_DIS_STOREB
4597 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);
4599 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4600 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4602 // JaguarWriteByte(PRM, PRN, DSP);
4605 pipeline[plPtrExec].address = PRM;
4607 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4609 pipeline[plPtrExec].value = PRN & 0xFF;
4610 pipeline[plPtrExec].type = TYPE_DWORD;
4614 pipeline[plPtrExec].value = PRN;
4615 pipeline[plPtrExec].type = TYPE_BYTE;
4621 static void DSP_storew(void)
4623 #ifdef DSP_DIS_STOREW
4625 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);
4627 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4628 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4630 // JaguarWriteWord(PRM, PRN, DSP);
4633 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4634 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4636 pipeline[plPtrExec].address = PRM;
4639 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4641 pipeline[plPtrExec].value = PRN & 0xFFFF;
4642 pipeline[plPtrExec].type = TYPE_DWORD;
4646 pipeline[plPtrExec].value = PRN;
4647 pipeline[plPtrExec].type = TYPE_WORD;
4652 static void DSP_store_r14_i(void)
4654 #ifdef DSP_DIS_STORE14I
4656 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));
4658 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4660 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4661 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4663 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4665 pipeline[plPtrExec].value = PRN;
4666 pipeline[plPtrExec].type = TYPE_DWORD;
4670 static void DSP_store_r14_r(void)
4672 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4674 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4675 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4677 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4679 pipeline[plPtrExec].value = PRN;
4680 pipeline[plPtrExec].type = TYPE_DWORD;
4684 static void DSP_store_r15_i(void)
4686 #ifdef DSP_DIS_STORE15I
4688 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));
4690 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4692 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4693 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4695 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4697 pipeline[plPtrExec].value = PRN;
4698 pipeline[plPtrExec].type = TYPE_DWORD;
4702 static void DSP_store_r15_r(void)
4704 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4706 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4707 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4709 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4711 pipeline[plPtrExec].value = PRN;
4712 pipeline[plPtrExec].type = TYPE_DWORD;
4716 static void DSP_sub(void)
4720 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);
4722 uint32 res = PRN - PRM;
4723 SET_ZNC_SUB(PRN, PRM, res);
4727 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);
4731 static void DSP_subc(void)
4735 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);
4737 uint32 res = PRN - PRM - dsp_flag_c;
4738 uint32 borrow = dsp_flag_c;
4739 SET_ZNC_SUB(PRN - borrow, PRM, res);
4743 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
4747 static void DSP_subq(void)
4751 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);
4753 uint32 r1 = dsp_convert_zero[PIMM1];
4754 uint32 res = PRN - r1;
4755 SET_ZNC_SUB(PRN, r1, res);
4759 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4763 static void DSP_subqmod(void)
4765 uint32 r1 = dsp_convert_zero[PIMM1];
4767 uint32 res = r2 - r1;
4768 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4770 SET_ZNC_SUB(r2, r1, res);
4773 static void DSP_subqt(void)
4775 #ifdef DSP_DIS_SUBQT
4777 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);
4779 PRES = PRN - dsp_convert_zero[PIMM1];
4780 #ifdef DSP_DIS_SUBQT
4782 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4786 static void DSP_xor(void)
4790 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);
4796 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);