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.
814 if (data & INT_ENA1) // I2S interrupt
816 int freq = GetCalculatedFrequency();
817 //This happens too often to be useful...
818 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
819 DACSetNewFrequency(freq);
821 else if (data & INT_ENA2) // TIMER 0 interrupt
823 int freq = JERRYGetPIT1Frequency();
824 //This happens too often to be useful...
825 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
826 DACSetNewFrequency(freq);
829 /* if (IMASKCleared) // If IMASK was cleared,
832 WriteLog("DSP: Finished interrupt.\n");
834 DSPHandleIRQs(); // see if any other interrupts need servicing!
839 if (/*4-8, 16*/data & 0x101F0)
840 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
841 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
842 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
843 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
844 /*if (data & 0x00020) // CD BIOS DSP code...
846 //001AC1BA: movea.l #$1AC200, A0
847 //001AC1C0: move.l #$1AC68C, D0
850 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
851 uint32 j = 0xF1B97C;//0x1AC200;
852 while (j <= 0xF1BE08)//0x1AC68C)
855 j += dasmjag(JAGUAR_DSP, buffer, j);
856 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
857 WriteLog("\t%08X: %s\n", oldj, buffer);
864 dsp_matrix_control = data;
867 // According to JTRM, only lines 2-11 are addressable, the rest being
868 // hardwired to $F1Bxxx.
869 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
872 dsp_data_organization = data;
877 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
882 ctrl1[0] = ctrl2[0] = data;
889 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
891 bool wasRunning = DSP_RUNNING;
892 // uint32 dsp_was_running = DSP_RUNNING;
893 // Check for DSP -> CPU interrupt
897 WriteLog("DSP: DSP -> CPU interrupt\n");
900 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
901 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
902 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
904 JERRYSetPendingIRQ(IRQ2_DSP);
905 DSPReleaseTimeslice();
906 m68k_set_irq(2); // Set 68000 IPL 2...
910 // Check for CPU -> DSP interrupt
914 WriteLog("DSP: CPU -> DSP interrupt\n");
916 m68k_end_timeslice();
917 DSPReleaseTimeslice();
918 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
922 if (data & SINGLE_STEP)
924 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
927 // Protect writes to VERSION and the interrupt latches...
928 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
929 dsp_control = (dsp_control & mask) | (data & ~mask);
933 ctrl1[8] = ctrl2[8] = dsp_control;
937 // if dsp wasn't running but is now running
938 // execute a few cycles
939 //This is just plain wrong, wrong, WRONG!
940 #ifndef DSP_SINGLE_STEPPING
941 /* if (!dsp_was_running && DSP_RUNNING)
946 //This is WRONG! !!! FIX !!!
947 if (dsp_control & 0x18)
952 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
954 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
957 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
958 // !!! FIX !!! [DONE]
962 m68k_end_timeslice();
964 DSPReleaseTimeslice();
968 //DSPDumpDisassembly();
976 dsp_div_control = data;
978 // default: // unaligned long read
984 //We don't have to break this up like this! We CAN do 32 bit writes!
985 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
986 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
987 //if (offset > 0xF1FFFF)
989 JaguarWriteLong(offset, data, who);
993 // Update the DSP register file pointers depending on REGPAGE bit
995 void DSPUpdateRegisterBanks(void)
997 int bank = (dsp_flags & REGPAGE);
999 if (dsp_flags & IMASK)
1000 bank = 0; // IMASK forces main bank to be bank 0
1003 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1005 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1009 // Check for and handle any asserted DSP IRQs
1011 void DSPHandleIRQs(void)
1013 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1016 // Get the active interrupt bits (latches) & interrupt mask (enables)
1017 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1018 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1020 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1023 if (!bits) // Bail if nothing is enabled
1026 int which = 0; // Determine which interrupt
1040 #ifdef DSP_DEBUG_IRQ
1041 WriteLog("DSP: Generating interrupt #%i...", which);
1044 //if (which == 0) doDSPDis = true;
1046 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1047 // directly into the pipeline, it has the side effect of ensuring that the
1048 // instruction interrupted also gets to do its writeback. We simulate that
1050 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1052 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1053 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1055 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1056 scoreboard[pipeline[plPtrWrite].operand2] = false;
1058 //This should be execute (or should it?--not sure now!)
1059 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1060 //and what just executed is now in the Write position...). So why didn't it do the
1061 //writeback into register 0?
1062 #ifdef DSP_DEBUG_IRQ
1063 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1064 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]);
1065 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]);
1066 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]);
1068 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1070 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1072 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1073 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1076 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1077 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1078 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1079 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1081 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1085 #ifndef NEW_SCOREBOARD
1086 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1087 scoreboard[pipeline[plPtrWrite].operand2] = false;
1089 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1090 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1091 if (scoreboard[pipeline[plPtrWrite].operand2])
1092 scoreboard[pipeline[plPtrWrite].operand2]--;
1099 ctrl2[4] = dsp_flags;
1102 DSPUpdateRegisterBanks();
1103 #ifdef DSP_DEBUG_IRQ
1104 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1105 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]);
1108 // subqt #4,r31 ; pre-decrement stack pointer
1109 // move pc,r30 ; address of interrupted code
1110 // store r30,(r31) ; store return address
1117 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1118 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1119 //It missed the place that it was supposed to come back to, so this is WRONG!
1121 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1123 // R -> baz (<- PC points here)
1124 // E -> bar (when it should point here!)
1127 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1128 // which means (assuming they're all 2 bytes long) that the code below will come back on
1129 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1130 // instruction stream...
1132 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1133 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1136 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1140 // movei #service_address,r30 ; pointer to ISR entry
1141 // jump (r30) ; jump to ISR
1143 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1146 ctrl2[0] = regs2[30] = dsp_pc;
1153 // Non-pipelined version...
1155 void DSPHandleIRQsNP(void)
1159 memcpy(dsp_ram_8, ram1, 0x2000);
1160 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1161 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1164 dsp_remain = ctrl1[2];
1165 dsp_modulo = ctrl1[3];
1166 dsp_flags = ctrl1[4];
1167 dsp_matrix_control = ctrl1[5];
1168 dsp_pointer_to_matrix = ctrl1[6];
1169 dsp_data_organization = ctrl1[7];
1170 dsp_control = ctrl1[8];
1171 dsp_div_control = ctrl1[9];
1172 IMASKCleared = ctrl1[10];
1173 dsp_flag_z = ctrl1[11];
1174 dsp_flag_n = ctrl1[12];
1175 dsp_flag_c = ctrl1[13];
1176 DSPUpdateRegisterBanks();
1179 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1182 // Get the active interrupt bits (latches) & interrupt mask (enables)
1183 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1184 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1186 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1189 if (!bits) // Bail if nothing is enabled
1192 int which = 0; // Determine which interrupt
1206 #ifdef DSP_DEBUG_IRQ
1207 WriteLog("DSP: Generating interrupt #%i...", which);
1213 ctrl1[4] = dsp_flags;
1216 DSPUpdateRegisterBanks();
1217 #ifdef DSP_DEBUG_IRQ
1218 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1221 // subqt #4,r31 ; pre-decrement stack pointer
1222 // move pc,r30 ; address of interrupted code
1223 // store r30,(r31) ; store return address
1230 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1233 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1237 // movei #service_address,r30 ; pointer to ISR entry
1238 // jump (r30) ; jump to ISR
1240 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1243 ctrl1[0] = regs1[30] = dsp_pc;
1249 // Set the specified DSP IRQ line to a given state
1251 void DSPSetIRQLine(int irqline, int state)
1253 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1254 uint32 mask = INT_LAT0 << irqline;
1255 dsp_control &= ~mask; // Clear the latch bit
1258 ctrl1[8] = ctrl2[8] = dsp_control;
1264 dsp_control |= mask; // Set the latch bit
1268 ctrl1[8] = ctrl2[8] = dsp_control;
1274 // Not sure if this is correct behavior, but according to JTRM,
1275 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1276 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1277 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1282 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1283 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1284 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1286 dsp_build_branch_condition_table();
1288 srandom(time(NULL)); // For randomizing local RAM
1293 dsp_pc = 0x00F1B000;
1294 dsp_acc = 0x00000000;
1295 dsp_remain = 0x00000000;
1296 dsp_modulo = 0xFFFFFFFF;
1297 dsp_flags = 0x00040000;
1298 dsp_matrix_control = 0x00000000;
1299 dsp_pointer_to_matrix = 0x00000000;
1300 dsp_data_organization = 0xFFFFFFFF;
1301 dsp_control = 0x00002000; // Report DSP version 2
1302 dsp_div_control = 0x00000000;
1305 dsp_reg = dsp_reg_bank_0;
1306 dsp_alternate_reg = dsp_reg_bank_1;
1308 for(int i=0; i<32; i++)
1309 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1312 IMASKCleared = false;
1315 // memset(dsp_ram_8, 0xFF, 0x2000);
1316 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1317 for(uint32 i=0; i<8192; i+=4)
1319 *((uint32 *)(&dsp_ram_8[i])) = random();
1323 void DSPDumpDisassembly(void)
1327 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1328 uint32 j = 0xF1B000;
1330 while (j <= 0xF1CFFF)
1333 j += dasmjag(JAGUAR_DSP, buffer, j);
1334 WriteLog("\t%08X: %s\n", oldj, buffer);
1338 void DSPDumpRegisters(void)
1340 //Shoud add modulus, etc to dump here...
1341 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1342 WriteLog("\nRegisters bank 0\n");
1344 for(int j=0; j<8; j++)
1346 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1347 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1348 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1349 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1350 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1353 WriteLog("Registers bank 1\n");
1355 for(int j=0; j<8; j++)
1357 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1358 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1359 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1360 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1361 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1368 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1369 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1371 // get the active interrupt bits
1372 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1373 // get the interrupt mask
1374 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1376 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1377 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1378 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1379 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1380 WriteLog("\nRegisters bank 0\n");
1382 for(int j=0; j<8; j++)
1384 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1385 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1386 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1387 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1388 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1391 WriteLog("\nRegisters bank 1\n");
1395 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1396 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1397 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1398 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1399 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1404 static char buffer[512];
1405 j = DSP_WORK_RAM_BASE;
1407 while (j <= 0xF1CFFF)
1410 j += dasmjag(JAGUAR_DSP, buffer, j);
1411 WriteLog("\t%08X: %s\n", oldj, buffer);
1414 WriteLog("DSP opcodes use:\n");
1418 if (dsp_opcode_use[i])
1419 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1422 // memory_free(dsp_ram_8);
1423 // memory_free(dsp_reg_bank_0);
1424 // memory_free(dsp_reg_bank_1);
1425 // if (dsp_branch_condition_table)
1426 // free(dsp_branch_condition_table);
1428 // if (mirror_table)
1429 // free(mirror_table);
1435 // DSP comparison core...
1438 static uint16 lastExec;
1439 void DSPExecComp(int32 cycles)
1441 while (cycles > 0 && DSP_RUNNING)
1443 // Load up vars for non-pipelined core
1444 memcpy(dsp_ram_8, ram1, 0x2000);
1445 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1446 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1449 dsp_remain = ctrl1[2];
1450 dsp_modulo = ctrl1[3];
1451 dsp_flags = ctrl1[4];
1452 dsp_matrix_control = ctrl1[5];
1453 dsp_pointer_to_matrix = ctrl1[6];
1454 dsp_data_organization = ctrl1[7];
1455 dsp_control = ctrl1[8];
1456 dsp_div_control = ctrl1[9];
1457 IMASKCleared = ctrl1[10];
1458 dsp_flag_z = ctrl1[11];
1459 dsp_flag_n = ctrl1[12];
1460 dsp_flag_c = ctrl1[13];
1461 DSPUpdateRegisterBanks();
1463 // Decrement cycles based on non-pipelined core...
1464 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1465 cycles -= dsp_opcode_cycles[instr1 >> 10];
1467 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1468 DSPExec(1); // Do *one* instruction
1471 memcpy(ram1, dsp_ram_8, 0x2000);
1472 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1473 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1476 ctrl1[2] = dsp_remain;
1477 ctrl1[3] = dsp_modulo;
1478 ctrl1[4] = dsp_flags;
1479 ctrl1[5] = dsp_matrix_control;
1480 ctrl1[6] = dsp_pointer_to_matrix;
1481 ctrl1[7] = dsp_data_organization;
1482 ctrl1[8] = dsp_control;
1483 ctrl1[9] = dsp_div_control;
1484 ctrl1[10] = IMASKCleared;
1485 ctrl1[11] = dsp_flag_z;
1486 ctrl1[12] = dsp_flag_n;
1487 ctrl1[13] = dsp_flag_c;
1489 // Load up vars for pipelined core
1490 memcpy(dsp_ram_8, ram2, 0x2000);
1491 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1492 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1495 dsp_remain = ctrl2[2];
1496 dsp_modulo = ctrl2[3];
1497 dsp_flags = ctrl2[4];
1498 dsp_matrix_control = ctrl2[5];
1499 dsp_pointer_to_matrix = ctrl2[6];
1500 dsp_data_organization = ctrl2[7];
1501 dsp_control = ctrl2[8];
1502 dsp_div_control = ctrl2[9];
1503 IMASKCleared = ctrl2[10];
1504 dsp_flag_z = ctrl2[11];
1505 dsp_flag_n = ctrl2[12];
1506 dsp_flag_c = ctrl2[13];
1507 DSPUpdateRegisterBanks();
1509 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1510 DSPExecP2(1); // Do *one* instruction
1513 memcpy(ram2, dsp_ram_8, 0x2000);
1514 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1515 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1518 ctrl2[2] = dsp_remain;
1519 ctrl2[3] = dsp_modulo;
1520 ctrl2[4] = dsp_flags;
1521 ctrl2[5] = dsp_matrix_control;
1522 ctrl2[6] = dsp_pointer_to_matrix;
1523 ctrl2[7] = dsp_data_organization;
1524 ctrl2[8] = dsp_control;
1525 ctrl2[9] = dsp_div_control;
1526 ctrl2[10] = IMASKCleared;
1527 ctrl2[11] = dsp_flag_z;
1528 ctrl2[12] = dsp_flag_n;
1529 ctrl2[13] = dsp_flag_c;
1531 if (instr1 != lastExec)
1533 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1535 // 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));
1536 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1537 // if (ctrl1[0] < ppc) // P ran ahead of NP
1538 //How to test this crap???
1541 DSPExecP2(1); // Do one more instruction
1544 memcpy(ram2, dsp_ram_8, 0x2000);
1545 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1546 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1549 ctrl2[2] = dsp_remain;
1550 ctrl2[3] = dsp_modulo;
1551 ctrl2[4] = dsp_flags;
1552 ctrl2[5] = dsp_matrix_control;
1553 ctrl2[6] = dsp_pointer_to_matrix;
1554 ctrl2[7] = dsp_data_organization;
1555 ctrl2[8] = dsp_control;
1556 ctrl2[9] = dsp_div_control;
1557 ctrl2[10] = IMASKCleared;
1558 ctrl2[11] = dsp_flag_z;
1559 ctrl2[12] = dsp_flag_n;
1560 ctrl2[13] = dsp_flag_c;
1562 // else // NP ran ahead of P
1563 if (instr1 != lastExec) // Must be the other way...
1566 // Load up vars for non-pipelined core
1567 memcpy(dsp_ram_8, ram1, 0x2000);
1568 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1569 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1572 dsp_remain = ctrl1[2];
1573 dsp_modulo = ctrl1[3];
1574 dsp_flags = ctrl1[4];
1575 dsp_matrix_control = ctrl1[5];
1576 dsp_pointer_to_matrix = ctrl1[6];
1577 dsp_data_organization = ctrl1[7];
1578 dsp_control = ctrl1[8];
1579 dsp_div_control = ctrl1[9];
1580 IMASKCleared = ctrl1[10];
1581 dsp_flag_z = ctrl1[11];
1582 dsp_flag_n = ctrl1[12];
1583 dsp_flag_c = ctrl1[13];
1584 DSPUpdateRegisterBanks();
1586 for(int k=0; k<2; k++)
1588 // Decrement cycles based on non-pipelined core...
1589 instr1 = DSPReadWord(dsp_pc, DSP);
1590 cycles -= dsp_opcode_cycles[instr1 >> 10];
1592 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1593 DSPExec(1); // Do *one* instruction
1597 memcpy(ram1, dsp_ram_8, 0x2000);
1598 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1599 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1602 ctrl1[2] = dsp_remain;
1603 ctrl1[3] = dsp_modulo;
1604 ctrl1[4] = dsp_flags;
1605 ctrl1[5] = dsp_matrix_control;
1606 ctrl1[6] = dsp_pointer_to_matrix;
1607 ctrl1[7] = dsp_data_organization;
1608 ctrl1[8] = dsp_control;
1609 ctrl1[9] = dsp_div_control;
1610 ctrl1[10] = IMASKCleared;
1611 ctrl1[11] = dsp_flag_z;
1612 ctrl1[12] = dsp_flag_n;
1613 ctrl1[13] = dsp_flag_c;
1617 if (instr1 != lastExec)
1619 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1621 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1622 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1635 // DSP execution core
1637 //static bool R20Set = false, tripwire = false;
1638 //static uint32 pcQueue[32], ptrPCQ = 0;
1639 void DSPExec(int32 cycles)
1641 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1642 dsp_check_if_i2s_interrupt_needed();*/
1644 #ifdef DSP_SINGLE_STEPPING
1645 if (dsp_control & 0x18)
1648 dsp_control &= ~0x10;
1651 //There is *no* good reason to do this here!
1653 dsp_releaseTimeSlice_flag = 0;
1656 while (cycles > 0 && DSP_RUNNING)
1658 /*extern uint32 totalFrames;
1659 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1660 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1661 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1663 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1666 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1668 if (dsp_pc == 0xF1B092)
1669 doDSPDis = false;//*/
1670 /*if (dsp_pc == 0xF1B140)
1671 doDSPDis = true;//*/
1673 if (IMASKCleared) // If IMASK was cleared,
1675 #ifdef DSP_DEBUG_IRQ
1676 WriteLog("DSP: Finished interrupt.\n");
1678 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1679 IMASKCleared = false;
1684 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1685 for(int i=0; i<80; i+=4)
1686 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1689 /*if (dsp_pc == 0xF1B55E)
1691 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1693 /*if (dsp_pc == 0xF1B7D2) // Start here???
1695 pcQueue[ptrPCQ++] = dsp_pc;
1697 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1698 uint32 index = opcode >> 10;
1699 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1700 dsp_opcode_second_parameter = opcode & 0x1F;
1702 dsp_opcode[index]();
1703 dsp_opcode_use[index]++;
1704 cycles -= dsp_opcode_cycles[index];
1705 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1707 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1710 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1712 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1714 DSPDumpDisassembly();
1717 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1720 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1723 WriteLog("\nBacktrace:\n");
1724 for(int i=0; i<32; i++)
1726 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1727 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1737 // DSP opcode handlers
1740 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1741 // can cause trouble because an interrupt can occur *before* the instruction following the
1742 // jump can execute... !!! FIX !!!
1743 static void dsp_opcode_jump(void)
1746 const char * condition[32] =
1747 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1748 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1749 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1750 "???", "???", "???", "F" };
1752 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);
1755 /* dsp_flag_c=dsp_flag_c?1:0;
1756 dsp_flag_z=dsp_flag_z?1:0;
1757 dsp_flag_n=dsp_flag_n?1:0;*/
1758 // KLUDGE: Used by BRANCH_CONDITION
1759 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1761 if (BRANCH_CONDITION(IMM_2))
1765 WriteLog("Branched!\n");
1767 uint32 delayed_pc = RM;
1769 dsp_pc = delayed_pc;
1774 WriteLog("Branch NOT taken.\n");
1778 static void dsp_opcode_jr(void)
1781 const char * condition[32] =
1782 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1783 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1784 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1785 "???", "???", "???", "F" };
1787 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);
1790 /* dsp_flag_c=dsp_flag_c?1:0;
1791 dsp_flag_z=dsp_flag_z?1:0;
1792 dsp_flag_n=dsp_flag_n?1:0;*/
1793 // KLUDGE: Used by BRANCH_CONDITION
1794 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1796 if (BRANCH_CONDITION(IMM_2))
1800 WriteLog("Branched!\n");
1802 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1803 int32 delayed_pc = dsp_pc + (offset * 2);
1805 dsp_pc = delayed_pc;
1810 WriteLog("Branch NOT taken.\n");
1814 static void dsp_opcode_add(void)
1818 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);
1820 uint32 res = RN + RM;
1821 SET_ZNC_ADD(RN, RM, res);
1825 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1829 static void dsp_opcode_addc(void)
1833 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);
1835 uint32 res = RN + RM + dsp_flag_c;
1836 uint32 carry = dsp_flag_c;
1837 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1838 SET_ZNC_ADD(RN + carry, RM, res);
1839 // SET_ZNC_ADD(RN, RM + carry, res);
1843 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);
1847 static void dsp_opcode_addq(void)
1851 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);
1853 uint32 r1 = dsp_convert_zero[IMM_1];
1854 uint32 res = RN + r1;
1855 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1859 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1863 static void dsp_opcode_sub(void)
1867 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);
1869 uint32 res = RN - RM;
1870 SET_ZNC_SUB(RN, RM, res);
1874 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);
1878 static void dsp_opcode_subc(void)
1882 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);
1884 uint32 res = RN - RM - dsp_flag_c;
1885 uint32 borrow = dsp_flag_c;
1886 SET_ZNC_SUB(RN - borrow, RM, res);
1890 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);
1894 static void dsp_opcode_subq(void)
1898 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);
1900 uint32 r1 = dsp_convert_zero[IMM_1];
1901 uint32 res = RN - r1;
1902 SET_ZNC_SUB(RN, r1, res);
1906 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1910 static void dsp_opcode_cmp(void)
1914 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);
1916 uint32 res = RN - RM;
1917 SET_ZNC_SUB(RN, RM, res);
1920 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1924 static void dsp_opcode_cmpq(void)
1926 static int32 sqtable[32] =
1927 { 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 };
1930 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);
1932 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1933 uint32 res = RN - r1;
1934 SET_ZNC_SUB(RN, r1, res);
1937 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1941 static void dsp_opcode_and(void)
1945 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);
1951 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);
1955 static void dsp_opcode_or(void)
1959 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);
1965 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1969 static void dsp_opcode_xor(void)
1973 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);
1979 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1983 static void dsp_opcode_not(void)
1987 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);
1993 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1997 static void dsp_opcode_move_pc(void)
2002 static void dsp_opcode_store_r14_indexed(void)
2004 #ifdef DSP_DIS_STORE14I
2006 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));
2008 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2009 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2011 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2015 static void dsp_opcode_store_r15_indexed(void)
2017 #ifdef DSP_DIS_STORE15I
2019 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));
2021 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2022 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2024 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2028 static void dsp_opcode_load_r14_ri(void)
2030 #ifdef DSP_DIS_LOAD14R
2032 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);
2034 #ifdef DSP_CORRECT_ALIGNMENT
2035 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2037 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2039 #ifdef DSP_DIS_LOAD14R
2041 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2045 static void dsp_opcode_load_r15_ri(void)
2047 #ifdef DSP_DIS_LOAD15R
2049 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);
2051 #ifdef DSP_CORRECT_ALIGNMENT
2052 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2054 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2056 #ifdef DSP_DIS_LOAD15R
2058 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2062 static void dsp_opcode_store_r14_ri(void)
2064 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2067 static void dsp_opcode_store_r15_ri(void)
2069 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2072 static void dsp_opcode_nop(void)
2076 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2080 static void dsp_opcode_storeb(void)
2082 #ifdef DSP_DIS_STOREB
2084 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);
2086 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2087 DSPWriteLong(RM, RN & 0xFF, DSP);
2089 JaguarWriteByte(RM, RN, DSP);
2092 static void dsp_opcode_storew(void)
2094 #ifdef DSP_DIS_STOREW
2096 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);
2098 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2099 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2100 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2102 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2104 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2105 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2107 JaguarWriteWord(RM, RN, DSP);
2111 static void dsp_opcode_store(void)
2113 #ifdef DSP_DIS_STORE
2115 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);
2117 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2118 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2120 DSPWriteLong(RM, RN, DSP);
2124 static void dsp_opcode_loadb(void)
2126 #ifdef DSP_DIS_LOADB
2128 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);
2130 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2131 RN = DSPReadLong(RM, DSP) & 0xFF;
2133 RN = JaguarReadByte(RM, DSP);
2134 #ifdef DSP_DIS_LOADB
2136 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2140 static void dsp_opcode_loadw(void)
2142 #ifdef DSP_DIS_LOADW
2144 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);
2146 #ifdef DSP_CORRECT_ALIGNMENT
2147 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2148 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2150 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2152 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2153 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2155 RN = JaguarReadWord(RM, DSP);
2157 #ifdef DSP_DIS_LOADW
2159 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2163 static void dsp_opcode_load(void)
2167 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);
2169 #ifdef DSP_CORRECT_ALIGNMENT
2170 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2172 RN = DSPReadLong(RM, DSP);
2176 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2180 static void dsp_opcode_load_r14_indexed(void)
2182 #ifdef DSP_DIS_LOAD14I
2184 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);
2186 #ifdef DSP_CORRECT_ALIGNMENT
2187 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2189 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2191 #ifdef DSP_DIS_LOAD14I
2193 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2197 static void dsp_opcode_load_r15_indexed(void)
2199 #ifdef DSP_DIS_LOAD15I
2201 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);
2203 #ifdef DSP_CORRECT_ALIGNMENT
2204 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2206 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2208 #ifdef DSP_DIS_LOAD15I
2210 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2214 static void dsp_opcode_movei(void)
2216 #ifdef DSP_DIS_MOVEI
2218 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);
2220 // This instruction is followed by 32-bit value in LSW / MSW format...
2221 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2223 #ifdef DSP_DIS_MOVEI
2225 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2229 static void dsp_opcode_moveta(void)
2231 #ifdef DSP_DIS_MOVETA
2233 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);
2236 #ifdef DSP_DIS_MOVETA
2238 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);
2242 static void dsp_opcode_movefa(void)
2244 #ifdef DSP_DIS_MOVEFA
2246 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);
2249 #ifdef DSP_DIS_MOVEFA
2251 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);
2255 static void dsp_opcode_move(void)
2259 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);
2264 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);
2268 static void dsp_opcode_moveq(void)
2270 #ifdef DSP_DIS_MOVEQ
2272 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);
2275 #ifdef DSP_DIS_MOVEQ
2277 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2281 static void dsp_opcode_resmac(void)
2283 #ifdef DSP_DIS_RESMAC
2285 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));
2287 RN = (uint32)dsp_acc;
2288 #ifdef DSP_DIS_RESMAC
2290 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2294 static void dsp_opcode_imult(void)
2296 #ifdef DSP_DIS_IMULT
2298 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);
2300 RN = (int16)RN * (int16)RM;
2302 #ifdef DSP_DIS_IMULT
2304 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);
2308 static void dsp_opcode_mult(void)
2312 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);
2314 RN = (uint16)RM * (uint16)RN;
2318 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2322 static void dsp_opcode_bclr(void)
2326 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);
2328 uint32 res = RN & ~(1 << IMM_1);
2333 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2337 static void dsp_opcode_btst(void)
2341 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);
2343 dsp_flag_z = (~RN >> IMM_1) & 1;
2346 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2350 static void dsp_opcode_bset(void)
2354 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);
2356 uint32 res = RN | (1 << IMM_1);
2361 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2365 static void dsp_opcode_subqt(void)
2367 #ifdef DSP_DIS_SUBQT
2369 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);
2371 RN -= dsp_convert_zero[IMM_1];
2372 #ifdef DSP_DIS_SUBQT
2374 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2378 static void dsp_opcode_addqt(void)
2380 #ifdef DSP_DIS_ADDQT
2382 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);
2384 RN += dsp_convert_zero[IMM_1];
2385 #ifdef DSP_DIS_ADDQT
2387 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2391 static void dsp_opcode_imacn(void)
2393 #ifdef DSP_DIS_IMACN
2395 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);
2397 int32 res = (int16)RM * (int16)RN;
2398 dsp_acc += (int64)res;
2399 //Should we AND the result to fit into 40 bits here???
2400 #ifdef DSP_DIS_IMACN
2402 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));
2406 static void dsp_opcode_mtoi(void)
2408 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2412 static void dsp_opcode_normi(void)
2419 while ((_Rm & 0xffc00000) == 0)
2424 while ((_Rm & 0xff800000) != 0)
2434 static void dsp_opcode_mmult(void)
2436 int count = dsp_matrix_control&0x0f;
2437 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2441 if (!(dsp_matrix_control & 0x10))
2443 for (int i = 0; i < count; i++)
2447 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2449 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2450 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2457 for (int i = 0; i < count; i++)
2461 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2463 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2464 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2469 RN = res = (int32)accum;
2471 //NOTE: The flags are set based upon the last add/multiply done...
2475 static void dsp_opcode_abs(void)
2479 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);
2484 if (_Rn == 0x80000000)
2488 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2489 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2494 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2498 static void dsp_opcode_div(void)
2505 if (dsp_div_control & 1)
2507 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2508 if (dsp_remain&0x80000000)
2510 RN = (((uint64)_Rn) << 16) / _Rm;
2514 dsp_remain = _Rn % _Rm;
2515 if (dsp_remain&0x80000000)
2524 static void dsp_opcode_imultn(void)
2526 #ifdef DSP_DIS_IMULTN
2528 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);
2530 // This is OK, since this multiply won't overflow 32 bits...
2531 int32 res = (int32)((int16)RN * (int16)RM);
2532 dsp_acc = (int64)res;
2534 #ifdef DSP_DIS_IMULTN
2536 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));
2540 static void dsp_opcode_neg(void)
2544 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);
2547 SET_ZNC_SUB(0, RN, res);
2551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2555 static void dsp_opcode_shlq(void)
2559 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);
2561 int32 r1 = 32 - IMM_1;
2562 uint32 res = RN << r1;
2563 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2571 static void dsp_opcode_shrq(void)
2575 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);
2577 int32 r1 = dsp_convert_zero[IMM_1];
2578 uint32 res = RN >> r1;
2579 SET_ZN(res); dsp_flag_c = RN & 1;
2583 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2587 static void dsp_opcode_ror(void)
2591 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);
2593 uint32 r1 = RM & 0x1F;
2594 uint32 res = (RN >> r1) | (RN << (32 - r1));
2595 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2599 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);
2603 static void dsp_opcode_rorq(void)
2607 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);
2609 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2611 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2613 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2616 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2620 static void dsp_opcode_sha(void)
2622 int32 sRm=(int32)RM;
2628 if (shift>=32) shift=32;
2629 dsp_flag_c=(_Rn&0x80000000)>>31;
2639 if (shift>=32) shift=32;
2643 _Rn=((int32)_Rn)>>1;
2651 static void dsp_opcode_sharq(void)
2653 #ifdef DSP_DIS_SHARQ
2655 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);
2657 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2658 SET_ZN(res); dsp_flag_c = RN & 0x01;
2660 #ifdef DSP_DIS_SHARQ
2662 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2666 static void dsp_opcode_sh(void)
2668 int32 sRm=(int32)RM;
2673 uint32 shift=(-sRm);
2674 if (shift>=32) shift=32;
2675 dsp_flag_c=(_Rn&0x80000000)>>31;
2685 if (shift>=32) shift=32;
2697 void dsp_opcode_addqmod(void)
2699 #ifdef DSP_DIS_ADDQMOD
2701 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);
2703 uint32 r1 = dsp_convert_zero[IMM_1];
2705 uint32 res = r2 + r1;
2706 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2708 SET_ZNC_ADD(r2, r1, res);
2709 #ifdef DSP_DIS_ADDQMOD
2711 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2715 void dsp_opcode_subqmod(void)
2717 uint32 r1 = dsp_convert_zero[IMM_1];
2719 uint32 res = r2 - r1;
2720 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2723 SET_ZNC_SUB(r2, r1, res);
2726 void dsp_opcode_mirror(void)
2729 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2733 void dsp_opcode_sat32s(void)
2735 int32 r2 = (uint32)RN;
2736 int32 temp = dsp_acc >> 32;
2737 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2742 void dsp_opcode_sat16s(void)
2745 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2751 // New pipelined DSP core
2754 static void DSP_abs(void);
2755 static void DSP_add(void);
2756 static void DSP_addc(void);
2757 static void DSP_addq(void);
2758 static void DSP_addqmod(void);
2759 static void DSP_addqt(void);
2760 static void DSP_and(void);
2761 static void DSP_bclr(void);
2762 static void DSP_bset(void);
2763 static void DSP_btst(void);
2764 static void DSP_cmp(void);
2765 static void DSP_cmpq(void);
2766 static void DSP_div(void);
2767 static void DSP_imacn(void);
2768 static void DSP_imult(void);
2769 static void DSP_imultn(void);
2770 static void DSP_illegal(void);
2771 static void DSP_jr(void);
2772 static void DSP_jump(void);
2773 static void DSP_load(void);
2774 static void DSP_loadb(void);
2775 static void DSP_loadw(void);
2776 static void DSP_load_r14_i(void);
2777 static void DSP_load_r14_r(void);
2778 static void DSP_load_r15_i(void);
2779 static void DSP_load_r15_r(void);
2780 static void DSP_mirror(void);
2781 static void DSP_mmult(void);
2782 static void DSP_move(void);
2783 static void DSP_movefa(void);
2784 static void DSP_movei(void);
2785 static void DSP_movepc(void);
2786 static void DSP_moveq(void);
2787 static void DSP_moveta(void);
2788 static void DSP_mtoi(void);
2789 static void DSP_mult(void);
2790 static void DSP_neg(void);
2791 static void DSP_nop(void);
2792 static void DSP_normi(void);
2793 static void DSP_not(void);
2794 static void DSP_or(void);
2795 static void DSP_resmac(void);
2796 static void DSP_ror(void);
2797 static void DSP_rorq(void);
2798 static void DSP_sat16s(void);
2799 static void DSP_sat32s(void);
2800 static void DSP_sh(void);
2801 static void DSP_sha(void);
2802 static void DSP_sharq(void);
2803 static void DSP_shlq(void);
2804 static void DSP_shrq(void);
2805 static void DSP_store(void);
2806 static void DSP_storeb(void);
2807 static void DSP_storew(void);
2808 static void DSP_store_r14_i(void);
2809 static void DSP_store_r14_r(void);
2810 static void DSP_store_r15_i(void);
2811 static void DSP_store_r15_r(void);
2812 static void DSP_sub(void);
2813 static void DSP_subc(void);
2814 static void DSP_subq(void);
2815 static void DSP_subqmod(void);
2816 static void DSP_subqt(void);
2817 static void DSP_xor(void);
2819 void (* DSPOpcode[64])() =
2821 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2822 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2823 DSP_neg, DSP_and, DSP_or, DSP_xor,
2824 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2826 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2827 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2828 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2829 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2831 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2832 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2833 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2834 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2836 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2837 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2838 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2839 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2842 bool readAffected[64][2] =
2844 { true, true}, { true, true}, {false, true}, {false, true},
2845 { true, true}, { true, true}, {false, true}, {false, true},
2846 {false, true}, { true, true}, { true, true}, { true, true},
2847 {false, true}, {false, true}, {false, true}, {false, true},
2849 { true, true}, { true, true}, { true, true}, {false, true},
2850 { true, true}, { true, true}, {false, true}, { true, true},
2851 {false, true}, {false, true}, { true, true}, {false, true},
2852 { true, true}, {false, true}, { true, true}, {false, true},
2854 {false, true}, {false, true}, { true, false}, {false, false},
2855 { true, false}, {false, false}, {false, false}, { true, false},
2856 { true, false}, { true, false}, {false, true}, { true, false},
2857 { true, false}, { true, true}, { true, true}, { true, true},
2859 {false, true}, { true, true}, { true, true}, {false, true},
2860 { true, false}, { true, false}, { true, true}, { true, false},
2861 { true, false}, {false, false}, { true, false}, { true, false},
2862 { true, true}, { true, true}, {false, false}, {false, true}
2865 bool isLoadStore[65] =
2867 false, false, false, false, false, false, false, false,
2868 false, false, false, false, false, false, false, false,
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, true,
2874 true, true, false, true, true, true, true, true,
2876 false, true, true, false, false, false, false, false,
2877 false, false, true, true, true, true, false, false, false
2880 void FlushDSPPipeline(void)
2882 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2884 for(int i=0; i<4; i++)
2885 pipeline[i].opcode = PIPELINE_STALL;
2887 for(int i=0; i<32; i++)
2892 // New pipelined DSP execution core
2894 /*void DSPExecP(int32 cycles)
2896 // bool inhibitFetch = false;
2898 dsp_releaseTimeSlice_flag = 0;
2901 while (cycles > 0 && DSP_RUNNING)
2903 WriteLog("DSPExecP: Pipeline status...\n");
2904 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);
2905 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);
2906 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);
2907 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);
2908 WriteLog(" --> Scoreboard: ");
2909 for(int i=0; i<32; i++)
2910 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2912 // Stage 1: Instruction fetch
2913 // if (!inhibitFetch)
2915 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2916 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2917 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2918 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2919 if (pipeline[plPtrFetch].opcode == 38)
2920 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2921 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2924 // inhibitFetch = false;
2925 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2927 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2928 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2929 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2930 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2931 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2932 // Stage 2: Read registers
2933 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2934 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2935 if (scoreboard[pipeline[plPtrRead].operand2])
2936 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2937 // We have a hit in the scoreboard, so we have to stall the pipeline...
2939 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2940 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2941 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2942 pipeline[plPtrFetch] = pipeline[plPtrRead];
2943 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2947 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2948 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2949 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2951 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2952 // Shouldn't we be more selective with the register scoreboarding?
2953 // Yes, we should. !!! FIX !!!
2954 scoreboard[pipeline[plPtrRead].operand2] = true;
2955 //Advance PC here??? Yes.
2956 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2957 //This is a mangling of the pipeline stages, but what else to do???
2958 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2961 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2962 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);
2963 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);
2964 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);
2965 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);
2967 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2969 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2970 DSPOpcode[pipeline[plPtrExec].opcode]();
2971 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2972 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2977 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2978 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);
2979 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);
2980 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);
2981 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);
2982 // Stage 4: Write back register
2983 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2985 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2986 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2988 scoreboard[pipeline[plPtrWrite].operand1]
2989 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2992 // Push instructions through the pipeline...
2993 plPtrFetch = (++plPtrFetch) & 0x03;
2994 plPtrRead = (++plPtrRead) & 0x03;
2995 plPtrExec = (++plPtrExec) & 0x03;
2996 plPtrWrite = (++plPtrWrite) & 0x03;
3003 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3005 // Should be fixed now. Another problem is figuring how to do the sequence following
3006 // a branch followed with the JR & JUMP instructions...
3008 // There are two conflicting problems:
3011 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3012 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3013 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3014 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3015 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3016 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3017 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3018 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3019 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3020 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3021 DSP: Finished interrupt.
3022 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3023 ; bank 0 (where is was prepared)!
3024 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3025 F1B252: NOP [NCZ:001]
3028 // The other is when you see this at the end of an IRQ:
3031 JUMP T, (R29) ; R29 = Previous stack + 2
3032 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3034 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3035 ; 1) The STORE goes through the pipeline and is executed/written back
3036 ; 2) The pipeline is flushed
3037 ; 3) The DSP_PC is set to the new address
3038 ; 4) Execution resumes
3040 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3041 ; bank 0 instead of the current bank 1 and so goes astray!
3044 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3045 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3049 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3050 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3051 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3052 If it were done properly, the STORE write back would occur *after* (well, technically,
3053 during) the execution of the the JUMP that follows it.
3057 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3058 F1B08A: NOP [NCZ:001]
3060 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3063 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3066 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3067 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3068 F1B08A: NOP [NCZ:001]
3070 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3073 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3074 DSP: CPU -> DSP interrupt
3075 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3076 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3078 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3081 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3082 F1B006: NOP [NCZ:001]
3084 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3087 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3088 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3091 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3092 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3095 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3096 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3099 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3100 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3103 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3106 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3109 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3110 F1B0FE: NOP [NCZ:000]
3112 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3115 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3118 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3119 F1B138: NOP [NCZ:000]
3121 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3124 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3125 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3126 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3129 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3130 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3133 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3134 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3135 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3137 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3138 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3141 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3142 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3143 DSP: Finished interrupt.
3144 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3146 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3149 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3150 F1B016: NOP [NCZ:001]
3152 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3155 uint32 pcQueue1[0x400];
3157 static uint32 prevR1;
3158 //Let's try a 3 stage pipeline....
3159 //Looks like 3 stage is correct, otherwise bad things happen...
3160 void DSPExecP2(int32 cycles)
3162 dsp_releaseTimeSlice_flag = 0;
3165 while (cycles > 0 && DSP_RUNNING)
3167 /*extern uint32 totalFrames;
3168 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3169 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3170 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3172 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3175 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3177 if (dsp_pc == 0xF1B092)
3178 doDSPDis = false;//*/
3179 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3180 doDSPDis = true;//*/
3181 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3182 doDSPDis = true;//*/
3183 /*if (dsp_pc == 0xF1B0A0)
3184 doDSPDis = true;//*/
3185 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3186 doDSPDis = true;//*/
3187 //Two parter... (not sure how to write this)
3188 //if (dsp_pc == 0xF1B0D2)
3189 // prevR1 = dsp_reg[1];
3191 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3192 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3195 pcQueue1[pcQPtr1++] = dsp_pc;
3198 #ifdef DSP_DEBUG_PL2
3199 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3201 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3206 for(int i=0; i<0x400; i++)
3208 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3209 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3215 if (IMASKCleared) // If IMASK was cleared,
3217 #ifdef DSP_DEBUG_IRQ
3218 WriteLog("DSP: Finished interrupt.\n");
3220 DSPHandleIRQs(); // See if any other interrupts are pending!
3221 IMASKCleared = false;
3224 //if (dsp_flags & REGPAGE)
3225 // WriteLog(" --> REGPAGE has just been set!\n");
3226 #ifdef DSP_DEBUG_PL2
3229 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3230 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]);
3231 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]);
3232 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]);
3233 WriteLog(" --> Scoreboard: ");
3234 for(int i=0; i<32; i++)
3235 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3239 // Stage 1a: Instruction fetch
3240 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3241 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3242 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3243 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3244 if (pipeline[plPtrRead].opcode == 38)
3245 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3246 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3247 #ifdef DSP_DEBUG_PL2
3250 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3251 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3252 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]);
3253 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]);
3254 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]);
3257 // Stage 1b: Read registers
3258 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3259 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3261 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3262 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3263 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3264 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3265 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3266 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3267 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3269 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3270 // We have a hit in the scoreboard, so we have to stall the pipeline...
3271 #ifdef DSP_DEBUG_PL2
3275 WriteLog(" --> Stalling pipeline: ");
3276 if (readAffected[pipeline[plPtrRead].opcode][0])
3277 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3278 if (readAffected[pipeline[plPtrRead].opcode][1])
3279 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3283 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3284 #ifdef DSP_DEBUG_PL2
3289 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3290 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3291 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3293 // Shouldn't we be more selective with the register scoreboarding?
3294 // Yes, we should. !!! FIX !!! Kinda [DONE]
3295 #ifndef NEW_SCOREBOARD
3296 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3298 //Hopefully this will fix the dual MOVEQ # problem...
3299 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3302 //Advance PC here??? Yes.
3303 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3306 #ifdef DSP_DEBUG_PL2
3309 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3310 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]);
3311 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]);
3312 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]);
3316 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3318 #ifdef DSP_DEBUG_PL2
3320 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"));
3324 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3329 lastExec = pipeline[plPtrExec].instruction;
3330 //WriteLog("[lastExec = %04X]\n", lastExec);
3332 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3333 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3334 DSPOpcode[pipeline[plPtrExec].opcode]();
3335 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3339 //Let's not, until we do the stalling correctly...
3340 //But, we gotta while we're doing the comparison core...!
3341 //Or do we? cycles--;
3342 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3343 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3344 //to model this clock cycle behavior correctly...
3345 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3346 //don't affect the reads at stage 1...
3347 #ifdef DSP_DEBUG_STALL
3349 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3353 #ifdef DSP_DEBUG_PL2
3356 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3357 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]);
3358 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]);
3359 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]);
3363 // Stage 3: Write back register/memory address
3364 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3366 /*if (pipeline[plPtrWrite].writebackRegister == 3
3367 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3370 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3373 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3375 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3376 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3379 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3380 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3381 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3382 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3384 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3388 #ifndef NEW_SCOREBOARD
3389 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3390 scoreboard[pipeline[plPtrWrite].operand2] = false;
3392 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3393 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3394 if (scoreboard[pipeline[plPtrWrite].operand2])
3395 scoreboard[pipeline[plPtrWrite].operand2]--;
3399 // Push instructions through the pipeline...
3400 plPtrRead = (++plPtrRead) & 0x03;
3401 plPtrExec = (++plPtrExec) & 0x03;
3402 plPtrWrite = (++plPtrWrite) & 0x03;
3411 //#define DSP_DEBUG_PL3
3412 //Let's try a 2 stage pipeline....
3413 void DSPExecP3(int32 cycles)
3415 dsp_releaseTimeSlice_flag = 0;
3418 while (cycles > 0 && DSP_RUNNING)
3420 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3422 #ifdef DSP_DEBUG_PL3
3423 WriteLog("DSPExecP: Pipeline status...\n");
3424 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]);
3425 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]);
3426 WriteLog(" --> Scoreboard: ");
3427 for(int i=0; i<32; i++)
3428 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3431 // Stage 1a: Instruction fetch
3432 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3433 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3434 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3435 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3436 if (pipeline[plPtrRead].opcode == 38)
3437 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3438 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3439 #ifdef DSP_DEBUG_PL3
3440 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3441 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3442 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]);
3443 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]);
3445 // Stage 1b: Read registers
3446 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3447 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3448 // We have a hit in the scoreboard, so we have to stall the pipeline...
3449 #ifdef DSP_DEBUG_PL3
3451 WriteLog(" --> Stalling pipeline: ");
3452 if (readAffected[pipeline[plPtrRead].opcode][0])
3453 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3454 if (readAffected[pipeline[plPtrRead].opcode][1])
3455 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3458 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3459 #ifdef DSP_DEBUG_PL3
3464 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3465 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3466 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3468 // Shouldn't we be more selective with the register scoreboarding?
3469 // Yes, we should. !!! FIX !!! [Kinda DONE]
3470 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3472 //Advance PC here??? Yes.
3473 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3476 #ifdef DSP_DEBUG_PL3
3477 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3478 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]);
3479 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]);
3481 // Stage 2a: Execute
3482 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3484 #ifdef DSP_DEBUG_PL3
3485 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3487 DSPOpcode[pipeline[plPtrExec].opcode]();
3488 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3489 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3494 #ifdef DSP_DEBUG_PL3
3495 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3496 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]);
3497 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]);
3500 // Stage 2b: Write back register
3501 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3503 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3504 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3506 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3507 scoreboard[pipeline[plPtrExec].operand2] = false;
3510 // Push instructions through the pipeline...
3511 plPtrRead = (++plPtrRead) & 0x03;
3512 plPtrExec = (++plPtrExec) & 0x03;
3519 // DSP pipelined opcode handlers
3522 #define PRM pipeline[plPtrExec].reg1
3523 #define PRN pipeline[plPtrExec].reg2
3524 #define PIMM1 pipeline[plPtrExec].operand1
3525 #define PIMM2 pipeline[plPtrExec].operand2
3526 #define PRES pipeline[plPtrExec].result
3527 #define PWBR pipeline[plPtrExec].writebackRegister
3528 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3529 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3530 #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))
3531 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3533 static void DSP_abs(void)
3537 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);
3541 if (_Rn == 0x80000000)
3545 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3546 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3547 CLR_ZN; SET_Z(PRES);
3551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3555 static void DSP_add(void)
3559 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);
3561 uint32 res = PRN + PRM;
3562 SET_ZNC_ADD(PRN, PRM, res);
3566 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);
3570 static void DSP_addc(void)
3574 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);
3576 uint32 res = PRN + PRM + dsp_flag_c;
3577 uint32 carry = dsp_flag_c;
3578 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3579 SET_ZNC_ADD(PRN + carry, PRM, res);
3580 // SET_ZNC_ADD(PRN, PRM + carry, res);
3584 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);
3588 static void DSP_addq(void)
3592 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);
3594 uint32 r1 = dsp_convert_zero[PIMM1];
3595 uint32 res = PRN + r1;
3596 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3600 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3604 static void DSP_addqmod(void)
3606 #ifdef DSP_DIS_ADDQMOD
3608 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);
3610 uint32 r1 = dsp_convert_zero[PIMM1];
3612 uint32 res = r2 + r1;
3613 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3615 SET_ZNC_ADD(r2, r1, res);
3616 #ifdef DSP_DIS_ADDQMOD
3618 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3622 static void DSP_addqt(void)
3624 #ifdef DSP_DIS_ADDQT
3626 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);
3628 PRES = PRN + dsp_convert_zero[PIMM1];
3629 #ifdef DSP_DIS_ADDQT
3631 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3635 static void DSP_and(void)
3639 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);
3645 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);
3649 static void DSP_bclr(void)
3653 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);
3655 PRES = PRN & ~(1 << PIMM1);
3659 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3663 static void DSP_bset(void)
3667 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);
3669 PRES = PRN | (1 << PIMM1);
3673 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3677 static void DSP_btst(void)
3681 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);
3683 dsp_flag_z = (~PRN >> PIMM1) & 1;
3687 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3691 static void DSP_cmp(void)
3695 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);
3697 uint32 res = PRN - PRM;
3698 SET_ZNC_SUB(PRN, PRM, res);
3702 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3706 static void DSP_cmpq(void)
3708 static int32 sqtable[32] =
3709 { 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 };
3712 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);
3714 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3715 uint32 res = PRN - r1;
3716 SET_ZNC_SUB(PRN, r1, res);
3720 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3724 static void DSP_div(void)
3726 uint32 _Rm = PRM, _Rn = PRN;
3730 if (dsp_div_control & 1)
3732 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3733 if (dsp_remain & 0x80000000)
3735 PRES = (((uint64)_Rn) << 16) / _Rm;
3739 dsp_remain = _Rn % _Rm;
3740 if (dsp_remain & 0x80000000)
3749 static void DSP_imacn(void)
3751 #ifdef DSP_DIS_IMACN
3753 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);
3755 int32 res = (int16)PRM * (int16)PRN;
3756 dsp_acc += (int64)res;
3757 //Should we AND the result to fit into 40 bits here???
3759 #ifdef DSP_DIS_IMACN
3761 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));
3765 static void DSP_imult(void)
3767 #ifdef DSP_DIS_IMULT
3769 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);
3771 PRES = (int16)PRN * (int16)PRM;
3773 #ifdef DSP_DIS_IMULT
3775 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);
3779 static void DSP_imultn(void)
3781 #ifdef DSP_DIS_IMULTN
3783 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);
3785 // This is OK, since this multiply won't overflow 32 bits...
3786 int32 res = (int32)((int16)PRN * (int16)PRM);
3787 dsp_acc = (int64)res;
3790 #ifdef DSP_DIS_IMULTN
3792 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));
3796 static void DSP_illegal(void)
3798 #ifdef DSP_DIS_ILLEGAL
3800 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3805 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3806 // can cause trouble because an interrupt can occur *before* the instruction following the
3807 // jump can execute... !!! FIX !!!
3808 // This can probably be solved by judicious coding in the pipeline execution core...
3809 // And should be fixed now...
3810 static void DSP_jr(void)
3813 const char * condition[32] =
3814 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3815 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3816 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3817 "???", "???", "???", "F" };
3819 //How come this is always off by 2???
3820 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);
3822 // KLUDGE: Used by BRANCH_CONDITION macro
3823 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3825 if (BRANCH_CONDITION(PIMM2))
3829 WriteLog("Branched!\n");
3831 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3832 //Account for pipeline effects...
3833 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3834 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3836 // Now that we've branched, we have to make sure that the following instruction
3837 // is executed atomically with this one and then flush the pipeline before setting
3840 // Step 1: Handle writebacks at stage 3 of pipeline
3841 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3843 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3844 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3846 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3847 scoreboard[pipeline[plPtrWrite].operand2] = false;
3849 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3851 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3853 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3854 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3857 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3858 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3859 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3860 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3862 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3866 #ifndef NEW_SCOREBOARD
3867 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3868 scoreboard[pipeline[plPtrWrite].operand2] = false;
3870 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3871 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3872 if (scoreboard[pipeline[plPtrWrite].operand2])
3873 scoreboard[pipeline[plPtrWrite].operand2]--;
3877 // Step 2: Push instruction through pipeline & execute following instruction
3878 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3879 // we effectively handle the final push of the instruction through the
3880 // pipeline when the new PC takes effect (since when we return, the
3881 // pipeline code will be executing the writeback stage. If we reverse
3882 // the execution order of the pipeline stages, this will no longer be
3884 pipeline[plPtrExec] = pipeline[plPtrRead];
3885 //This is BAD. We need to get that next opcode and execute it!
3886 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3887 // remove this crap.
3888 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3890 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3891 pipeline[plPtrExec].opcode = instruction >> 10;
3892 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3893 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3894 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3895 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3896 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3898 dsp_pc += 2; // For DSP_DIS_* accuracy
3899 DSPOpcode[pipeline[plPtrExec].opcode]();
3900 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3901 pipeline[plPtrWrite] = pipeline[plPtrExec];
3903 // Step 3: Flush pipeline & set new PC
3904 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3911 WriteLog("Branch NOT taken.\n");
3917 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3920 static void DSP_jump(void)
3923 const char * condition[32] =
3924 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3925 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3926 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3927 "???", "???", "???", "F" };
3929 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);
3931 // KLUDGE: Used by BRANCH_CONDITION macro
3932 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3934 if (BRANCH_CONDITION(PIMM2))
3938 WriteLog("Branched!\n");
3940 uint32 PCSave = PRM;
3941 // Now that we've branched, we have to make sure that the following instruction
3942 // is executed atomically with this one and then flush the pipeline before setting
3945 // Step 1: Handle writebacks at stage 3 of pipeline
3946 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3948 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3949 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3951 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3952 scoreboard[pipeline[plPtrWrite].operand2] = false;
3954 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3956 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3958 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3959 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3962 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3963 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3964 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3965 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3967 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3971 #ifndef NEW_SCOREBOARD
3972 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3973 scoreboard[pipeline[plPtrWrite].operand2] = false;
3975 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3976 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3977 if (scoreboard[pipeline[plPtrWrite].operand2])
3978 scoreboard[pipeline[plPtrWrite].operand2]--;
3982 // Step 2: Push instruction through pipeline & execute following instruction
3983 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3984 // we effectively handle the final push of the instruction through the
3985 // pipeline when the new PC takes effect (since when we return, the
3986 // pipeline code will be executing the writeback stage. If we reverse
3987 // the execution order of the pipeline stages, this will no longer be
3989 pipeline[plPtrExec] = pipeline[plPtrRead];
3990 //This is BAD. We need to get that next opcode and execute it!
3991 //Also, same problem in JR!
3992 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3993 // remove this crap.
3994 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3996 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3997 pipeline[plPtrExec].opcode = instruction >> 10;
3998 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3999 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4000 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4001 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4002 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4004 dsp_pc += 2; // For DSP_DIS_* accuracy
4005 DSPOpcode[pipeline[plPtrExec].opcode]();
4006 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4007 pipeline[plPtrWrite] = pipeline[plPtrExec];
4009 // Step 3: Flush pipeline & set new PC
4010 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4017 WriteLog("Branch NOT taken.\n");
4025 static void DSP_load(void)
4029 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);
4031 #ifdef DSP_CORRECT_ALIGNMENT
4032 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4034 PRES = DSPReadLong(PRM, DSP);
4038 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4042 static void DSP_loadb(void)
4044 #ifdef DSP_DIS_LOADB
4046 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);
4048 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4049 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4051 PRES = JaguarReadByte(PRM, DSP);
4052 #ifdef DSP_DIS_LOADB
4054 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4058 static void DSP_loadw(void)
4060 #ifdef DSP_DIS_LOADW
4062 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);
4064 #ifdef DSP_CORRECT_ALIGNMENT
4065 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4066 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4068 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4070 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4071 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4073 PRES = JaguarReadWord(PRM, DSP);
4075 #ifdef DSP_DIS_LOADW
4077 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4081 static void DSP_load_r14_i(void)
4083 #ifdef DSP_DIS_LOAD14I
4085 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);
4087 #ifdef DSP_CORRECT_ALIGNMENT
4088 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4090 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4092 #ifdef DSP_DIS_LOAD14I
4094 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4098 static void DSP_load_r14_r(void)
4100 #ifdef DSP_DIS_LOAD14R
4102 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);
4104 #ifdef DSP_CORRECT_ALIGNMENT
4105 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4107 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4109 #ifdef DSP_DIS_LOAD14R
4111 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4115 static void DSP_load_r15_i(void)
4117 #ifdef DSP_DIS_LOAD15I
4119 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);
4121 #ifdef DSP_CORRECT_ALIGNMENT
4122 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4124 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4126 #ifdef DSP_DIS_LOAD15I
4128 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4132 static void DSP_load_r15_r(void)
4134 #ifdef DSP_DIS_LOAD15R
4136 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);
4138 #ifdef DSP_CORRECT_ALIGNMENT
4139 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4141 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4143 #ifdef DSP_DIS_LOAD15R
4145 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4149 static void DSP_mirror(void)
4152 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4156 static void DSP_mmult(void)
4158 int count = dsp_matrix_control&0x0f;
4159 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4163 if (!(dsp_matrix_control & 0x10))
4165 for (int i = 0; i < count; i++)
4169 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4171 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4172 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4179 for (int i = 0; i < count; i++)
4183 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4185 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4186 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4192 PRES = res = (int32)accum;
4194 //NOTE: The flags are set based upon the last add/multiply done...
4198 static void DSP_move(void)
4202 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);
4207 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);
4211 static void DSP_movefa(void)
4213 #ifdef DSP_DIS_MOVEFA
4215 // 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);
4216 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);
4218 // PRES = ALTERNATE_RM;
4219 PRES = dsp_alternate_reg[PIMM1];
4220 #ifdef DSP_DIS_MOVEFA
4222 // 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);
4223 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);
4227 static void DSP_movei(void)
4229 #ifdef DSP_DIS_MOVEI
4231 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);
4233 // // This instruction is followed by 32-bit value in LSW / MSW format...
4234 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4236 #ifdef DSP_DIS_MOVEI
4238 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4242 static void DSP_movepc(void)
4244 #ifdef DSP_DIS_MOVEPC
4246 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);
4248 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4249 // PRES = dsp_pc - 2;
4250 //Account for pipeline effects...
4251 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4252 #ifdef DSP_DIS_MOVEPC
4254 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4258 static void DSP_moveq(void)
4260 #ifdef DSP_DIS_MOVEQ
4262 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);
4265 #ifdef DSP_DIS_MOVEQ
4267 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4271 static void DSP_moveta(void)
4273 #ifdef DSP_DIS_MOVETA
4275 // 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);
4276 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]);
4278 // ALTERNATE_RN = PRM;
4279 dsp_alternate_reg[PIMM2] = PRM;
4281 #ifdef DSP_DIS_MOVETA
4283 // 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);
4284 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]);
4288 static void DSP_mtoi(void)
4290 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4294 static void DSP_mult(void)
4298 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);
4300 PRES = (uint16)PRM * (uint16)PRN;
4304 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);
4308 static void DSP_neg(void)
4312 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);
4315 SET_ZNC_SUB(0, PRN, res);
4319 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4323 static void DSP_nop(void)
4327 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4332 static void DSP_normi(void)
4339 while ((_Rm & 0xffc00000) == 0)
4344 while ((_Rm & 0xff800000) != 0)
4354 static void DSP_not(void)
4358 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);
4364 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4368 static void DSP_or(void)
4372 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);
4378 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);
4382 static void DSP_resmac(void)
4384 #ifdef DSP_DIS_RESMAC
4386 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));
4388 PRES = (uint32)dsp_acc;
4389 #ifdef DSP_DIS_RESMAC
4391 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4395 static void DSP_ror(void)
4399 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);
4401 uint32 r1 = PRM & 0x1F;
4402 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4403 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4407 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);
4411 static void DSP_rorq(void)
4415 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);
4417 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4419 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4421 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4424 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4428 static void DSP_sat16s(void)
4431 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4436 static void DSP_sat32s(void)
4438 int32 r2 = (uint32)PRN;
4439 int32 temp = dsp_acc >> 32;
4440 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4445 static void DSP_sh(void)
4447 int32 sRm = (int32)PRM;
4452 uint32 shift = -sRm;
4457 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4472 dsp_flag_c = _Rn & 0x1;
4485 static void DSP_sha(void)
4487 int32 sRm = (int32)PRM;
4492 uint32 shift = -sRm;
4497 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4512 dsp_flag_c = _Rn & 0x1;
4516 _Rn = ((int32)_Rn) >> 1;
4525 static void DSP_sharq(void)
4527 #ifdef DSP_DIS_SHARQ
4529 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);
4531 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4532 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4534 #ifdef DSP_DIS_SHARQ
4536 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4540 static void DSP_shlq(void)
4544 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);
4546 int32 r1 = 32 - PIMM1;
4547 uint32 res = PRN << r1;
4548 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4552 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4556 static void DSP_shrq(void)
4560 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);
4562 int32 r1 = dsp_convert_zero[PIMM1];
4563 uint32 res = PRN >> r1;
4564 SET_ZN(res); dsp_flag_c = PRN & 1;
4568 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4572 static void DSP_store(void)
4574 #ifdef DSP_DIS_STORE
4576 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);
4578 // DSPWriteLong(PRM, PRN, DSP);
4580 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4581 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4583 pipeline[plPtrExec].address = PRM;
4585 pipeline[plPtrExec].value = PRN;
4586 pipeline[plPtrExec].type = TYPE_DWORD;
4590 static void DSP_storeb(void)
4592 #ifdef DSP_DIS_STOREB
4594 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);
4596 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4597 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4599 // JaguarWriteByte(PRM, PRN, DSP);
4602 pipeline[plPtrExec].address = PRM;
4604 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4606 pipeline[plPtrExec].value = PRN & 0xFF;
4607 pipeline[plPtrExec].type = TYPE_DWORD;
4611 pipeline[plPtrExec].value = PRN;
4612 pipeline[plPtrExec].type = TYPE_BYTE;
4618 static void DSP_storew(void)
4620 #ifdef DSP_DIS_STOREW
4622 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);
4624 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4625 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4627 // JaguarWriteWord(PRM, PRN, DSP);
4630 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4631 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4633 pipeline[plPtrExec].address = PRM;
4636 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4638 pipeline[plPtrExec].value = PRN & 0xFFFF;
4639 pipeline[plPtrExec].type = TYPE_DWORD;
4643 pipeline[plPtrExec].value = PRN;
4644 pipeline[plPtrExec].type = TYPE_WORD;
4649 static void DSP_store_r14_i(void)
4651 #ifdef DSP_DIS_STORE14I
4653 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));
4655 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4657 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4658 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4660 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4662 pipeline[plPtrExec].value = PRN;
4663 pipeline[plPtrExec].type = TYPE_DWORD;
4667 static void DSP_store_r14_r(void)
4669 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4671 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4672 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4674 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4676 pipeline[plPtrExec].value = PRN;
4677 pipeline[plPtrExec].type = TYPE_DWORD;
4681 static void DSP_store_r15_i(void)
4683 #ifdef DSP_DIS_STORE15I
4685 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));
4687 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4689 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4690 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4692 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4694 pipeline[plPtrExec].value = PRN;
4695 pipeline[plPtrExec].type = TYPE_DWORD;
4699 static void DSP_store_r15_r(void)
4701 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4703 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4704 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4706 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4708 pipeline[plPtrExec].value = PRN;
4709 pipeline[plPtrExec].type = TYPE_DWORD;
4713 static void DSP_sub(void)
4717 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);
4719 uint32 res = PRN - PRM;
4720 SET_ZNC_SUB(PRN, PRM, res);
4724 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);
4728 static void DSP_subc(void)
4732 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);
4734 uint32 res = PRN - PRM - dsp_flag_c;
4735 uint32 borrow = dsp_flag_c;
4736 SET_ZNC_SUB(PRN - borrow, PRM, res);
4740 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);
4744 static void DSP_subq(void)
4748 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);
4750 uint32 r1 = dsp_convert_zero[PIMM1];
4751 uint32 res = PRN - r1;
4752 SET_ZNC_SUB(PRN, r1, res);
4756 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4760 static void DSP_subqmod(void)
4762 uint32 r1 = dsp_convert_zero[PIMM1];
4764 uint32 res = r2 - r1;
4765 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4767 SET_ZNC_SUB(r2, r1, res);
4770 static void DSP_subqt(void)
4772 #ifdef DSP_DIS_SUBQT
4774 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);
4776 PRES = PRN - dsp_convert_zero[PIMM1];
4777 #ifdef DSP_DIS_SUBQT
4779 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4783 static void DSP_xor(void)
4787 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);
4793 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);