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...
31 // Seems alignment in loads & stores was off...
32 #define DSP_CORRECT_ALIGNMENT
33 //#define DSP_CORRECT_ALIGNMENT_STORE
36 //#define DSP_DEBUG_IRQ
37 //#define DSP_DEBUG_PL2
38 //#define DSP_DEBUG_STALL
39 //#define DSP_DEBUG_CC
40 #define NEW_SCOREBOARD
42 // Disassembly definitions
49 #define DSP_DIS_ADDQMOD
59 #define DSP_DIS_IMULTN
60 #define DSP_DIS_ILLEGAL
64 #define DSP_DIS_LOAD14I
65 #define DSP_DIS_LOAD14R
66 #define DSP_DIS_LOAD15I
67 #define DSP_DIS_LOAD15R
73 #define DSP_DIS_MOVEFA
74 #define DSP_DIS_MOVEPC // Pipeline only!
75 #define DSP_DIS_MOVETA
81 #define DSP_DIS_RESMAC
88 #define DSP_DIS_STORE14I
89 #define DSP_DIS_STORE15I
90 #define DSP_DIS_STOREB
91 #define DSP_DIS_STOREW
98 bool doDSPDis = false;
99 //bool doDSPDis = true;
134 + load_r15_indexed 284500
136 + store_r15_indexed 47416
140 + load_r14_ri 1229448
143 // Pipeline structures
145 const bool affectsScoreboard[64] =
147 true, true, true, true,
148 true, true, true, true,
149 true, true, true, true,
150 true, false, true, true,
152 true, true, false, true,
153 false, true, true, true,
154 true, true, true, true,
155 true, true, false, false,
157 true, true, true, true,
158 false, true, true, true,
159 true, true, true, true,
160 true, false, false, false,
162 true, false, false, true,
163 false, false, true, true,
164 true, false, true, true,
165 false, false, false, true
171 uint8 opcode, operand1, operand2;
172 uint32 reg1, reg2, areg1, areg2;
174 uint8 writebackRegister;
175 // General memory store...
184 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
185 #ifndef NEW_SCOREBOARD
188 uint8 scoreboard[32];
190 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
191 PipelineStage pipeline[4];
192 bool IMASKCleared = false;
194 // DSP flags (old--have to get rid of this crap)
196 #define CINT0FLAG 0x00200
197 #define CINT1FLAG 0x00400
198 #define CINT2FLAG 0x00800
199 #define CINT3FLAG 0x01000
200 #define CINT4FLAG 0x02000
201 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
202 #define CINT5FLAG 0x20000 /* DSP only */
206 #define ZERO_FLAG 0x00001
207 #define CARRY_FLAG 0x00002
208 #define NEGA_FLAG 0x00004
209 #define IMASK 0x00008
210 #define INT_ENA0 0x00010
211 #define INT_ENA1 0x00020
212 #define INT_ENA2 0x00040
213 #define INT_ENA3 0x00080
214 #define INT_ENA4 0x00100
215 #define INT_CLR0 0x00200
216 #define INT_CLR1 0x00400
217 #define INT_CLR2 0x00800
218 #define INT_CLR3 0x01000
219 #define INT_CLR4 0x02000
220 #define REGPAGE 0x04000
221 #define DMAEN 0x08000
222 #define INT_ENA5 0x10000
223 #define INT_CLR5 0x20000
227 #define DSPGO 0x00001
228 #define CPUINT 0x00002
229 #define DSPINT0 0x00004
230 #define SINGLE_STEP 0x00008
231 #define SINGLE_GO 0x00010
233 #define INT_LAT0 0x00040
234 #define INT_LAT1 0x00080
235 #define INT_LAT2 0x00100
236 #define INT_LAT3 0x00200
237 #define INT_LAT4 0x00400
238 #define BUS_HOG 0x00800
239 #define VERSION 0x0F000
240 #define INT_LAT5 0x10000
242 extern uint32 jaguar_mainRom_crc32;
244 // Is opcode 62 *really* a NOP? Seems like it...
245 static void dsp_opcode_abs(void);
246 static void dsp_opcode_add(void);
247 static void dsp_opcode_addc(void);
248 static void dsp_opcode_addq(void);
249 static void dsp_opcode_addqmod(void);
250 static void dsp_opcode_addqt(void);
251 static void dsp_opcode_and(void);
252 static void dsp_opcode_bclr(void);
253 static void dsp_opcode_bset(void);
254 static void dsp_opcode_btst(void);
255 static void dsp_opcode_cmp(void);
256 static void dsp_opcode_cmpq(void);
257 static void dsp_opcode_div(void);
258 static void dsp_opcode_imacn(void);
259 static void dsp_opcode_imult(void);
260 static void dsp_opcode_imultn(void);
261 static void dsp_opcode_jr(void);
262 static void dsp_opcode_jump(void);
263 static void dsp_opcode_load(void);
264 static void dsp_opcode_loadb(void);
265 static void dsp_opcode_loadw(void);
266 static void dsp_opcode_load_r14_indexed(void);
267 static void dsp_opcode_load_r14_ri(void);
268 static void dsp_opcode_load_r15_indexed(void);
269 static void dsp_opcode_load_r15_ri(void);
270 static void dsp_opcode_mirror(void);
271 static void dsp_opcode_mmult(void);
272 static void dsp_opcode_move(void);
273 static void dsp_opcode_movei(void);
274 static void dsp_opcode_movefa(void);
275 static void dsp_opcode_move_pc(void);
276 static void dsp_opcode_moveq(void);
277 static void dsp_opcode_moveta(void);
278 static void dsp_opcode_mtoi(void);
279 static void dsp_opcode_mult(void);
280 static void dsp_opcode_neg(void);
281 static void dsp_opcode_nop(void);
282 static void dsp_opcode_normi(void);
283 static void dsp_opcode_not(void);
284 static void dsp_opcode_or(void);
285 static void dsp_opcode_resmac(void);
286 static void dsp_opcode_ror(void);
287 static void dsp_opcode_rorq(void);
288 static void dsp_opcode_xor(void);
289 static void dsp_opcode_sat16s(void);
290 static void dsp_opcode_sat32s(void);
291 static void dsp_opcode_sh(void);
292 static void dsp_opcode_sha(void);
293 static void dsp_opcode_sharq(void);
294 static void dsp_opcode_shlq(void);
295 static void dsp_opcode_shrq(void);
296 static void dsp_opcode_store(void);
297 static void dsp_opcode_storeb(void);
298 static void dsp_opcode_storew(void);
299 static void dsp_opcode_store_r14_indexed(void);
300 static void dsp_opcode_store_r14_ri(void);
301 static void dsp_opcode_store_r15_indexed(void);
302 static void dsp_opcode_store_r15_ri(void);
303 static void dsp_opcode_sub(void);
304 static void dsp_opcode_subc(void);
305 static void dsp_opcode_subq(void);
306 static void dsp_opcode_subqmod(void);
307 static void dsp_opcode_subqt(void);
309 uint8 dsp_opcode_cycles[64] =
311 3, 3, 3, 3, 3, 3, 3, 3,
312 3, 3, 3, 3, 3, 3, 3, 3,
313 3, 3, 1, 3, 1, 18, 3, 3,
314 3, 3, 3, 3, 3, 3, 3, 3,
315 3, 3, 2, 2, 2, 2, 3, 4,
316 5, 4, 5, 6, 6, 1, 1, 1,
317 1, 2, 2, 2, 1, 1, 9, 3,
318 3, 1, 6, 6, 2, 2, 3, 3
320 //Here's a QnD kludge...
321 //This is wrong, wrong, WRONG, but it seems to work for the time being...
322 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
323 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
324 /*uint8 dsp_opcode_cycles[64] =
326 1, 1, 1, 1, 1, 1, 1, 1,
327 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 9, 1, 1,
329 1, 1, 1, 1, 1, 1, 1, 1,
330 1, 1, 1, 1, 1, 1, 1, 2,
331 2, 2, 2, 3, 3, 1, 1, 1,
332 1, 1, 1, 1, 1, 1, 4, 1,
333 1, 1, 3, 3, 1, 1, 1, 1
336 void (* dsp_opcode[64])() =
338 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
339 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
340 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
341 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
342 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
343 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
344 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
345 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
346 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
347 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
348 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
349 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
350 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
351 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
352 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
353 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
356 uint32 dsp_opcode_use[65];
358 const char * dsp_opcode_str[65]=
360 "add", "addc", "addq", "addqt",
361 "sub", "subc", "subq", "subqt",
362 "neg", "and", "or", "xor",
363 "not", "btst", "bset", "bclr",
364 "mult", "imult", "imultn", "resmac",
365 "imacn", "div", "abs", "sh",
366 "shlq", "shrq", "sha", "sharq",
367 "ror", "rorq", "cmp", "cmpq",
368 "subqmod", "sat16s", "move", "moveq",
369 "moveta", "movefa", "movei", "loadb",
370 "loadw", "load", "sat32s", "load_r14_indexed",
371 "load_r15_indexed", "storeb", "storew", "store",
372 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
373 "jump", "jr", "mmult", "mtoi",
374 "normi", "nop", "load_r14_ri", "load_r15_ri",
375 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
380 static uint64 dsp_acc; // 40 bit register, NOT 32!
381 static uint32 dsp_remain;
382 static uint32 dsp_modulo;
383 static uint32 dsp_flags;
384 static uint32 dsp_matrix_control;
385 static uint32 dsp_pointer_to_matrix;
386 static uint32 dsp_data_organization;
388 static uint32 dsp_div_control;
389 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
390 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
391 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
393 static uint32 dsp_opcode_first_parameter;
394 static uint32 dsp_opcode_second_parameter;
396 #define DSP_RUNNING (dsp_control & 0x01)
398 #define RM dsp_reg[dsp_opcode_first_parameter]
399 #define RN dsp_reg[dsp_opcode_second_parameter]
400 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
401 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
402 #define IMM_1 dsp_opcode_first_parameter
403 #define IMM_2 dsp_opcode_second_parameter
405 #define CLR_Z (dsp_flag_z = 0)
406 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
407 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
408 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
409 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
410 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
411 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
412 #define SET_ZN(r) SET_N(r); SET_Z(r)
413 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
414 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
416 uint32 dsp_convert_zero[32] = {
417 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
418 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
420 uint8 dsp_branch_condition_table[32 * 8];
421 static uint16 mirror_table[65536];
422 static uint8 dsp_ram_8[0x2000];
424 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
426 static uint32 dsp_in_exec = 0;
427 static uint32 dsp_releaseTimeSlice_flag = 0;
432 // Comparison core vars (used only for core comparison! :-)
433 static uint64 count = 0;
434 static uint8 ram1[0x2000], ram2[0x2000];
435 static uint32 regs1[64], regs2[64];
436 static uint32 ctrl1[14], ctrl2[14];
439 // Private function prototypes
441 void DSPDumpRegisters(void);
442 void DSPDumpDisassembly(void);
443 void FlushDSPPipeline(void);
446 void dsp_reset_stats(void)
448 for(int i=0; i<65; i++)
449 dsp_opcode_use[i] = 0;
452 void DSPReleaseTimeslice(void)
454 //This does absolutely nothing!!! !!! FIX !!!
455 dsp_releaseTimeSlice_flag = 1;
458 void dsp_build_branch_condition_table(void)
460 // Fill in the mirror table
461 for(int i=0; i<65536; i++)
463 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
464 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
465 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
466 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
467 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
468 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
469 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
470 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
473 // Fill in the condition table
474 for(int i=0; i<8; i++)
476 for(int j=0; j<32; j++)
480 if ((j & 1) && (i & ZERO_FLAG))
483 if ((j & 2) && (!(i & ZERO_FLAG)))
486 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
489 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
492 dsp_branch_condition_table[i * 32 + j] = result;
497 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
499 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
500 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
502 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
505 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
507 if (offset==0xF1CFE0)
510 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
511 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
513 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
515 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
517 if ((offset&0x03)==0)
520 if ((offset&0x03)==1)
521 return((data>>16)&0xff);
523 if ((offset&0x03)==2)
524 return((data>>8)&0xff);
526 if ((offset&0x03)==3)
530 return JaguarReadByte(offset, who);
533 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
535 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
536 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
538 offset &= 0xFFFFFFFE;
540 /* if (jaguar_mainRom_crc32==0xa74a97cd)
542 if (offset==0xF1A114) return(0x0000);
543 if (offset==0xF1A116) return(0x0000);
544 if (offset==0xF1B000) return(0x1234);
545 if (offset==0xF1B002) return(0x5678);
548 if (jaguar_mainRom_crc32==0x7ae20823)
550 if (offset==0xF1B9D8) return(0x0000);
551 if (offset==0xF1B9Da) return(0x0000);
552 if (offset==0xF1B2C0) return(0x0000);
553 if (offset==0xF1B2C2) return(0x0000);
556 // pour permettre � wolfenstein 3d de tourner sans le dsp
557 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
561 // pour permettre � nba jam de tourner sans le dsp
562 /* if (jaguar_mainRom_crc32==0x4faddb18)
564 if (offset==0xf1b2c0) return(0);
565 if (offset==0xf1b2c2) return(0);
566 if (offset==0xf1b240) return(0);
567 if (offset==0xf1b242) return(0);
568 if (offset==0xF1B340) return(0);
569 if (offset==0xF1B342) return(0);
570 if (offset==0xF1BAD8) return(0);
571 if (offset==0xF1BADA) return(0);
572 if (offset==0xF1B040) return(0);
573 if (offset==0xF1B042) return(0);
574 if (offset==0xF1B0C0) return(0);
575 if (offset==0xF1B0C2) return(0);
576 if (offset==0xF1B140) return(0);
577 if (offset==0xF1B142) return(0);
578 if (offset==0xF1B1C0) return(0);
579 if (offset==0xF1B1C2) return(0);
582 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
584 offset -= DSP_WORK_RAM_BASE;
585 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
587 return GET16(dsp_ram_8, offset);
589 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
591 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
594 return data & 0xFFFF;
599 return JaguarReadWord(offset, who);
602 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
604 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
605 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
608 offset &= 0xFFFFFFFC;
609 /*if (offset == 0xF1BCF4)
611 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));
612 DSPDumpDisassembly();
614 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
616 offset -= DSP_WORK_RAM_BASE;
617 return GET32(dsp_ram_8, offset);
619 //NOTE: Didn't return DSP_ACCUM!!!
620 //Mebbe it's not 'spose to! Yes, it is!
621 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
626 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
627 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
628 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
630 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
631 return dsp_flags & 0xFFFFC1FF;
632 case 0x04: return dsp_matrix_control;
633 case 0x08: return dsp_pointer_to_matrix;
634 case 0x0C: return dsp_data_organization;
635 case 0x10: return dsp_pc;
636 case 0x14: return dsp_control;
637 case 0x18: return dsp_modulo;
638 case 0x1C: return dsp_remain;
640 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
642 // unaligned long read-- !!! FIX !!!
646 return JaguarReadLong(offset, who);
649 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
651 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
652 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
654 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
656 offset -= DSP_WORK_RAM_BASE;
657 dsp_ram_8[offset] = data;
658 //This is rather stupid! !!! FIX !!!
659 /* if (dsp_in_exec == 0)
661 m68k_end_timeslice();
662 dsp_releaseTimeslice();
666 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
668 uint32 reg = offset & 0x1C;
669 int bytenum = offset & 0x03;
671 if ((reg >= 0x1C) && (reg <= 0x1F))
672 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
675 //This looks funky. !!! FIX !!!
676 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
677 bytenum = 3 - bytenum; // convention motorola !!!
678 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
679 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
683 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
684 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
685 JaguarWriteByte(offset, data, who);
688 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
690 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
691 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
692 offset &= 0xFFFFFFFE;
693 /*if (offset == 0xF1BCF4)
695 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
697 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
698 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
700 /*if (offset == 0xF1B2F4)
702 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
704 offset -= DSP_WORK_RAM_BASE;
705 dsp_ram_8[offset] = data >> 8;
706 dsp_ram_8[offset+1] = data & 0xFF;
707 //This is rather stupid! !!! FIX !!!
708 /* if (dsp_in_exec == 0)
710 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
711 m68k_end_timeslice();
712 dsp_releaseTimeslice();
716 SET16(ram1, offset, data),
717 SET16(ram2, offset, data);
722 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
724 if ((offset & 0x1C) == 0x1C)
727 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
729 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
733 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
735 old_data = (old_data&0xffff0000)|(data&0xffff);
737 old_data = (old_data&0xffff)|((data&0xffff)<<16);
738 DSPWriteLong(offset & 0xffffffc, old_data, who);
743 JaguarWriteWord(offset, data, who);
746 //bool badWrite = false;
747 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
749 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
750 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
752 offset &= 0xFFFFFFFC;
753 /*if (offset == 0xF1BCF4)
755 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
757 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
758 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
760 /*if (offset == 0xF1BE2C)
762 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
764 offset -= DSP_WORK_RAM_BASE;
765 SET32(dsp_ram_8, offset, data);
768 SET32(ram1, offset, data),
769 SET32(ram2, offset, data);
774 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
782 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
784 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
785 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
787 dsp_flag_z = dsp_flags & 0x01;
788 dsp_flag_c = (dsp_flags >> 1) & 0x01;
789 dsp_flag_n = (dsp_flags >> 2) & 0x01;
790 DSPUpdateRegisterBanks();
791 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
792 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
794 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
795 // It can be timed to anything really, anything that writes to L/RTXD at a regular
796 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
797 // interrupt, so that's what we check for here. Just know that this approach
798 // can be easily fooled!
799 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
800 if (data & INT_ENA1) // I2S interrupt
802 int freq = GetCalculatedFrequency();
803 //This happens too often to be useful...
804 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
805 DACSetNewFrequency(freq);
807 else if (data & INT_ENA2) // TIMER 0 interrupt
809 int freq = JERRYGetPIT1Frequency();
810 //This happens too often to be useful...
811 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
812 DACSetNewFrequency(freq);
815 /* if (IMASKCleared) // If IMASK was cleared,
818 WriteLog("DSP: Finished interrupt.\n");
820 DSPHandleIRQs(); // see if any other interrupts need servicing!
825 if (/*4-8, 16*/data & 0x101F0)
826 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
827 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
828 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
829 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
830 /*if (data & 0x00020) // CD BIOS DSP code...
832 //001AC1BA: movea.l #$1AC200, A0
833 //001AC1C0: move.l #$1AC68C, D0
836 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
837 uint32 j = 0xF1B97C;//0x1AC200;
838 while (j <= 0xF1BE08)//0x1AC68C)
841 j += dasmjag(JAGUAR_DSP, buffer, j);
842 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
843 WriteLog("\t%08X: %s\n", oldj, buffer);
850 dsp_matrix_control = data;
853 // According to JTRM, only lines 2-11 are addressable, the rest being
854 // hardwired to $F1Bxxx.
855 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
858 dsp_data_organization = data;
863 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
868 ctrl1[0] = ctrl2[0] = data;
875 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
877 bool wasRunning = DSP_RUNNING;
878 // uint32 dsp_was_running = DSP_RUNNING;
879 // Check for DSP -> CPU interrupt
883 WriteLog("DSP: DSP -> CPU interrupt\n");
886 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
887 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
888 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
890 JERRYSetPendingIRQ(IRQ2_DSP);
891 DSPReleaseTimeslice();
892 m68k_set_irq(2); // Set 68000 IPL 2...
896 // Check for CPU -> DSP interrupt
900 WriteLog("DSP: CPU -> DSP interrupt\n");
902 m68k_end_timeslice();
903 DSPReleaseTimeslice();
904 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
908 if (data & SINGLE_STEP)
910 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
913 // Protect writes to VERSION and the interrupt latches...
914 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
915 dsp_control = (dsp_control & mask) | (data & ~mask);
919 ctrl1[8] = ctrl2[8] = dsp_control;
923 // if dsp wasn't running but is now running
924 // execute a few cycles
925 //This is just plain wrong, wrong, WRONG!
926 #ifndef DSP_SINGLE_STEPPING
927 /* if (!dsp_was_running && DSP_RUNNING)
932 //This is WRONG! !!! FIX !!!
933 if (dsp_control & 0x18)
938 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
940 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
943 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
944 // !!! FIX !!! [DONE]
948 m68k_end_timeslice();
950 DSPReleaseTimeslice();
954 //DSPDumpDisassembly();
962 dsp_div_control = data;
964 // default: // unaligned long read
970 //We don't have to break this up like this! We CAN do 32 bit writes!
971 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
972 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
973 //if (offset > 0xF1FFFF)
975 JaguarWriteLong(offset, data, who);
979 // Update the DSP register file pointers depending on REGPAGE bit
981 void DSPUpdateRegisterBanks(void)
983 int bank = (dsp_flags & REGPAGE);
985 if (dsp_flags & IMASK)
986 bank = 0; // IMASK forces main bank to be bank 0
989 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
991 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
995 // Check for and handle any asserted DSP IRQs
997 void DSPHandleIRQs(void)
999 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1002 // Get the active interrupt bits (latches) & interrupt mask (enables)
1003 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1004 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1006 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1009 if (!bits) // Bail if nothing is enabled
1012 int which = 0; // Determine which interrupt
1026 #ifdef DSP_DEBUG_IRQ
1027 WriteLog("DSP: Generating interrupt #%i...", which);
1030 //if (which == 0) doDSPDis = true;
1032 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1033 // directly into the pipeline, it has the side effect of ensuring that the
1034 // instruction interrupted also gets to do its writeback. We simulate that
1036 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1038 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1039 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1041 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1042 scoreboard[pipeline[plPtrWrite].operand2] = false;
1044 //This should be execute (or should it?--not sure now!)
1045 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1046 //and what just executed is now in the Write position...). So why didn't it do the
1047 //writeback into register 0?
1048 #ifdef DSP_DEBUG_IRQ
1049 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1050 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]);
1051 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]);
1052 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]);
1054 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1056 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1058 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1059 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1062 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1063 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1064 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1065 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1067 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1071 #ifndef NEW_SCOREBOARD
1072 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1073 scoreboard[pipeline[plPtrWrite].operand2] = false;
1075 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1076 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1077 if (scoreboard[pipeline[plPtrWrite].operand2])
1078 scoreboard[pipeline[plPtrWrite].operand2]--;
1085 ctrl2[4] = dsp_flags;
1088 DSPUpdateRegisterBanks();
1089 #ifdef DSP_DEBUG_IRQ
1090 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1091 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]);
1094 // subqt #4,r31 ; pre-decrement stack pointer
1095 // move pc,r30 ; address of interrupted code
1096 // store r30,(r31) ; store return address
1103 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1104 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1105 //It missed the place that it was supposed to come back to, so this is WRONG!
1107 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1109 // R -> baz (<- PC points here)
1110 // E -> bar (when it should point here!)
1113 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1114 // which means (assuming they're all 2 bytes long) that the code below will come back on
1115 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1116 // instruction stream...
1118 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1119 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1122 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1126 // movei #service_address,r30 ; pointer to ISR entry
1127 // jump (r30) ; jump to ISR
1129 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1132 ctrl2[0] = regs2[30] = dsp_pc;
1139 // Non-pipelined version...
1141 void DSPHandleIRQsNP(void)
1145 memcpy(dsp_ram_8, ram1, 0x2000);
1146 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1147 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1150 dsp_remain = ctrl1[2];
1151 dsp_modulo = ctrl1[3];
1152 dsp_flags = ctrl1[4];
1153 dsp_matrix_control = ctrl1[5];
1154 dsp_pointer_to_matrix = ctrl1[6];
1155 dsp_data_organization = ctrl1[7];
1156 dsp_control = ctrl1[8];
1157 dsp_div_control = ctrl1[9];
1158 IMASKCleared = ctrl1[10];
1159 dsp_flag_z = ctrl1[11];
1160 dsp_flag_n = ctrl1[12];
1161 dsp_flag_c = ctrl1[13];
1162 DSPUpdateRegisterBanks();
1165 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1168 // Get the active interrupt bits (latches) & interrupt mask (enables)
1169 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1170 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1172 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1175 if (!bits) // Bail if nothing is enabled
1178 int which = 0; // Determine which interrupt
1192 #ifdef DSP_DEBUG_IRQ
1193 WriteLog("DSP: Generating interrupt #%i...", which);
1199 ctrl1[4] = dsp_flags;
1202 DSPUpdateRegisterBanks();
1203 #ifdef DSP_DEBUG_IRQ
1204 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1207 // subqt #4,r31 ; pre-decrement stack pointer
1208 // move pc,r30 ; address of interrupted code
1209 // store r30,(r31) ; store return address
1216 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1219 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1223 // movei #service_address,r30 ; pointer to ISR entry
1224 // jump (r30) ; jump to ISR
1226 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1229 ctrl1[0] = regs1[30] = dsp_pc;
1235 // Set the specified DSP IRQ line to a given state
1237 void DSPSetIRQLine(int irqline, int state)
1239 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1240 uint32 mask = INT_LAT0 << irqline;
1241 dsp_control &= ~mask; // Clear the latch bit
1244 ctrl1[8] = ctrl2[8] = dsp_control;
1250 dsp_control |= mask; // Set the latch bit
1254 ctrl1[8] = ctrl2[8] = dsp_control;
1260 // Not sure if this is correct behavior, but according to JTRM,
1261 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1262 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1263 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1268 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1269 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1270 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1272 dsp_build_branch_condition_table();
1278 dsp_pc = 0x00F1B000;
1279 dsp_acc = 0x00000000;
1280 dsp_remain = 0x00000000;
1281 dsp_modulo = 0xFFFFFFFF;
1282 dsp_flags = 0x00040000;
1283 dsp_matrix_control = 0x00000000;
1284 dsp_pointer_to_matrix = 0x00000000;
1285 dsp_data_organization = 0xFFFFFFFF;
1286 dsp_control = 0x00002000; // Report DSP version 2
1287 dsp_div_control = 0x00000000;
1290 dsp_reg = dsp_reg_bank_0;
1291 dsp_alternate_reg = dsp_reg_bank_1;
1293 for(int i=0; i<32; i++)
1294 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1297 IMASKCleared = false;
1300 memset(dsp_ram_8, 0xFF, 0x2000);
1303 void DSPDumpDisassembly(void)
1307 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1308 uint32 j = 0xF1B000;
1310 while (j <= 0xF1CFFF)
1313 j += dasmjag(JAGUAR_DSP, buffer, j);
1314 WriteLog("\t%08X: %s\n", oldj, buffer);
1318 void DSPDumpRegisters(void)
1320 //Shoud add modulus, etc to dump here...
1321 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1322 WriteLog("\nRegisters bank 0\n");
1324 for(int j=0; j<8; j++)
1326 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1327 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1328 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1329 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1330 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1333 WriteLog("Registers bank 1\n");
1335 for(int j=0; j<8; j++)
1337 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1338 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1339 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1340 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1341 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1348 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1349 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1351 // get the active interrupt bits
1352 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1353 // get the interrupt mask
1354 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1356 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1357 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1358 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1359 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1360 WriteLog("\nRegisters bank 0\n");
1362 for(int j=0; j<8; j++)
1364 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1365 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1366 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1367 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1368 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1371 WriteLog("\nRegisters bank 1\n");
1375 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1376 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1377 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1378 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1379 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1383 static char buffer[512];
1384 j = DSP_WORK_RAM_BASE;
1386 while (j <= 0xF1BFFF)
1389 j += dasmjag(JAGUAR_DSP, buffer, j);
1390 WriteLog("\t%08X: %s\n", oldj, buffer);
1393 WriteLog("DSP opcodes use:\n");
1397 if (dsp_opcode_use[i])
1398 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1401 // memory_free(dsp_ram_8);
1402 // memory_free(dsp_reg_bank_0);
1403 // memory_free(dsp_reg_bank_1);
1404 // if (dsp_branch_condition_table)
1405 // free(dsp_branch_condition_table);
1407 // if (mirror_table)
1408 // free(mirror_table);
1414 // DSP comparison core...
1417 static uint16 lastExec;
1418 void DSPExecComp(int32 cycles)
1420 while (cycles > 0 && DSP_RUNNING)
1422 // Load up vars for non-pipelined core
1423 memcpy(dsp_ram_8, ram1, 0x2000);
1424 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1425 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1428 dsp_remain = ctrl1[2];
1429 dsp_modulo = ctrl1[3];
1430 dsp_flags = ctrl1[4];
1431 dsp_matrix_control = ctrl1[5];
1432 dsp_pointer_to_matrix = ctrl1[6];
1433 dsp_data_organization = ctrl1[7];
1434 dsp_control = ctrl1[8];
1435 dsp_div_control = ctrl1[9];
1436 IMASKCleared = ctrl1[10];
1437 dsp_flag_z = ctrl1[11];
1438 dsp_flag_n = ctrl1[12];
1439 dsp_flag_c = ctrl1[13];
1440 DSPUpdateRegisterBanks();
1442 // Decrement cycles based on non-pipelined core...
1443 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1444 cycles -= dsp_opcode_cycles[instr1 >> 10];
1446 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1447 DSPExec(1); // Do *one* instruction
1450 memcpy(ram1, dsp_ram_8, 0x2000);
1451 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1452 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1455 ctrl1[2] = dsp_remain;
1456 ctrl1[3] = dsp_modulo;
1457 ctrl1[4] = dsp_flags;
1458 ctrl1[5] = dsp_matrix_control;
1459 ctrl1[6] = dsp_pointer_to_matrix;
1460 ctrl1[7] = dsp_data_organization;
1461 ctrl1[8] = dsp_control;
1462 ctrl1[9] = dsp_div_control;
1463 ctrl1[10] = IMASKCleared;
1464 ctrl1[11] = dsp_flag_z;
1465 ctrl1[12] = dsp_flag_n;
1466 ctrl1[13] = dsp_flag_c;
1468 // Load up vars for pipelined core
1469 memcpy(dsp_ram_8, ram2, 0x2000);
1470 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1471 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1474 dsp_remain = ctrl2[2];
1475 dsp_modulo = ctrl2[3];
1476 dsp_flags = ctrl2[4];
1477 dsp_matrix_control = ctrl2[5];
1478 dsp_pointer_to_matrix = ctrl2[6];
1479 dsp_data_organization = ctrl2[7];
1480 dsp_control = ctrl2[8];
1481 dsp_div_control = ctrl2[9];
1482 IMASKCleared = ctrl2[10];
1483 dsp_flag_z = ctrl2[11];
1484 dsp_flag_n = ctrl2[12];
1485 dsp_flag_c = ctrl2[13];
1486 DSPUpdateRegisterBanks();
1488 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1489 DSPExecP2(1); // Do *one* instruction
1492 memcpy(ram2, dsp_ram_8, 0x2000);
1493 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1494 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1497 ctrl2[2] = dsp_remain;
1498 ctrl2[3] = dsp_modulo;
1499 ctrl2[4] = dsp_flags;
1500 ctrl2[5] = dsp_matrix_control;
1501 ctrl2[6] = dsp_pointer_to_matrix;
1502 ctrl2[7] = dsp_data_organization;
1503 ctrl2[8] = dsp_control;
1504 ctrl2[9] = dsp_div_control;
1505 ctrl2[10] = IMASKCleared;
1506 ctrl2[11] = dsp_flag_z;
1507 ctrl2[12] = dsp_flag_n;
1508 ctrl2[13] = dsp_flag_c;
1510 if (instr1 != lastExec)
1512 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1514 // 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));
1515 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1516 // if (ctrl1[0] < ppc) // P ran ahead of NP
1517 //How to test this crap???
1520 DSPExecP2(1); // Do one more instruction
1523 memcpy(ram2, dsp_ram_8, 0x2000);
1524 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1525 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1528 ctrl2[2] = dsp_remain;
1529 ctrl2[3] = dsp_modulo;
1530 ctrl2[4] = dsp_flags;
1531 ctrl2[5] = dsp_matrix_control;
1532 ctrl2[6] = dsp_pointer_to_matrix;
1533 ctrl2[7] = dsp_data_organization;
1534 ctrl2[8] = dsp_control;
1535 ctrl2[9] = dsp_div_control;
1536 ctrl2[10] = IMASKCleared;
1537 ctrl2[11] = dsp_flag_z;
1538 ctrl2[12] = dsp_flag_n;
1539 ctrl2[13] = dsp_flag_c;
1541 // else // NP ran ahead of P
1542 if (instr1 != lastExec) // Must be the other way...
1545 // Load up vars for non-pipelined core
1546 memcpy(dsp_ram_8, ram1, 0x2000);
1547 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1548 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1551 dsp_remain = ctrl1[2];
1552 dsp_modulo = ctrl1[3];
1553 dsp_flags = ctrl1[4];
1554 dsp_matrix_control = ctrl1[5];
1555 dsp_pointer_to_matrix = ctrl1[6];
1556 dsp_data_organization = ctrl1[7];
1557 dsp_control = ctrl1[8];
1558 dsp_div_control = ctrl1[9];
1559 IMASKCleared = ctrl1[10];
1560 dsp_flag_z = ctrl1[11];
1561 dsp_flag_n = ctrl1[12];
1562 dsp_flag_c = ctrl1[13];
1563 DSPUpdateRegisterBanks();
1565 for(int k=0; k<2; k++)
1567 // Decrement cycles based on non-pipelined core...
1568 instr1 = DSPReadWord(dsp_pc, DSP);
1569 cycles -= dsp_opcode_cycles[instr1 >> 10];
1571 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1572 DSPExec(1); // Do *one* instruction
1576 memcpy(ram1, dsp_ram_8, 0x2000);
1577 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1578 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1581 ctrl1[2] = dsp_remain;
1582 ctrl1[3] = dsp_modulo;
1583 ctrl1[4] = dsp_flags;
1584 ctrl1[5] = dsp_matrix_control;
1585 ctrl1[6] = dsp_pointer_to_matrix;
1586 ctrl1[7] = dsp_data_organization;
1587 ctrl1[8] = dsp_control;
1588 ctrl1[9] = dsp_div_control;
1589 ctrl1[10] = IMASKCleared;
1590 ctrl1[11] = dsp_flag_z;
1591 ctrl1[12] = dsp_flag_n;
1592 ctrl1[13] = dsp_flag_c;
1596 if (instr1 != lastExec)
1598 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1600 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1601 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1614 // DSP execution core
1616 //static bool R20Set = false, tripwire = false;
1617 //static uint32 pcQueue[32], ptrPCQ = 0;
1618 void DSPExec(int32 cycles)
1620 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1621 dsp_check_if_i2s_interrupt_needed();*/
1623 #ifdef DSP_SINGLE_STEPPING
1624 if (dsp_control & 0x18)
1627 dsp_control &= ~0x10;
1630 //There is *no* good reason to do this here!
1632 dsp_releaseTimeSlice_flag = 0;
1635 while (cycles > 0 && DSP_RUNNING)
1637 /*extern uint32 totalFrames;
1638 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1639 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1640 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1642 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1645 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1647 if (dsp_pc == 0xF1B092)
1648 doDSPDis = false;//*/
1649 /*if (dsp_pc == 0xF1B140)
1650 doDSPDis = true;//*/
1652 if (IMASKCleared) // If IMASK was cleared,
1654 #ifdef DSP_DEBUG_IRQ
1655 WriteLog("DSP: Finished interrupt.\n");
1657 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1658 IMASKCleared = false;
1663 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1664 for(int i=0; i<80; i+=4)
1665 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1668 /*if (dsp_pc == 0xF1B55E)
1670 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1672 /*if (dsp_pc == 0xF1B7D2) // Start here???
1674 pcQueue[ptrPCQ++] = dsp_pc;
1676 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1677 uint32 index = opcode >> 10;
1678 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1679 dsp_opcode_second_parameter = opcode & 0x1F;
1681 dsp_opcode[index]();
1682 dsp_opcode_use[index]++;
1683 cycles -= dsp_opcode_cycles[index];
1684 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1686 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1689 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1691 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1693 DSPDumpDisassembly();
1696 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1699 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1702 WriteLog("\nBacktrace:\n");
1703 for(int i=0; i<32; i++)
1705 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1706 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1716 // DSP opcode handlers
1719 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1720 // can cause trouble because an interrupt can occur *before* the instruction following the
1721 // jump can execute... !!! FIX !!!
1722 static void dsp_opcode_jump(void)
1725 const char * condition[32] =
1726 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1727 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1728 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1729 "???", "???", "???", "F" };
1731 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);
1734 /* dsp_flag_c=dsp_flag_c?1:0;
1735 dsp_flag_z=dsp_flag_z?1:0;
1736 dsp_flag_n=dsp_flag_n?1:0;*/
1737 // KLUDGE: Used by BRANCH_CONDITION
1738 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1740 if (BRANCH_CONDITION(IMM_2))
1744 WriteLog("Branched!\n");
1746 uint32 delayed_pc = RM;
1748 dsp_pc = delayed_pc;
1753 WriteLog("Branch NOT taken.\n");
1757 static void dsp_opcode_jr(void)
1760 const char * condition[32] =
1761 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1762 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1763 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1764 "???", "???", "???", "F" };
1766 WriteLog("%06X: 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);
1769 /* dsp_flag_c=dsp_flag_c?1:0;
1770 dsp_flag_z=dsp_flag_z?1:0;
1771 dsp_flag_n=dsp_flag_n?1:0;*/
1772 // KLUDGE: Used by BRANCH_CONDITION
1773 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1775 if (BRANCH_CONDITION(IMM_2))
1779 WriteLog("Branched!\n");
1781 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1782 int32 delayed_pc = dsp_pc + (offset * 2);
1784 dsp_pc = delayed_pc;
1789 WriteLog("Branch NOT taken.\n");
1793 static void dsp_opcode_add(void)
1797 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);
1799 uint32 res = RN + RM;
1800 SET_ZNC_ADD(RN, RM, res);
1804 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);
1808 static void dsp_opcode_addc(void)
1812 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);
1814 uint32 res = RN + RM + dsp_flag_c;
1815 uint32 carry = dsp_flag_c;
1816 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1817 SET_ZNC_ADD(RN + carry, RM, res);
1818 // SET_ZNC_ADD(RN, RM + carry, res);
1822 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);
1826 static void dsp_opcode_addq(void)
1830 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);
1832 uint32 r1 = dsp_convert_zero[IMM_1];
1833 uint32 res = RN + r1;
1834 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1838 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1842 static void dsp_opcode_sub(void)
1846 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);
1848 uint32 res = RN - RM;
1849 SET_ZNC_SUB(RN, RM, res);
1853 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);
1857 static void dsp_opcode_subc(void)
1861 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);
1863 uint32 res = RN - RM - dsp_flag_c;
1864 uint32 borrow = dsp_flag_c;
1865 SET_ZNC_SUB(RN - borrow, RM, res);
1869 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);
1873 static void dsp_opcode_subq(void)
1877 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);
1879 uint32 r1 = dsp_convert_zero[IMM_1];
1880 uint32 res = RN - r1;
1881 SET_ZNC_SUB(RN, r1, res);
1885 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1889 static void dsp_opcode_cmp(void)
1893 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);
1895 uint32 res = RN - RM;
1896 SET_ZNC_SUB(RN, RM, res);
1899 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1903 static void dsp_opcode_cmpq(void)
1905 static int32 sqtable[32] =
1906 { 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 };
1909 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);
1911 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1912 uint32 res = RN - r1;
1913 SET_ZNC_SUB(RN, r1, res);
1916 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1920 static void dsp_opcode_and(void)
1924 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);
1930 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1934 static void dsp_opcode_or(void)
1938 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);
1944 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);
1948 static void dsp_opcode_xor(void)
1952 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);
1958 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);
1962 static void dsp_opcode_not(void)
1966 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);
1972 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1976 static void dsp_opcode_move_pc(void)
1981 static void dsp_opcode_store_r14_indexed(void)
1983 #ifdef DSP_DIS_STORE14I
1985 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));
1987 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1988 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1990 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1994 static void dsp_opcode_store_r15_indexed(void)
1996 #ifdef DSP_DIS_STORE15I
1998 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));
2000 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2001 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2003 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2007 static void dsp_opcode_load_r14_ri(void)
2009 #ifdef DSP_DIS_LOAD14R
2011 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);
2013 #ifdef DSP_CORRECT_ALIGNMENT
2014 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2016 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2018 #ifdef DSP_DIS_LOAD14R
2020 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2024 static void dsp_opcode_load_r15_ri(void)
2026 #ifdef DSP_DIS_LOAD15R
2028 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);
2030 #ifdef DSP_CORRECT_ALIGNMENT
2031 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2033 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2035 #ifdef DSP_DIS_LOAD15R
2037 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2041 static void dsp_opcode_store_r14_ri(void)
2043 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2046 static void dsp_opcode_store_r15_ri(void)
2048 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2051 static void dsp_opcode_nop(void)
2055 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2059 static void dsp_opcode_storeb(void)
2061 #ifdef DSP_DIS_STOREB
2063 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);
2065 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2066 DSPWriteLong(RM, RN & 0xFF, DSP);
2068 JaguarWriteByte(RM, RN, DSP);
2071 static void dsp_opcode_storew(void)
2073 #ifdef DSP_DIS_STOREW
2075 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);
2077 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2078 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2079 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2081 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2083 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2084 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2086 JaguarWriteWord(RM, RN, DSP);
2090 static void dsp_opcode_store(void)
2092 #ifdef DSP_DIS_STORE
2094 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);
2096 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2097 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2099 DSPWriteLong(RM, RN, DSP);
2103 static void dsp_opcode_loadb(void)
2105 #ifdef DSP_DIS_LOADB
2107 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);
2109 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2110 RN = DSPReadLong(RM, DSP) & 0xFF;
2112 RN = JaguarReadByte(RM, DSP);
2113 #ifdef DSP_DIS_LOADB
2115 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2119 static void dsp_opcode_loadw(void)
2121 #ifdef DSP_DIS_LOADW
2123 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);
2125 #ifdef DSP_CORRECT_ALIGNMENT
2126 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2127 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2129 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2131 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2132 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2134 RN = JaguarReadWord(RM, DSP);
2136 #ifdef DSP_DIS_LOADW
2138 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2142 static void dsp_opcode_load(void)
2146 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);
2148 #ifdef DSP_CORRECT_ALIGNMENT
2149 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2151 RN = DSPReadLong(RM, DSP);
2155 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2159 static void dsp_opcode_load_r14_indexed(void)
2161 #ifdef DSP_DIS_LOAD14I
2163 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);
2165 #ifdef DSP_CORRECT_ALIGNMENT
2166 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2168 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2170 #ifdef DSP_DIS_LOAD14I
2172 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2176 static void dsp_opcode_load_r15_indexed(void)
2178 #ifdef DSP_DIS_LOAD15I
2180 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);
2182 #ifdef DSP_CORRECT_ALIGNMENT
2183 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2185 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2187 #ifdef DSP_DIS_LOAD15I
2189 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2193 static void dsp_opcode_movei(void)
2195 #ifdef DSP_DIS_MOVEI
2197 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);
2199 // This instruction is followed by 32-bit value in LSW / MSW format...
2200 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2202 #ifdef DSP_DIS_MOVEI
2204 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2208 static void dsp_opcode_moveta(void)
2210 #ifdef DSP_DIS_MOVETA
2212 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);
2215 #ifdef DSP_DIS_MOVETA
2217 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);
2221 static void dsp_opcode_movefa(void)
2223 #ifdef DSP_DIS_MOVEFA
2225 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);
2228 #ifdef DSP_DIS_MOVEFA
2230 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);
2234 static void dsp_opcode_move(void)
2238 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);
2243 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);
2247 static void dsp_opcode_moveq(void)
2249 #ifdef DSP_DIS_MOVEQ
2251 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);
2254 #ifdef DSP_DIS_MOVEQ
2256 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2260 static void dsp_opcode_resmac(void)
2262 #ifdef DSP_DIS_RESMAC
2264 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));
2266 RN = (uint32)dsp_acc;
2267 #ifdef DSP_DIS_RESMAC
2269 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2273 static void dsp_opcode_imult(void)
2275 #ifdef DSP_DIS_IMULT
2277 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);
2279 RN = (int16)RN * (int16)RM;
2281 #ifdef DSP_DIS_IMULT
2283 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);
2287 static void dsp_opcode_mult(void)
2291 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);
2293 RN = (uint16)RM * (uint16)RN;
2297 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);
2301 static void dsp_opcode_bclr(void)
2305 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);
2307 uint32 res = RN & ~(1 << IMM_1);
2312 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2316 static void dsp_opcode_btst(void)
2320 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);
2322 dsp_flag_z = (~RN >> IMM_1) & 1;
2325 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2329 static void dsp_opcode_bset(void)
2333 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);
2335 uint32 res = RN | (1 << IMM_1);
2340 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2344 static void dsp_opcode_subqt(void)
2346 #ifdef DSP_DIS_SUBQT
2348 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);
2350 RN -= dsp_convert_zero[IMM_1];
2351 #ifdef DSP_DIS_SUBQT
2353 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2357 static void dsp_opcode_addqt(void)
2359 #ifdef DSP_DIS_ADDQT
2361 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);
2363 RN += dsp_convert_zero[IMM_1];
2364 #ifdef DSP_DIS_ADDQT
2366 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2370 static void dsp_opcode_imacn(void)
2372 #ifdef DSP_DIS_IMACN
2374 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);
2376 int32 res = (int16)RM * (int16)RN;
2377 dsp_acc += (int64)res;
2378 //Should we AND the result to fit into 40 bits here???
2379 #ifdef DSP_DIS_IMACN
2381 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));
2385 static void dsp_opcode_mtoi(void)
2387 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2391 static void dsp_opcode_normi(void)
2398 while ((_Rm & 0xffc00000) == 0)
2403 while ((_Rm & 0xff800000) != 0)
2413 static void dsp_opcode_mmult(void)
2415 int count = dsp_matrix_control&0x0f;
2416 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2420 if (!(dsp_matrix_control & 0x10))
2422 for (int i = 0; i < count; i++)
2426 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2428 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2429 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2436 for (int i = 0; i < count; i++)
2440 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2442 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2443 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2448 RN = res = (int32)accum;
2450 //NOTE: The flags are set based upon the last add/multiply done...
2454 static void dsp_opcode_abs(void)
2458 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);
2463 if (_Rn == 0x80000000)
2467 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2468 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2473 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2477 static void dsp_opcode_div(void)
2484 if (dsp_div_control & 1)
2486 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2487 if (dsp_remain&0x80000000)
2489 RN = (((uint64)_Rn) << 16) / _Rm;
2493 dsp_remain = _Rn % _Rm;
2494 if (dsp_remain&0x80000000)
2503 static void dsp_opcode_imultn(void)
2505 #ifdef DSP_DIS_IMULTN
2507 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);
2509 // This is OK, since this multiply won't overflow 32 bits...
2510 int32 res = (int32)((int16)RN * (int16)RM);
2511 dsp_acc = (int64)res;
2513 #ifdef DSP_DIS_IMULTN
2515 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));
2519 static void dsp_opcode_neg(void)
2523 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);
2526 SET_ZNC_SUB(0, RN, res);
2530 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2534 static void dsp_opcode_shlq(void)
2538 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);
2540 int32 r1 = 32 - IMM_1;
2541 uint32 res = RN << r1;
2542 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2546 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2550 static void dsp_opcode_shrq(void)
2554 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);
2556 int32 r1 = dsp_convert_zero[IMM_1];
2557 uint32 res = RN >> r1;
2558 SET_ZN(res); dsp_flag_c = RN & 1;
2562 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2566 static void dsp_opcode_ror(void)
2570 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);
2572 uint32 r1 = RM & 0x1F;
2573 uint32 res = (RN >> r1) | (RN << (32 - r1));
2574 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2578 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);
2582 static void dsp_opcode_rorq(void)
2586 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);
2588 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2590 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2592 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2595 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2599 static void dsp_opcode_sha(void)
2601 int32 sRm=(int32)RM;
2607 if (shift>=32) shift=32;
2608 dsp_flag_c=(_Rn&0x80000000)>>31;
2618 if (shift>=32) shift=32;
2622 _Rn=((int32)_Rn)>>1;
2630 static void dsp_opcode_sharq(void)
2632 #ifdef DSP_DIS_SHARQ
2634 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);
2636 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2637 SET_ZN(res); dsp_flag_c = RN & 0x01;
2639 #ifdef DSP_DIS_SHARQ
2641 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2645 static void dsp_opcode_sh(void)
2647 int32 sRm=(int32)RM;
2652 uint32 shift=(-sRm);
2653 if (shift>=32) shift=32;
2654 dsp_flag_c=(_Rn&0x80000000)>>31;
2664 if (shift>=32) shift=32;
2676 void dsp_opcode_addqmod(void)
2678 #ifdef DSP_DIS_ADDQMOD
2680 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);
2682 uint32 r1 = dsp_convert_zero[IMM_1];
2684 uint32 res = r2 + r1;
2685 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2687 SET_ZNC_ADD(r2, r1, res);
2688 #ifdef DSP_DIS_ADDQMOD
2690 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2694 void dsp_opcode_subqmod(void)
2696 uint32 r1 = dsp_convert_zero[IMM_1];
2698 uint32 res = r2 - r1;
2699 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2702 SET_ZNC_SUB(r2, r1, res);
2705 void dsp_opcode_mirror(void)
2708 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2712 void dsp_opcode_sat32s(void)
2714 int32 r2 = (uint32)RN;
2715 int32 temp = dsp_acc >> 32;
2716 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2721 void dsp_opcode_sat16s(void)
2724 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2730 // New pipelined DSP core
2733 static void DSP_abs(void);
2734 static void DSP_add(void);
2735 static void DSP_addc(void);
2736 static void DSP_addq(void);
2737 static void DSP_addqmod(void);
2738 static void DSP_addqt(void);
2739 static void DSP_and(void);
2740 static void DSP_bclr(void);
2741 static void DSP_bset(void);
2742 static void DSP_btst(void);
2743 static void DSP_cmp(void);
2744 static void DSP_cmpq(void);
2745 static void DSP_div(void);
2746 static void DSP_imacn(void);
2747 static void DSP_imult(void);
2748 static void DSP_imultn(void);
2749 static void DSP_illegal(void);
2750 static void DSP_jr(void);
2751 static void DSP_jump(void);
2752 static void DSP_load(void);
2753 static void DSP_loadb(void);
2754 static void DSP_loadw(void);
2755 static void DSP_load_r14_i(void);
2756 static void DSP_load_r14_r(void);
2757 static void DSP_load_r15_i(void);
2758 static void DSP_load_r15_r(void);
2759 static void DSP_mirror(void);
2760 static void DSP_mmult(void);
2761 static void DSP_move(void);
2762 static void DSP_movefa(void);
2763 static void DSP_movei(void);
2764 static void DSP_movepc(void);
2765 static void DSP_moveq(void);
2766 static void DSP_moveta(void);
2767 static void DSP_mtoi(void);
2768 static void DSP_mult(void);
2769 static void DSP_neg(void);
2770 static void DSP_nop(void);
2771 static void DSP_normi(void);
2772 static void DSP_not(void);
2773 static void DSP_or(void);
2774 static void DSP_resmac(void);
2775 static void DSP_ror(void);
2776 static void DSP_rorq(void);
2777 static void DSP_sat16s(void);
2778 static void DSP_sat32s(void);
2779 static void DSP_sh(void);
2780 static void DSP_sha(void);
2781 static void DSP_sharq(void);
2782 static void DSP_shlq(void);
2783 static void DSP_shrq(void);
2784 static void DSP_store(void);
2785 static void DSP_storeb(void);
2786 static void DSP_storew(void);
2787 static void DSP_store_r14_i(void);
2788 static void DSP_store_r14_r(void);
2789 static void DSP_store_r15_i(void);
2790 static void DSP_store_r15_r(void);
2791 static void DSP_sub(void);
2792 static void DSP_subc(void);
2793 static void DSP_subq(void);
2794 static void DSP_subqmod(void);
2795 static void DSP_subqt(void);
2796 static void DSP_xor(void);
2798 void (* DSPOpcode[64])() =
2800 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2801 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2802 DSP_neg, DSP_and, DSP_or, DSP_xor,
2803 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2805 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2806 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2807 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2808 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2810 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2811 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2812 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2813 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2815 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2816 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2817 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2818 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2821 bool readAffected[64][2] =
2823 { true, true}, { true, true}, {false, true}, {false, true},
2824 { true, true}, { true, true}, {false, true}, {false, true},
2825 {false, true}, { true, true}, { true, true}, { true, true},
2826 {false, true}, {false, true}, {false, true}, {false, true},
2828 { true, true}, { true, true}, { true, true}, {false, true},
2829 { true, true}, { true, true}, {false, true}, { true, true},
2830 {false, true}, {false, true}, { true, true}, {false, true},
2831 { true, true}, {false, true}, { true, true}, {false, true},
2833 {false, true}, {false, true}, { true, false}, {false, false},
2834 { true, false}, {false, false}, {false, false}, { true, false},
2835 { true, false}, { true, false}, {false, true}, { true, false},
2836 { true, false}, { true, true}, { true, true}, { true, true},
2838 {false, true}, { true, true}, { true, true}, {false, true},
2839 { true, false}, { true, false}, { true, true}, { true, false},
2840 { true, false}, {false, false}, { true, false}, { true, false},
2841 { true, true}, { true, true}, {false, false}, {false, true}
2844 bool isLoadStore[65] =
2846 false, false, false, false, false, false, false, false,
2847 false, false, false, false, false, false, false, false,
2849 false, false, false, false, false, false, false, false,
2850 false, false, false, false, false, false, false, false,
2852 false, false, false, false, false, false, false, true,
2853 true, true, false, true, true, true, true, true,
2855 false, true, true, false, false, false, false, false,
2856 false, false, true, true, true, true, false, false, false
2859 void FlushDSPPipeline(void)
2861 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2863 for(int i=0; i<4; i++)
2864 pipeline[i].opcode = PIPELINE_STALL;
2866 for(int i=0; i<32; i++)
2871 // New pipelined DSP execution core
2873 /*void DSPExecP(int32 cycles)
2875 // bool inhibitFetch = false;
2877 dsp_releaseTimeSlice_flag = 0;
2880 while (cycles > 0 && DSP_RUNNING)
2882 WriteLog("DSPExecP: Pipeline status...\n");
2883 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);
2884 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);
2885 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);
2886 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);
2887 WriteLog(" --> Scoreboard: ");
2888 for(int i=0; i<32; i++)
2889 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2891 // Stage 1: Instruction fetch
2892 // if (!inhibitFetch)
2894 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2895 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2896 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2897 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2898 if (pipeline[plPtrFetch].opcode == 38)
2899 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2900 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2903 // inhibitFetch = false;
2904 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2906 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2907 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2908 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2909 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2910 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2911 // Stage 2: Read registers
2912 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2913 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2914 if (scoreboard[pipeline[plPtrRead].operand2])
2915 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2916 // We have a hit in the scoreboard, so we have to stall the pipeline...
2918 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2919 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2920 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2921 pipeline[plPtrFetch] = pipeline[plPtrRead];
2922 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2926 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2927 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2928 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2930 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2931 // Shouldn't we be more selective with the register scoreboarding?
2932 // Yes, we should. !!! FIX !!!
2933 scoreboard[pipeline[plPtrRead].operand2] = true;
2934 //Advance PC here??? Yes.
2935 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2936 //This is a mangling of the pipeline stages, but what else to do???
2937 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2940 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2941 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);
2942 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);
2943 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);
2944 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2946 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2948 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2949 DSPOpcode[pipeline[plPtrExec].opcode]();
2950 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2951 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2956 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2957 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);
2958 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);
2959 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);
2960 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);
2961 // Stage 4: Write back register
2962 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2964 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2965 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2967 scoreboard[pipeline[plPtrWrite].operand1]
2968 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2971 // Push instructions through the pipeline...
2972 plPtrFetch = (++plPtrFetch) & 0x03;
2973 plPtrRead = (++plPtrRead) & 0x03;
2974 plPtrExec = (++plPtrExec) & 0x03;
2975 plPtrWrite = (++plPtrWrite) & 0x03;
2982 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2984 // Should be fixed now. Another problem is figuring how to do the sequence following
2985 // a branch followed with the JR & JUMP instructions...
2987 // There are two conflicting problems:
2990 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2991 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2992 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2993 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2994 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2995 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2996 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2997 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2998 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2999 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3000 DSP: Finished interrupt.
3001 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3002 ; bank 0 (where is was prepared)!
3003 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3004 F1B252: NOP [NCZ:001]
3007 // The other is when you see this at the end of an IRQ:
3010 JUMP T, (R29) ; R29 = Previous stack + 2
3011 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3013 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3014 ; 1) The STORE goes through the pipeline and is executed/written back
3015 ; 2) The pipeline is flushed
3016 ; 3) The DSP_PC is set to the new address
3017 ; 4) Execution resumes
3019 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3020 ; bank 0 instead of the current bank 1 and so goes astray!
3023 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3024 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3028 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3029 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3030 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3031 If it were done properly, the STORE write back would occur *after* (well, technically,
3032 during) the execution of the the JUMP that follows it.
3036 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3037 F1B08A: NOP [NCZ:001]
3039 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3042 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3045 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3046 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3047 F1B08A: NOP [NCZ:001]
3049 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3052 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3053 DSP: CPU -> DSP interrupt
3054 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3055 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3057 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3060 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3061 F1B006: NOP [NCZ:001]
3063 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3066 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3067 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3070 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3071 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3074 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3075 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3078 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3079 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3082 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3085 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3088 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3089 F1B0FE: NOP [NCZ:000]
3091 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3094 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3097 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3098 F1B138: NOP [NCZ:000]
3100 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3103 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3104 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3105 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3108 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3109 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3112 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3113 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3114 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3116 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3117 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3120 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3121 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3122 DSP: Finished interrupt.
3123 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3125 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3128 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3129 F1B016: NOP [NCZ:001]
3131 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3134 uint32 pcQueue1[0x400];
3136 static uint32 prevR1;
3137 //Let's try a 3 stage pipeline....
3138 //Looks like 3 stage is correct, otherwise bad things happen...
3139 void DSPExecP2(int32 cycles)
3141 dsp_releaseTimeSlice_flag = 0;
3144 while (cycles > 0 && DSP_RUNNING)
3146 /*extern uint32 totalFrames;
3147 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3148 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3149 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3151 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3154 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3156 if (dsp_pc == 0xF1B092)
3157 doDSPDis = false;//*/
3158 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3159 doDSPDis = true;//*/
3160 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3161 doDSPDis = true;//*/
3162 /*if (dsp_pc == 0xF1B0A0)
3163 doDSPDis = true;//*/
3164 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3165 doDSPDis = true;//*/
3166 //Two parter... (not sure how to write this)
3167 //if (dsp_pc == 0xF1B0D2)
3168 // prevR1 = dsp_reg[1];
3170 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3171 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3174 pcQueue1[pcQPtr1++] = dsp_pc;
3177 #ifdef DSP_DEBUG_PL2
3178 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3180 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3185 for(int i=0; i<0x400; i++)
3187 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3188 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3194 if (IMASKCleared) // If IMASK was cleared,
3196 #ifdef DSP_DEBUG_IRQ
3197 WriteLog("DSP: Finished interrupt.\n");
3199 DSPHandleIRQs(); // See if any other interrupts are pending!
3200 IMASKCleared = false;
3203 //if (dsp_flags & REGPAGE)
3204 // WriteLog(" --> REGPAGE has just been set!\n");
3205 #ifdef DSP_DEBUG_PL2
3208 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3209 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]);
3210 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]);
3211 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]);
3212 WriteLog(" --> Scoreboard: ");
3213 for(int i=0; i<32; i++)
3214 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3218 // Stage 1a: Instruction fetch
3219 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3220 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3221 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3222 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3223 if (pipeline[plPtrRead].opcode == 38)
3224 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3225 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3226 #ifdef DSP_DEBUG_PL2
3229 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3230 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3231 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]);
3232 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]);
3233 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
3236 // Stage 1b: Read registers
3237 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3238 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3240 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3241 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3242 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3243 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3244 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3245 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3246 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3248 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3249 // We have a hit in the scoreboard, so we have to stall the pipeline...
3250 #ifdef DSP_DEBUG_PL2
3254 WriteLog(" --> Stalling pipeline: ");
3255 if (readAffected[pipeline[plPtrRead].opcode][0])
3256 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3257 if (readAffected[pipeline[plPtrRead].opcode][1])
3258 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3262 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3263 #ifdef DSP_DEBUG_PL2
3268 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3269 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3270 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3272 // Shouldn't we be more selective with the register scoreboarding?
3273 // Yes, we should. !!! FIX !!! Kinda [DONE]
3274 #ifndef NEW_SCOREBOARD
3275 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3277 //Hopefully this will fix the dual MOVEQ # problem...
3278 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3281 //Advance PC here??? Yes.
3282 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3285 #ifdef DSP_DEBUG_PL2
3288 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3289 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]);
3290 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]);
3291 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]);
3295 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3297 #ifdef DSP_DEBUG_PL2
3299 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"));
3303 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3308 lastExec = pipeline[plPtrExec].instruction;
3309 //WriteLog("[lastExec = %04X]\n", lastExec);
3311 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3312 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3313 DSPOpcode[pipeline[plPtrExec].opcode]();
3314 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3318 //Let's not, until we do the stalling correctly...
3319 //But, we gotta while we're doing the comparison core...!
3320 //Or do we? cycles--;
3321 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3322 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3323 //to model this clock cycle behavior correctly...
3324 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3325 //don't affect the reads at stage 1...
3326 #ifdef DSP_DEBUG_STALL
3328 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3332 #ifdef DSP_DEBUG_PL2
3335 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3336 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]);
3337 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]);
3338 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]);
3342 // Stage 3: Write back register/memory address
3343 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3345 /*if (pipeline[plPtrWrite].writebackRegister == 3
3346 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3349 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3352 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3354 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3355 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3358 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3359 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3360 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3361 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3363 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3367 #ifndef NEW_SCOREBOARD
3368 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3369 scoreboard[pipeline[plPtrWrite].operand2] = false;
3371 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3372 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3373 if (scoreboard[pipeline[plPtrWrite].operand2])
3374 scoreboard[pipeline[plPtrWrite].operand2]--;
3378 // Push instructions through the pipeline...
3379 plPtrRead = (++plPtrRead) & 0x03;
3380 plPtrExec = (++plPtrExec) & 0x03;
3381 plPtrWrite = (++plPtrWrite) & 0x03;
3390 //#define DSP_DEBUG_PL3
3391 //Let's try a 2 stage pipeline....
3392 void DSPExecP3(int32 cycles)
3394 dsp_releaseTimeSlice_flag = 0;
3397 while (cycles > 0 && DSP_RUNNING)
3399 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3401 #ifdef DSP_DEBUG_PL3
3402 WriteLog("DSPExecP: Pipeline status...\n");
3403 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]);
3404 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]);
3405 WriteLog(" --> Scoreboard: ");
3406 for(int i=0; i<32; i++)
3407 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3410 // Stage 1a: Instruction fetch
3411 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3412 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3413 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3414 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3415 if (pipeline[plPtrRead].opcode == 38)
3416 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3417 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3418 #ifdef DSP_DEBUG_PL3
3419 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3420 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3421 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]);
3422 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]);
3424 // Stage 1b: Read registers
3425 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3426 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3427 // We have a hit in the scoreboard, so we have to stall the pipeline...
3428 #ifdef DSP_DEBUG_PL3
3430 WriteLog(" --> Stalling pipeline: ");
3431 if (readAffected[pipeline[plPtrRead].opcode][0])
3432 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3433 if (readAffected[pipeline[plPtrRead].opcode][1])
3434 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3437 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3438 #ifdef DSP_DEBUG_PL3
3443 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3444 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3445 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3447 // Shouldn't we be more selective with the register scoreboarding?
3448 // Yes, we should. !!! FIX !!! [Kinda DONE]
3449 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3451 //Advance PC here??? Yes.
3452 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3455 #ifdef DSP_DEBUG_PL3
3456 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3457 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]);
3458 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]);
3460 // Stage 2a: Execute
3461 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3463 #ifdef DSP_DEBUG_PL3
3464 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3466 DSPOpcode[pipeline[plPtrExec].opcode]();
3467 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3468 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3473 #ifdef DSP_DEBUG_PL3
3474 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3475 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]);
3476 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]);
3479 // Stage 2b: Write back register
3480 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3482 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3483 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3485 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3486 scoreboard[pipeline[plPtrExec].operand2] = false;
3489 // Push instructions through the pipeline...
3490 plPtrRead = (++plPtrRead) & 0x03;
3491 plPtrExec = (++plPtrExec) & 0x03;
3498 // DSP pipelined opcode handlers
3501 #define PRM pipeline[plPtrExec].reg1
3502 #define PRN pipeline[plPtrExec].reg2
3503 #define PIMM1 pipeline[plPtrExec].operand1
3504 #define PIMM2 pipeline[plPtrExec].operand2
3505 #define PRES pipeline[plPtrExec].result
3506 #define PWBR pipeline[plPtrExec].writebackRegister
3507 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3508 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3509 #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))
3510 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3512 static void DSP_abs(void)
3516 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);
3520 if (_Rn == 0x80000000)
3524 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3525 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3526 CLR_ZN; SET_Z(PRES);
3530 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3534 static void DSP_add(void)
3538 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);
3540 uint32 res = PRN + PRM;
3541 SET_ZNC_ADD(PRN, PRM, res);
3545 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);
3549 static void DSP_addc(void)
3553 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);
3555 uint32 res = PRN + PRM + dsp_flag_c;
3556 uint32 carry = dsp_flag_c;
3557 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3558 SET_ZNC_ADD(PRN + carry, PRM, res);
3559 // SET_ZNC_ADD(PRN, PRM + carry, res);
3563 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);
3567 static void DSP_addq(void)
3571 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);
3573 uint32 r1 = dsp_convert_zero[PIMM1];
3574 uint32 res = PRN + r1;
3575 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3579 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3583 static void DSP_addqmod(void)
3585 #ifdef DSP_DIS_ADDQMOD
3587 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);
3589 uint32 r1 = dsp_convert_zero[PIMM1];
3591 uint32 res = r2 + r1;
3592 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3594 SET_ZNC_ADD(r2, r1, res);
3595 #ifdef DSP_DIS_ADDQMOD
3597 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3601 static void DSP_addqt(void)
3603 #ifdef DSP_DIS_ADDQT
3605 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);
3607 PRES = PRN + dsp_convert_zero[PIMM1];
3608 #ifdef DSP_DIS_ADDQT
3610 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3614 static void DSP_and(void)
3618 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);
3624 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);
3628 static void DSP_bclr(void)
3632 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);
3634 PRES = PRN & ~(1 << PIMM1);
3638 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3642 static void DSP_bset(void)
3646 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);
3648 PRES = PRN | (1 << PIMM1);
3652 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3656 static void DSP_btst(void)
3660 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);
3662 dsp_flag_z = (~PRN >> PIMM1) & 1;
3666 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3670 static void DSP_cmp(void)
3674 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);
3676 uint32 res = PRN - PRM;
3677 SET_ZNC_SUB(PRN, PRM, res);
3681 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3685 static void DSP_cmpq(void)
3687 static int32 sqtable[32] =
3688 { 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 };
3691 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);
3693 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3694 uint32 res = PRN - r1;
3695 SET_ZNC_SUB(PRN, r1, res);
3699 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3703 static void DSP_div(void)
3705 uint32 _Rm = PRM, _Rn = PRN;
3709 if (dsp_div_control & 1)
3711 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3712 if (dsp_remain & 0x80000000)
3714 PRES = (((uint64)_Rn) << 16) / _Rm;
3718 dsp_remain = _Rn % _Rm;
3719 if (dsp_remain & 0x80000000)
3728 static void DSP_imacn(void)
3730 #ifdef DSP_DIS_IMACN
3732 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);
3734 int32 res = (int16)PRM * (int16)PRN;
3735 dsp_acc += (int64)res;
3736 //Should we AND the result to fit into 40 bits here???
3738 #ifdef DSP_DIS_IMACN
3740 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));
3744 static void DSP_imult(void)
3746 #ifdef DSP_DIS_IMULT
3748 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);
3750 PRES = (int16)PRN * (int16)PRM;
3752 #ifdef DSP_DIS_IMULT
3754 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);
3758 static void DSP_imultn(void)
3760 #ifdef DSP_DIS_IMULTN
3762 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);
3764 // This is OK, since this multiply won't overflow 32 bits...
3765 int32 res = (int32)((int16)PRN * (int16)PRM);
3766 dsp_acc = (int64)res;
3769 #ifdef DSP_DIS_IMULTN
3771 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));
3775 static void DSP_illegal(void)
3777 #ifdef DSP_DIS_ILLEGAL
3779 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3784 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3785 // can cause trouble because an interrupt can occur *before* the instruction following the
3786 // jump can execute... !!! FIX !!!
3787 // This can probably be solved by judicious coding in the pipeline execution core...
3788 // And should be fixed now...
3789 static void DSP_jr(void)
3792 const char * condition[32] =
3793 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3794 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3795 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3796 "???", "???", "???", "F" };
3798 //How come this is always off by 2???
3799 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);
3801 // KLUDGE: Used by BRANCH_CONDITION macro
3802 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3804 if (BRANCH_CONDITION(PIMM2))
3808 WriteLog("Branched!\n");
3810 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3811 //Account for pipeline effects...
3812 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3813 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3815 // Now that we've branched, we have to make sure that the following instruction
3816 // is executed atomically with this one and then flush the pipeline before setting
3819 // Step 1: Handle writebacks at stage 3 of pipeline
3820 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3822 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3823 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3825 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3826 scoreboard[pipeline[plPtrWrite].operand2] = false;
3828 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3830 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3832 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3833 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3836 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3837 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3838 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3839 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3841 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3845 #ifndef NEW_SCOREBOARD
3846 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3847 scoreboard[pipeline[plPtrWrite].operand2] = false;
3849 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3850 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3851 if (scoreboard[pipeline[plPtrWrite].operand2])
3852 scoreboard[pipeline[plPtrWrite].operand2]--;
3856 // Step 2: Push instruction through pipeline & execute following instruction
3857 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3858 // we effectively handle the final push of the instruction through the
3859 // pipeline when the new PC takes effect (since when we return, the
3860 // pipeline code will be executing the writeback stage. If we reverse
3861 // the execution order of the pipeline stages, this will no longer be
3863 pipeline[plPtrExec] = pipeline[plPtrRead];
3864 //This is BAD. We need to get that next opcode and execute it!
3865 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3866 // remove this crap.
3867 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3869 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3870 pipeline[plPtrExec].opcode = instruction >> 10;
3871 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3872 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3873 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3874 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3875 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3877 dsp_pc += 2; // For DSP_DIS_* accuracy
3878 DSPOpcode[pipeline[plPtrExec].opcode]();
3879 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3880 pipeline[plPtrWrite] = pipeline[plPtrExec];
3882 // Step 3: Flush pipeline & set new PC
3883 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3890 WriteLog("Branch NOT taken.\n");
3896 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3899 static void DSP_jump(void)
3902 const char * condition[32] =
3903 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3904 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3905 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3906 "???", "???", "???", "F" };
3908 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);
3910 // KLUDGE: Used by BRANCH_CONDITION macro
3911 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3913 if (BRANCH_CONDITION(PIMM2))
3917 WriteLog("Branched!\n");
3919 uint32 PCSave = PRM;
3920 // Now that we've branched, we have to make sure that the following instruction
3921 // is executed atomically with this one and then flush the pipeline before setting
3924 // Step 1: Handle writebacks at stage 3 of pipeline
3925 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3927 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3928 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3930 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3931 scoreboard[pipeline[plPtrWrite].operand2] = false;
3933 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3935 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3937 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3938 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3941 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3942 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3943 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3944 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3946 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3950 #ifndef NEW_SCOREBOARD
3951 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3952 scoreboard[pipeline[plPtrWrite].operand2] = false;
3954 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3955 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3956 if (scoreboard[pipeline[plPtrWrite].operand2])
3957 scoreboard[pipeline[plPtrWrite].operand2]--;
3961 // Step 2: Push instruction through pipeline & execute following instruction
3962 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3963 // we effectively handle the final push of the instruction through the
3964 // pipeline when the new PC takes effect (since when we return, the
3965 // pipeline code will be executing the writeback stage. If we reverse
3966 // the execution order of the pipeline stages, this will no longer be
3968 pipeline[plPtrExec] = pipeline[plPtrRead];
3969 //This is BAD. We need to get that next opcode and execute it!
3970 //Also, same problem in JR!
3971 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3972 // remove this crap.
3973 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3975 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3976 pipeline[plPtrExec].opcode = instruction >> 10;
3977 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3978 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3979 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3980 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3981 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3983 dsp_pc += 2; // For DSP_DIS_* accuracy
3984 DSPOpcode[pipeline[plPtrExec].opcode]();
3985 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3986 pipeline[plPtrWrite] = pipeline[plPtrExec];
3988 // Step 3: Flush pipeline & set new PC
3989 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3996 WriteLog("Branch NOT taken.\n");
4004 static void DSP_load(void)
4008 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);
4010 #ifdef DSP_CORRECT_ALIGNMENT
4011 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4013 PRES = DSPReadLong(PRM, DSP);
4017 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4021 static void DSP_loadb(void)
4023 #ifdef DSP_DIS_LOADB
4025 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);
4027 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4028 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4030 PRES = JaguarReadByte(PRM, DSP);
4031 #ifdef DSP_DIS_LOADB
4033 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4037 static void DSP_loadw(void)
4039 #ifdef DSP_DIS_LOADW
4041 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);
4043 #ifdef DSP_CORRECT_ALIGNMENT
4044 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4045 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4047 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4049 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4050 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4052 PRES = JaguarReadWord(PRM, DSP);
4054 #ifdef DSP_DIS_LOADW
4056 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4060 static void DSP_load_r14_i(void)
4062 #ifdef DSP_DIS_LOAD14I
4064 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);
4066 #ifdef DSP_CORRECT_ALIGNMENT
4067 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4069 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4071 #ifdef DSP_DIS_LOAD14I
4073 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4077 static void DSP_load_r14_r(void)
4079 #ifdef DSP_DIS_LOAD14R
4081 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);
4083 #ifdef DSP_CORRECT_ALIGNMENT
4084 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4086 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4088 #ifdef DSP_DIS_LOAD14R
4090 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4094 static void DSP_load_r15_i(void)
4096 #ifdef DSP_DIS_LOAD15I
4098 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);
4100 #ifdef DSP_CORRECT_ALIGNMENT
4101 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4103 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4105 #ifdef DSP_DIS_LOAD15I
4107 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4111 static void DSP_load_r15_r(void)
4113 #ifdef DSP_DIS_LOAD15R
4115 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);
4117 #ifdef DSP_CORRECT_ALIGNMENT
4118 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4120 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4122 #ifdef DSP_DIS_LOAD15R
4124 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4128 static void DSP_mirror(void)
4131 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4135 static void DSP_mmult(void)
4137 int count = dsp_matrix_control&0x0f;
4138 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4142 if (!(dsp_matrix_control & 0x10))
4144 for (int i = 0; i < count; i++)
4148 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4150 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4151 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4158 for (int i = 0; i < count; i++)
4162 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4164 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4165 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4171 PRES = res = (int32)accum;
4173 //NOTE: The flags are set based upon the last add/multiply done...
4177 static void DSP_move(void)
4181 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);
4186 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);
4190 static void DSP_movefa(void)
4192 #ifdef DSP_DIS_MOVEFA
4194 // 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);
4195 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);
4197 // PRES = ALTERNATE_RM;
4198 PRES = dsp_alternate_reg[PIMM1];
4199 #ifdef DSP_DIS_MOVEFA
4201 // 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);
4202 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);
4206 static void DSP_movei(void)
4208 #ifdef DSP_DIS_MOVEI
4210 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);
4212 // // This instruction is followed by 32-bit value in LSW / MSW format...
4213 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4215 #ifdef DSP_DIS_MOVEI
4217 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4221 static void DSP_movepc(void)
4223 #ifdef DSP_DIS_MOVEPC
4225 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);
4227 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4228 // PRES = dsp_pc - 2;
4229 //Account for pipeline effects...
4230 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4231 #ifdef DSP_DIS_MOVEPC
4233 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4237 static void DSP_moveq(void)
4239 #ifdef DSP_DIS_MOVEQ
4241 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);
4244 #ifdef DSP_DIS_MOVEQ
4246 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4250 static void DSP_moveta(void)
4252 #ifdef DSP_DIS_MOVETA
4254 // 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);
4255 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]);
4257 // ALTERNATE_RN = PRM;
4258 dsp_alternate_reg[PIMM2] = PRM;
4260 #ifdef DSP_DIS_MOVETA
4262 // 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);
4263 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]);
4267 static void DSP_mtoi(void)
4269 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4273 static void DSP_mult(void)
4277 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);
4279 PRES = (uint16)PRM * (uint16)PRN;
4283 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);
4287 static void DSP_neg(void)
4291 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);
4294 SET_ZNC_SUB(0, PRN, res);
4298 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4302 static void DSP_nop(void)
4306 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4311 static void DSP_normi(void)
4318 while ((_Rm & 0xffc00000) == 0)
4323 while ((_Rm & 0xff800000) != 0)
4333 static void DSP_not(void)
4337 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);
4343 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4347 static void DSP_or(void)
4351 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);
4357 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);
4361 static void DSP_resmac(void)
4363 #ifdef DSP_DIS_RESMAC
4365 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));
4367 PRES = (uint32)dsp_acc;
4368 #ifdef DSP_DIS_RESMAC
4370 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4374 static void DSP_ror(void)
4378 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);
4380 uint32 r1 = PRM & 0x1F;
4381 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4382 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4386 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
4390 static void DSP_rorq(void)
4394 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);
4396 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4398 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4400 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4403 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4407 static void DSP_sat16s(void)
4410 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4415 static void DSP_sat32s(void)
4417 int32 r2 = (uint32)PRN;
4418 int32 temp = dsp_acc >> 32;
4419 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4424 static void DSP_sh(void)
4426 int32 sRm = (int32)PRM;
4431 uint32 shift = -sRm;
4436 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4451 dsp_flag_c = _Rn & 0x1;
4464 static void DSP_sha(void)
4466 int32 sRm = (int32)PRM;
4471 uint32 shift = -sRm;
4476 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4491 dsp_flag_c = _Rn & 0x1;
4495 _Rn = ((int32)_Rn) >> 1;
4504 static void DSP_sharq(void)
4506 #ifdef DSP_DIS_SHARQ
4508 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);
4510 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4511 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4513 #ifdef DSP_DIS_SHARQ
4515 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4519 static void DSP_shlq(void)
4523 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);
4525 int32 r1 = 32 - PIMM1;
4526 uint32 res = PRN << r1;
4527 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4531 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4535 static void DSP_shrq(void)
4539 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);
4541 int32 r1 = dsp_convert_zero[PIMM1];
4542 uint32 res = PRN >> r1;
4543 SET_ZN(res); dsp_flag_c = PRN & 1;
4547 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4551 static void DSP_store(void)
4553 #ifdef DSP_DIS_STORE
4555 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);
4557 // DSPWriteLong(PRM, PRN, DSP);
4559 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4560 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4562 pipeline[plPtrExec].address = PRM;
4564 pipeline[plPtrExec].value = PRN;
4565 pipeline[plPtrExec].type = TYPE_DWORD;
4569 static void DSP_storeb(void)
4571 #ifdef DSP_DIS_STOREB
4573 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);
4575 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4576 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4578 // JaguarWriteByte(PRM, PRN, DSP);
4581 pipeline[plPtrExec].address = PRM;
4583 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4585 pipeline[plPtrExec].value = PRN & 0xFF;
4586 pipeline[plPtrExec].type = TYPE_DWORD;
4590 pipeline[plPtrExec].value = PRN;
4591 pipeline[plPtrExec].type = TYPE_BYTE;
4597 static void DSP_storew(void)
4599 #ifdef DSP_DIS_STOREW
4601 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);
4603 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4604 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4606 // JaguarWriteWord(PRM, PRN, DSP);
4609 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4610 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4612 pipeline[plPtrExec].address = PRM;
4615 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4617 pipeline[plPtrExec].value = PRN & 0xFFFF;
4618 pipeline[plPtrExec].type = TYPE_DWORD;
4622 pipeline[plPtrExec].value = PRN;
4623 pipeline[plPtrExec].type = TYPE_WORD;
4628 static void DSP_store_r14_i(void)
4630 #ifdef DSP_DIS_STORE14I
4632 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));
4634 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4636 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4637 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4639 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4641 pipeline[plPtrExec].value = PRN;
4642 pipeline[plPtrExec].type = TYPE_DWORD;
4646 static void DSP_store_r14_r(void)
4648 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4650 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4651 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4653 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4655 pipeline[plPtrExec].value = PRN;
4656 pipeline[plPtrExec].type = TYPE_DWORD;
4660 static void DSP_store_r15_i(void)
4662 #ifdef DSP_DIS_STORE15I
4664 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));
4666 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4668 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4669 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4671 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4673 pipeline[plPtrExec].value = PRN;
4674 pipeline[plPtrExec].type = TYPE_DWORD;
4678 static void DSP_store_r15_r(void)
4680 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4682 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4683 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4685 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4687 pipeline[plPtrExec].value = PRN;
4688 pipeline[plPtrExec].type = TYPE_DWORD;
4692 static void DSP_sub(void)
4696 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);
4698 uint32 res = PRN - PRM;
4699 SET_ZNC_SUB(PRN, PRM, res);
4703 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);
4707 static void DSP_subc(void)
4711 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);
4713 uint32 res = PRN - PRM - dsp_flag_c;
4714 uint32 borrow = dsp_flag_c;
4715 SET_ZNC_SUB(PRN - borrow, PRM, res);
4719 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);
4723 static void DSP_subq(void)
4727 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);
4729 uint32 r1 = dsp_convert_zero[PIMM1];
4730 uint32 res = PRN - r1;
4731 SET_ZNC_SUB(PRN, r1, res);
4735 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4739 static void DSP_subqmod(void)
4741 uint32 r1 = dsp_convert_zero[PIMM1];
4743 uint32 res = r2 - r1;
4744 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4746 SET_ZNC_SUB(r2, r1, res);
4749 static void DSP_subqt(void)
4751 #ifdef DSP_DIS_SUBQT
4753 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);
4755 PRES = PRN - dsp_convert_zero[PIMM1];
4756 #ifdef DSP_DIS_SUBQT
4758 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4762 static void DSP_xor(void)
4766 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);
4772 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);