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] = { 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 };
417 uint8 * dsp_branch_condition_table = NULL;
418 static uint16 * mirror_table = NULL;
419 static uint8 dsp_ram_8[0x2000];
421 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
423 static uint32 dsp_in_exec = 0;
424 static uint32 dsp_releaseTimeSlice_flag = 0;
429 // Comparison core vars (used only for core comparison! :-)
430 static uint64 count = 0;
431 static uint8 ram1[0x2000], ram2[0x2000];
432 static uint32 regs1[64], regs2[64];
433 static uint32 ctrl1[14], ctrl2[14];
436 // Private function prototypes
438 void DSPDumpRegisters(void);
439 void DSPDumpDisassembly(void);
440 void FlushDSPPipeline(void);
443 void dsp_reset_stats(void)
445 for(int i=0; i<65; i++)
446 dsp_opcode_use[i] = 0;
449 void DSPReleaseTimeslice(void)
451 //This does absolutely nothing!!! !!! FIX !!!
452 dsp_releaseTimeSlice_flag = 1;
455 void dsp_build_branch_condition_table(void)
457 // Allocate the mirror table
459 mirror_table = (uint16 *)malloc(65536 * sizeof(uint16));
461 // Fill in the mirror table
463 for(int i=0; i<65536; i++)
464 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
465 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
466 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
467 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
468 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
469 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
470 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
471 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
473 if (!dsp_branch_condition_table)
475 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8));
477 // Fill in the condition table
478 if (dsp_branch_condition_table)
480 for(int i=0; i<8; i++)
482 for(int j=0; j<32; j++)
489 if (!(i & ZERO_FLAG))
492 if (i & (CARRY_FLAG << (j >> 4)))
495 if (!(i & (CARRY_FLAG << (j >> 4))))
497 dsp_branch_condition_table[i * 32 + j] = result;
504 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
506 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
507 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
509 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
512 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
514 if (offset==0xF1CFE0)
517 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
518 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
520 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
522 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
524 if ((offset&0x03)==0)
527 if ((offset&0x03)==1)
528 return((data>>16)&0xff);
530 if ((offset&0x03)==2)
531 return((data>>8)&0xff);
533 if ((offset&0x03)==3)
537 return JaguarReadByte(offset, who);
540 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
542 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
543 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
545 offset &= 0xFFFFFFFE;
547 /* if (jaguar_mainRom_crc32==0xa74a97cd)
549 if (offset==0xF1A114) return(0x0000);
550 if (offset==0xF1A116) return(0x0000);
551 if (offset==0xF1B000) return(0x1234);
552 if (offset==0xF1B002) return(0x5678);
555 if (jaguar_mainRom_crc32==0x7ae20823)
557 if (offset==0xF1B9D8) return(0x0000);
558 if (offset==0xF1B9Da) return(0x0000);
559 if (offset==0xF1B2C0) return(0x0000);
560 if (offset==0xF1B2C2) return(0x0000);
563 // pour permettre � wolfenstein 3d de tourner sans le dsp
564 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
568 // pour permettre � nba jam de tourner sans le dsp
569 /* if (jaguar_mainRom_crc32==0x4faddb18)
571 if (offset==0xf1b2c0) return(0);
572 if (offset==0xf1b2c2) return(0);
573 if (offset==0xf1b240) return(0);
574 if (offset==0xf1b242) return(0);
575 if (offset==0xF1B340) return(0);
576 if (offset==0xF1B342) return(0);
577 if (offset==0xF1BAD8) return(0);
578 if (offset==0xF1BADA) return(0);
579 if (offset==0xF1B040) return(0);
580 if (offset==0xF1B042) return(0);
581 if (offset==0xF1B0C0) return(0);
582 if (offset==0xF1B0C2) return(0);
583 if (offset==0xF1B140) return(0);
584 if (offset==0xF1B142) return(0);
585 if (offset==0xF1B1C0) return(0);
586 if (offset==0xF1B1C2) return(0);
589 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
591 offset -= DSP_WORK_RAM_BASE;
592 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
594 return GET16(dsp_ram_8, offset);
596 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
598 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
601 return data & 0xFFFF;
606 return JaguarReadWord(offset, who);
609 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
611 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
612 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
615 offset &= 0xFFFFFFFC;
616 /*if (offset == 0xF1BCF4)
618 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));
619 DSPDumpDisassembly();
621 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
623 offset -= DSP_WORK_RAM_BASE;
624 return GET32(dsp_ram_8, offset);
626 //NOTE: Didn't return DSP_ACCUM!!!
627 //Mebbe it's not 'spose to! Yes, it is!
628 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
633 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
634 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
635 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
637 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
638 return dsp_flags & 0xFFFFC1FF;
639 case 0x04: return dsp_matrix_control;
640 case 0x08: return dsp_pointer_to_matrix;
641 case 0x0C: return dsp_data_organization;
642 case 0x10: return dsp_pc;
643 case 0x14: return dsp_control;
644 case 0x18: return dsp_modulo;
645 case 0x1C: return dsp_remain;
647 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
649 // unaligned long read-- !!! FIX !!!
653 return JaguarReadLong(offset, who);
656 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
658 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
659 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
661 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
663 offset -= DSP_WORK_RAM_BASE;
664 dsp_ram_8[offset] = data;
665 //This is rather stupid! !!! FIX !!!
666 /* if (dsp_in_exec == 0)
668 m68k_end_timeslice();
669 dsp_releaseTimeslice();
673 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
675 uint32 reg = offset & 0x1C;
676 int bytenum = offset & 0x03;
678 if ((reg >= 0x1C) && (reg <= 0x1F))
679 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
682 //This looks funky. !!! FIX !!!
683 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
684 bytenum = 3 - bytenum; // convention motorola !!!
685 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
686 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
690 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
691 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
692 JaguarWriteByte(offset, data, who);
695 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
697 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
698 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
699 offset &= 0xFFFFFFFE;
700 /*if (offset == 0xF1BCF4)
702 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
704 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
705 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
707 /*if (offset == 0xF1B2F4)
709 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
711 offset -= DSP_WORK_RAM_BASE;
712 dsp_ram_8[offset] = data >> 8;
713 dsp_ram_8[offset+1] = data & 0xFF;
714 //This is rather stupid! !!! FIX !!!
715 /* if (dsp_in_exec == 0)
717 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
718 m68k_end_timeslice();
719 dsp_releaseTimeslice();
723 SET16(ram1, offset, data),
724 SET16(ram2, offset, data);
729 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
731 if ((offset & 0x1C) == 0x1C)
734 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
736 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
740 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
742 old_data = (old_data&0xffff0000)|(data&0xffff);
744 old_data = (old_data&0xffff)|((data&0xffff)<<16);
745 DSPWriteLong(offset & 0xffffffc, old_data, who);
750 JaguarWriteWord(offset, data, who);
753 //bool badWrite = false;
754 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
756 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
757 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
759 offset &= 0xFFFFFFFC;
760 /*if (offset == 0xF1BCF4)
762 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
764 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
765 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
767 /*if (offset == 0xF1BE2C)
769 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
771 offset -= DSP_WORK_RAM_BASE;
772 SET32(dsp_ram_8, offset, data);
775 SET32(ram1, offset, data),
776 SET32(ram2, offset, data);
781 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
789 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
791 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
792 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
794 dsp_flag_z = dsp_flags & 0x01;
795 dsp_flag_c = (dsp_flags >> 1) & 0x01;
796 dsp_flag_n = (dsp_flags >> 2) & 0x01;
797 DSPUpdateRegisterBanks();
798 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
799 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
801 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
802 // It can be timed to anything really, anything that writes to L/RTXD at a regular
803 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
804 // interrupt, so that's what we check for here. Just know that this approach
805 // can be easily fooled!
806 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
807 if (data & INT_ENA1) // I2S interrupt
809 int freq = GetCalculatedFrequency();
810 //This happens too often to be useful...
811 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
812 DACSetNewFrequency(freq);
814 else if (data & INT_ENA2) // TIMER 0 interrupt
816 int freq = JERRYGetPIT1Frequency();
817 //This happens too often to be useful...
818 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
819 DACSetNewFrequency(freq);
822 /* if (IMASKCleared) // If IMASK was cleared,
825 WriteLog("DSP: Finished interrupt.\n");
827 DSPHandleIRQs(); // see if any other interrupts need servicing!
832 if (/*4-8, 16*/data & 0x101F0)
833 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
834 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
835 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
836 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
837 /*if (data & 0x00020) // CD BIOS DSP code...
839 //001AC1BA: movea.l #$1AC200, A0
840 //001AC1C0: move.l #$1AC68C, D0
843 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
844 uint32 j = 0xF1B97C;//0x1AC200;
845 while (j <= 0xF1BE08)//0x1AC68C)
848 j += dasmjag(JAGUAR_DSP, buffer, j);
849 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
850 WriteLog("\t%08X: %s\n", oldj, buffer);
857 dsp_matrix_control = data;
860 // According to JTRM, only lines 2-11 are addressable, the rest being
861 // hardwired to $F1Bxxx.
862 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
865 dsp_data_organization = data;
870 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
875 ctrl1[0] = ctrl2[0] = data;
882 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
884 bool wasRunning = DSP_RUNNING;
885 // uint32 dsp_was_running = DSP_RUNNING;
886 // Check for DSP -> CPU interrupt
890 WriteLog("DSP: DSP -> CPU interrupt\n");
893 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
894 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
895 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
897 JERRYSetPendingIRQ(IRQ2_DSP);
898 DSPReleaseTimeslice();
899 m68k_set_irq(2); // Set 68000 IPL 2...
903 // Check for CPU -> DSP interrupt
907 WriteLog("DSP: CPU -> DSP interrupt\n");
909 m68k_end_timeslice();
910 DSPReleaseTimeslice();
911 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
915 if (data & SINGLE_STEP)
917 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
920 // Protect writes to VERSION and the interrupt latches...
921 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
922 dsp_control = (dsp_control & mask) | (data & ~mask);
926 ctrl1[8] = ctrl2[8] = dsp_control;
930 // if dsp wasn't running but is now running
931 // execute a few cycles
932 //This is just plain wrong, wrong, WRONG!
933 #ifndef DSP_SINGLE_STEPPING
934 /* if (!dsp_was_running && DSP_RUNNING)
939 //This is WRONG! !!! FIX !!!
940 if (dsp_control & 0x18)
945 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
947 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
950 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
951 // !!! FIX !!! [DONE]
955 m68k_end_timeslice();
957 DSPReleaseTimeslice();
961 //DSPDumpDisassembly();
969 dsp_div_control = data;
971 // default: // unaligned long read
977 //We don't have to break this up like this! We CAN do 32 bit writes!
978 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
979 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
980 //if (offset > 0xF1FFFF)
982 JaguarWriteLong(offset, data, who);
986 // Update the DSP register file pointers depending on REGPAGE bit
988 void DSPUpdateRegisterBanks(void)
990 int bank = (dsp_flags & REGPAGE);
992 if (dsp_flags & IMASK)
993 bank = 0; // IMASK forces main bank to be bank 0
996 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
998 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1002 // Check for and handle any asserted DSP IRQs
1004 void DSPHandleIRQs(void)
1006 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1009 // Get the active interrupt bits (latches) & interrupt mask (enables)
1010 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1011 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1013 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1016 if (!bits) // Bail if nothing is enabled
1019 int which = 0; // Determine which interrupt
1033 #ifdef DSP_DEBUG_IRQ
1034 WriteLog("DSP: Generating interrupt #%i...", which);
1037 //if (which == 0) doDSPDis = true;
1039 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1040 // directly into the pipeline, it has the side effect of ensuring that the
1041 // instruction interrupted also gets to do its writeback. We simulate that
1043 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1045 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1046 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1048 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1049 scoreboard[pipeline[plPtrWrite].operand2] = false;
1051 //This should be execute (or should it?--not sure now!)
1052 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1053 //and what just executed is now in the Write position...). So why didn't it do the
1054 //writeback into register 0?
1055 #ifdef DSP_DEBUG_IRQ
1056 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1057 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]);
1058 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]);
1059 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]);
1061 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1063 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1065 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1066 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1069 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1070 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1071 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1072 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1074 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1078 #ifndef NEW_SCOREBOARD
1079 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1080 scoreboard[pipeline[plPtrWrite].operand2] = false;
1082 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1083 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1084 if (scoreboard[pipeline[plPtrWrite].operand2])
1085 scoreboard[pipeline[plPtrWrite].operand2]--;
1092 ctrl2[4] = dsp_flags;
1095 DSPUpdateRegisterBanks();
1096 #ifdef DSP_DEBUG_IRQ
1097 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1098 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]);
1101 // subqt #4,r31 ; pre-decrement stack pointer
1102 // move pc,r30 ; address of interrupted code
1103 // store r30,(r31) ; store return address
1110 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1111 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1112 //It missed the place that it was supposed to come back to, so this is WRONG!
1114 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1116 // R -> baz (<- PC points here)
1117 // E -> bar (when it should point here!)
1120 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1121 // which means (assuming they're all 2 bytes long) that the code below will come back on
1122 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1123 // instruction stream...
1125 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1126 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1129 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1133 // movei #service_address,r30 ; pointer to ISR entry
1134 // jump (r30) ; jump to ISR
1136 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1139 ctrl2[0] = regs2[30] = dsp_pc;
1146 // Non-pipelined version...
1148 void DSPHandleIRQsNP(void)
1152 memcpy(dsp_ram_8, ram1, 0x2000);
1153 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1154 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1157 dsp_remain = ctrl1[2];
1158 dsp_modulo = ctrl1[3];
1159 dsp_flags = ctrl1[4];
1160 dsp_matrix_control = ctrl1[5];
1161 dsp_pointer_to_matrix = ctrl1[6];
1162 dsp_data_organization = ctrl1[7];
1163 dsp_control = ctrl1[8];
1164 dsp_div_control = ctrl1[9];
1165 IMASKCleared = ctrl1[10];
1166 dsp_flag_z = ctrl1[11];
1167 dsp_flag_n = ctrl1[12];
1168 dsp_flag_c = ctrl1[13];
1169 DSPUpdateRegisterBanks();
1172 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1175 // Get the active interrupt bits (latches) & interrupt mask (enables)
1176 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1177 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1179 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1182 if (!bits) // Bail if nothing is enabled
1185 int which = 0; // Determine which interrupt
1199 #ifdef DSP_DEBUG_IRQ
1200 WriteLog("DSP: Generating interrupt #%i...", which);
1206 ctrl1[4] = dsp_flags;
1209 DSPUpdateRegisterBanks();
1210 #ifdef DSP_DEBUG_IRQ
1211 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1214 // subqt #4,r31 ; pre-decrement stack pointer
1215 // move pc,r30 ; address of interrupted code
1216 // store r30,(r31) ; store return address
1223 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1226 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1230 // movei #service_address,r30 ; pointer to ISR entry
1231 // jump (r30) ; jump to ISR
1233 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1236 ctrl1[0] = regs1[30] = dsp_pc;
1242 // Set the specified DSP IRQ line to a given state
1244 void DSPSetIRQLine(int irqline, int state)
1246 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1247 uint32 mask = INT_LAT0 << irqline;
1248 dsp_control &= ~mask; // Clear the latch bit
1251 ctrl1[8] = ctrl2[8] = dsp_control;
1257 dsp_control |= mask; // Set the latch bit
1261 ctrl1[8] = ctrl2[8] = dsp_control;
1267 // Not sure if this is correct behavior, but according to JTRM,
1268 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1269 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1270 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1275 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1276 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1277 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1279 dsp_build_branch_condition_table();
1285 dsp_pc = 0x00F1B000;
1286 dsp_acc = 0x00000000;
1287 dsp_remain = 0x00000000;
1288 dsp_modulo = 0xFFFFFFFF;
1289 dsp_flags = 0x00040000;
1290 dsp_matrix_control = 0x00000000;
1291 dsp_pointer_to_matrix = 0x00000000;
1292 dsp_data_organization = 0xFFFFFFFF;
1293 dsp_control = 0x00002000; // Report DSP version 2
1294 dsp_div_control = 0x00000000;
1297 dsp_reg = dsp_reg_bank_0;
1298 dsp_alternate_reg = dsp_reg_bank_1;
1300 for(int i=0; i<32; i++)
1301 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1304 IMASKCleared = false;
1307 memset(dsp_ram_8, 0xFF, 0x2000);
1310 void DSPDumpDisassembly(void)
1314 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1315 uint32 j = 0xF1B000;
1316 while (j <= 0xF1CFFF)
1319 j += dasmjag(JAGUAR_DSP, buffer, j);
1320 WriteLog("\t%08X: %s\n", oldj, buffer);
1324 void DSPDumpRegisters(void)
1326 //Shoud add modulus, etc to dump here...
1327 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1328 WriteLog("\nRegisters bank 0\n");
1329 for(int j=0; j<8; j++)
1331 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1332 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1333 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1334 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1335 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1337 WriteLog("Registers bank 1\n");
1338 for(int j=0; j<8; j++)
1340 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1341 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1342 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1343 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1344 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1351 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1352 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1354 // get the active interrupt bits
1355 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1356 // get the interrupt mask
1357 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1359 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1360 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1361 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1362 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1363 WriteLog("\nRegisters bank 0\n");
1364 for(int j=0; j<8; j++)
1366 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1367 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1368 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1369 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1370 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1372 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;
1385 while (j <= 0xF1BFFF)
1388 j += dasmjag(JAGUAR_DSP, buffer, j);
1389 WriteLog("\t%08X: %s\n", oldj, buffer);
1392 WriteLog("DSP opcodes use:\n");
1395 if (dsp_opcode_use[i])
1396 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1399 // memory_free(dsp_ram_8);
1400 // memory_free(dsp_reg_bank_0);
1401 // memory_free(dsp_reg_bank_1);
1402 if (dsp_branch_condition_table)
1403 free(dsp_branch_condition_table);
1412 // DSP comparison core...
1415 static uint16 lastExec;
1416 void DSPExecComp(int32 cycles)
1418 while (cycles > 0 && DSP_RUNNING)
1420 // Load up vars for non-pipelined core
1421 memcpy(dsp_ram_8, ram1, 0x2000);
1422 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1423 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1426 dsp_remain = ctrl1[2];
1427 dsp_modulo = ctrl1[3];
1428 dsp_flags = ctrl1[4];
1429 dsp_matrix_control = ctrl1[5];
1430 dsp_pointer_to_matrix = ctrl1[6];
1431 dsp_data_organization = ctrl1[7];
1432 dsp_control = ctrl1[8];
1433 dsp_div_control = ctrl1[9];
1434 IMASKCleared = ctrl1[10];
1435 dsp_flag_z = ctrl1[11];
1436 dsp_flag_n = ctrl1[12];
1437 dsp_flag_c = ctrl1[13];
1438 DSPUpdateRegisterBanks();
1440 // Decrement cycles based on non-pipelined core...
1441 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1442 cycles -= dsp_opcode_cycles[instr1 >> 10];
1444 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1445 DSPExec(1); // Do *one* instruction
1448 memcpy(ram1, dsp_ram_8, 0x2000);
1449 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1450 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1453 ctrl1[2] = dsp_remain;
1454 ctrl1[3] = dsp_modulo;
1455 ctrl1[4] = dsp_flags;
1456 ctrl1[5] = dsp_matrix_control;
1457 ctrl1[6] = dsp_pointer_to_matrix;
1458 ctrl1[7] = dsp_data_organization;
1459 ctrl1[8] = dsp_control;
1460 ctrl1[9] = dsp_div_control;
1461 ctrl1[10] = IMASKCleared;
1462 ctrl1[11] = dsp_flag_z;
1463 ctrl1[12] = dsp_flag_n;
1464 ctrl1[13] = dsp_flag_c;
1466 // Load up vars for pipelined core
1467 memcpy(dsp_ram_8, ram2, 0x2000);
1468 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1469 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1472 dsp_remain = ctrl2[2];
1473 dsp_modulo = ctrl2[3];
1474 dsp_flags = ctrl2[4];
1475 dsp_matrix_control = ctrl2[5];
1476 dsp_pointer_to_matrix = ctrl2[6];
1477 dsp_data_organization = ctrl2[7];
1478 dsp_control = ctrl2[8];
1479 dsp_div_control = ctrl2[9];
1480 IMASKCleared = ctrl2[10];
1481 dsp_flag_z = ctrl2[11];
1482 dsp_flag_n = ctrl2[12];
1483 dsp_flag_c = ctrl2[13];
1484 DSPUpdateRegisterBanks();
1486 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1487 DSPExecP2(1); // Do *one* instruction
1490 memcpy(ram2, dsp_ram_8, 0x2000);
1491 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1492 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1495 ctrl2[2] = dsp_remain;
1496 ctrl2[3] = dsp_modulo;
1497 ctrl2[4] = dsp_flags;
1498 ctrl2[5] = dsp_matrix_control;
1499 ctrl2[6] = dsp_pointer_to_matrix;
1500 ctrl2[7] = dsp_data_organization;
1501 ctrl2[8] = dsp_control;
1502 ctrl2[9] = dsp_div_control;
1503 ctrl2[10] = IMASKCleared;
1504 ctrl2[11] = dsp_flag_z;
1505 ctrl2[12] = dsp_flag_n;
1506 ctrl2[13] = dsp_flag_c;
1508 if (instr1 != lastExec)
1510 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1512 // 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));
1513 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1514 // if (ctrl1[0] < ppc) // P ran ahead of NP
1515 //How to test this crap???
1518 DSPExecP2(1); // Do one more instruction
1521 memcpy(ram2, dsp_ram_8, 0x2000);
1522 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1523 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1526 ctrl2[2] = dsp_remain;
1527 ctrl2[3] = dsp_modulo;
1528 ctrl2[4] = dsp_flags;
1529 ctrl2[5] = dsp_matrix_control;
1530 ctrl2[6] = dsp_pointer_to_matrix;
1531 ctrl2[7] = dsp_data_organization;
1532 ctrl2[8] = dsp_control;
1533 ctrl2[9] = dsp_div_control;
1534 ctrl2[10] = IMASKCleared;
1535 ctrl2[11] = dsp_flag_z;
1536 ctrl2[12] = dsp_flag_n;
1537 ctrl2[13] = dsp_flag_c;
1539 // else // NP ran ahead of P
1540 if (instr1 != lastExec) // Must be the other way...
1543 // Load up vars for non-pipelined core
1544 memcpy(dsp_ram_8, ram1, 0x2000);
1545 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1546 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1549 dsp_remain = ctrl1[2];
1550 dsp_modulo = ctrl1[3];
1551 dsp_flags = ctrl1[4];
1552 dsp_matrix_control = ctrl1[5];
1553 dsp_pointer_to_matrix = ctrl1[6];
1554 dsp_data_organization = ctrl1[7];
1555 dsp_control = ctrl1[8];
1556 dsp_div_control = ctrl1[9];
1557 IMASKCleared = ctrl1[10];
1558 dsp_flag_z = ctrl1[11];
1559 dsp_flag_n = ctrl1[12];
1560 dsp_flag_c = ctrl1[13];
1561 DSPUpdateRegisterBanks();
1563 for(int k=0; k<2; k++)
1565 // Decrement cycles based on non-pipelined core...
1566 instr1 = DSPReadWord(dsp_pc, DSP);
1567 cycles -= dsp_opcode_cycles[instr1 >> 10];
1569 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1570 DSPExec(1); // Do *one* instruction
1574 memcpy(ram1, dsp_ram_8, 0x2000);
1575 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1576 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1579 ctrl1[2] = dsp_remain;
1580 ctrl1[3] = dsp_modulo;
1581 ctrl1[4] = dsp_flags;
1582 ctrl1[5] = dsp_matrix_control;
1583 ctrl1[6] = dsp_pointer_to_matrix;
1584 ctrl1[7] = dsp_data_organization;
1585 ctrl1[8] = dsp_control;
1586 ctrl1[9] = dsp_div_control;
1587 ctrl1[10] = IMASKCleared;
1588 ctrl1[11] = dsp_flag_z;
1589 ctrl1[12] = dsp_flag_n;
1590 ctrl1[13] = dsp_flag_c;
1594 if (instr1 != lastExec)
1596 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1598 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1599 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1612 // DSP execution core
1614 //static bool R20Set = false, tripwire = false;
1615 //static uint32 pcQueue[32], ptrPCQ = 0;
1616 void DSPExec(int32 cycles)
1618 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1619 dsp_check_if_i2s_interrupt_needed();*/
1621 #ifdef DSP_SINGLE_STEPPING
1622 if (dsp_control & 0x18)
1625 dsp_control &= ~0x10;
1628 //There is *no* good reason to do this here!
1630 dsp_releaseTimeSlice_flag = 0;
1633 while (cycles > 0 && DSP_RUNNING)
1635 /*extern uint32 totalFrames;
1636 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1637 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1638 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1640 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1643 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1645 if (dsp_pc == 0xF1B092)
1646 doDSPDis = false;//*/
1647 /*if (dsp_pc == 0xF1B140)
1648 doDSPDis = true;//*/
1650 if (IMASKCleared) // If IMASK was cleared,
1652 #ifdef DSP_DEBUG_IRQ
1653 WriteLog("DSP: Finished interrupt.\n");
1655 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1656 IMASKCleared = false;
1661 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1662 for(int i=0; i<80; i+=4)
1663 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1666 /*if (dsp_pc == 0xF1B55E)
1668 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1670 /*if (dsp_pc == 0xF1B7D2) // Start here???
1672 pcQueue[ptrPCQ++] = dsp_pc;
1674 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1675 uint32 index = opcode >> 10;
1676 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1677 dsp_opcode_second_parameter = opcode & 0x1F;
1679 dsp_opcode[index]();
1680 dsp_opcode_use[index]++;
1681 cycles -= dsp_opcode_cycles[index];
1682 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1684 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1687 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1689 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1691 DSPDumpDisassembly();
1694 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1697 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1700 WriteLog("\nBacktrace:\n");
1701 for(int i=0; i<32; i++)
1703 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1704 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1714 // DSP opcode handlers
1717 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1718 // can cause trouble because an interrupt can occur *before* the instruction following the
1719 // jump can execute... !!! FIX !!!
1720 static void dsp_opcode_jump(void)
1723 const char * condition[32] =
1724 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1725 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1726 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1727 "???", "???", "???", "F" };
1729 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);
1732 /* dsp_flag_c=dsp_flag_c?1:0;
1733 dsp_flag_z=dsp_flag_z?1:0;
1734 dsp_flag_n=dsp_flag_n?1:0;*/
1735 // KLUDGE: Used by BRANCH_CONDITION
1736 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1738 if (BRANCH_CONDITION(IMM_2))
1742 WriteLog("Branched!\n");
1744 uint32 delayed_pc = RM;
1746 dsp_pc = delayed_pc;
1751 WriteLog("Branch NOT taken.\n");
1755 static void dsp_opcode_jr(void)
1758 const char * condition[32] =
1759 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1760 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1761 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1762 "???", "???", "???", "F" };
1764 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);
1767 /* dsp_flag_c=dsp_flag_c?1:0;
1768 dsp_flag_z=dsp_flag_z?1:0;
1769 dsp_flag_n=dsp_flag_n?1:0;*/
1770 // KLUDGE: Used by BRANCH_CONDITION
1771 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1773 if (BRANCH_CONDITION(IMM_2))
1777 WriteLog("Branched!\n");
1779 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1780 int32 delayed_pc = dsp_pc + (offset * 2);
1782 dsp_pc = delayed_pc;
1787 WriteLog("Branch NOT taken.\n");
1791 static void dsp_opcode_add(void)
1795 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);
1797 uint32 res = RN + RM;
1798 SET_ZNC_ADD(RN, RM, res);
1802 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);
1806 static void dsp_opcode_addc(void)
1810 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);
1812 uint32 res = RN + RM + dsp_flag_c;
1813 uint32 carry = dsp_flag_c;
1814 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1815 SET_ZNC_ADD(RN + carry, RM, res);
1816 // SET_ZNC_ADD(RN, RM + carry, res);
1820 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);
1824 static void dsp_opcode_addq(void)
1828 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);
1830 uint32 r1 = dsp_convert_zero[IMM_1];
1831 uint32 res = RN + r1;
1832 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1836 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1840 static void dsp_opcode_sub(void)
1844 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);
1846 uint32 res = RN - RM;
1847 SET_ZNC_SUB(RN, RM, res);
1851 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1855 static void dsp_opcode_subc(void)
1859 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);
1861 uint32 res = RN - RM - dsp_flag_c;
1862 uint32 borrow = dsp_flag_c;
1863 SET_ZNC_SUB(RN - borrow, RM, res);
1867 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);
1871 static void dsp_opcode_subq(void)
1875 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);
1877 uint32 r1 = dsp_convert_zero[IMM_1];
1878 uint32 res = RN - r1;
1879 SET_ZNC_SUB(RN, r1, res);
1883 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1887 static void dsp_opcode_cmp(void)
1891 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);
1893 uint32 res = RN - RM;
1894 SET_ZNC_SUB(RN, RM, res);
1897 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1901 static void dsp_opcode_cmpq(void)
1903 static int32 sqtable[32] =
1904 { 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 };
1907 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);
1909 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1910 uint32 res = RN - r1;
1911 SET_ZNC_SUB(RN, r1, res);
1914 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1918 static void dsp_opcode_and(void)
1922 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);
1928 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);
1932 static void dsp_opcode_or(void)
1936 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);
1942 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);
1946 static void dsp_opcode_xor(void)
1950 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);
1956 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);
1960 static void dsp_opcode_not(void)
1964 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);
1970 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1974 static void dsp_opcode_move_pc(void)
1979 static void dsp_opcode_store_r14_indexed(void)
1981 #ifdef DSP_DIS_STORE14I
1983 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));
1985 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1986 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1988 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1992 static void dsp_opcode_store_r15_indexed(void)
1994 #ifdef DSP_DIS_STORE15I
1996 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));
1998 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1999 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2001 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2005 static void dsp_opcode_load_r14_ri(void)
2007 #ifdef DSP_DIS_LOAD14R
2009 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);
2011 #ifdef DSP_CORRECT_ALIGNMENT
2012 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2014 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2016 #ifdef DSP_DIS_LOAD14R
2018 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2022 static void dsp_opcode_load_r15_ri(void)
2024 #ifdef DSP_DIS_LOAD15R
2026 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);
2028 #ifdef DSP_CORRECT_ALIGNMENT
2029 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2031 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2033 #ifdef DSP_DIS_LOAD15R
2035 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2039 static void dsp_opcode_store_r14_ri(void)
2041 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2044 static void dsp_opcode_store_r15_ri(void)
2046 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2049 static void dsp_opcode_nop(void)
2053 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2057 static void dsp_opcode_storeb(void)
2059 #ifdef DSP_DIS_STOREB
2061 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);
2063 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2064 DSPWriteLong(RM, RN & 0xFF, DSP);
2066 JaguarWriteByte(RM, RN, DSP);
2069 static void dsp_opcode_storew(void)
2071 #ifdef DSP_DIS_STOREW
2073 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);
2075 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2076 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2077 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2079 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2081 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2082 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2084 JaguarWriteWord(RM, RN, DSP);
2088 static void dsp_opcode_store(void)
2090 #ifdef DSP_DIS_STORE
2092 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);
2094 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2095 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2097 DSPWriteLong(RM, RN, DSP);
2101 static void dsp_opcode_loadb(void)
2103 #ifdef DSP_DIS_LOADB
2105 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);
2107 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2108 RN = DSPReadLong(RM, DSP) & 0xFF;
2110 RN = JaguarReadByte(RM, DSP);
2111 #ifdef DSP_DIS_LOADB
2113 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2117 static void dsp_opcode_loadw(void)
2119 #ifdef DSP_DIS_LOADW
2121 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);
2123 #ifdef DSP_CORRECT_ALIGNMENT
2124 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2125 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2127 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2129 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2130 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2132 RN = JaguarReadWord(RM, DSP);
2134 #ifdef DSP_DIS_LOADW
2136 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2140 static void dsp_opcode_load(void)
2144 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);
2146 #ifdef DSP_CORRECT_ALIGNMENT
2147 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2149 RN = DSPReadLong(RM, DSP);
2153 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2157 static void dsp_opcode_load_r14_indexed(void)
2159 #ifdef DSP_DIS_LOAD14I
2161 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);
2163 #ifdef DSP_CORRECT_ALIGNMENT
2164 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2166 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2168 #ifdef DSP_DIS_LOAD14I
2170 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2174 static void dsp_opcode_load_r15_indexed(void)
2176 #ifdef DSP_DIS_LOAD15I
2178 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);
2180 #ifdef DSP_CORRECT_ALIGNMENT
2181 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2183 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2185 #ifdef DSP_DIS_LOAD15I
2187 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2191 static void dsp_opcode_movei(void)
2193 #ifdef DSP_DIS_MOVEI
2195 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);
2197 // This instruction is followed by 32-bit value in LSW / MSW format...
2198 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2200 #ifdef DSP_DIS_MOVEI
2202 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2206 static void dsp_opcode_moveta(void)
2208 #ifdef DSP_DIS_MOVETA
2210 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);
2213 #ifdef DSP_DIS_MOVETA
2215 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);
2219 static void dsp_opcode_movefa(void)
2221 #ifdef DSP_DIS_MOVEFA
2223 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);
2226 #ifdef DSP_DIS_MOVEFA
2228 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);
2232 static void dsp_opcode_move(void)
2236 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);
2241 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);
2245 static void dsp_opcode_moveq(void)
2247 #ifdef DSP_DIS_MOVEQ
2249 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);
2252 #ifdef DSP_DIS_MOVEQ
2254 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2258 static void dsp_opcode_resmac(void)
2260 #ifdef DSP_DIS_RESMAC
2262 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));
2264 RN = (uint32)dsp_acc;
2265 #ifdef DSP_DIS_RESMAC
2267 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2271 static void dsp_opcode_imult(void)
2273 #ifdef DSP_DIS_IMULT
2275 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);
2277 RN = (int16)RN * (int16)RM;
2279 #ifdef DSP_DIS_IMULT
2281 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);
2285 static void dsp_opcode_mult(void)
2289 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);
2291 RN = (uint16)RM * (uint16)RN;
2295 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);
2299 static void dsp_opcode_bclr(void)
2303 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);
2305 uint32 res = RN & ~(1 << IMM_1);
2310 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2314 static void dsp_opcode_btst(void)
2318 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);
2320 dsp_flag_z = (~RN >> IMM_1) & 1;
2323 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2327 static void dsp_opcode_bset(void)
2331 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);
2333 uint32 res = RN | (1 << IMM_1);
2338 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2342 static void dsp_opcode_subqt(void)
2344 #ifdef DSP_DIS_SUBQT
2346 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);
2348 RN -= dsp_convert_zero[IMM_1];
2349 #ifdef DSP_DIS_SUBQT
2351 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2355 static void dsp_opcode_addqt(void)
2357 #ifdef DSP_DIS_ADDQT
2359 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);
2361 RN += dsp_convert_zero[IMM_1];
2362 #ifdef DSP_DIS_ADDQT
2364 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2368 static void dsp_opcode_imacn(void)
2370 #ifdef DSP_DIS_IMACN
2372 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);
2374 int32 res = (int16)RM * (int16)RN;
2375 dsp_acc += (int64)res;
2376 //Should we AND the result to fit into 40 bits here???
2377 #ifdef DSP_DIS_IMACN
2379 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));
2383 static void dsp_opcode_mtoi(void)
2385 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2389 static void dsp_opcode_normi(void)
2396 while ((_Rm & 0xffc00000) == 0)
2401 while ((_Rm & 0xff800000) != 0)
2411 static void dsp_opcode_mmult(void)
2413 int count = dsp_matrix_control&0x0f;
2414 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2418 if (!(dsp_matrix_control & 0x10))
2420 for (int i = 0; i < count; i++)
2424 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2426 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2427 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2434 for (int i = 0; i < count; i++)
2438 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2440 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2441 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2446 RN = res = (int32)accum;
2448 //NOTE: The flags are set based upon the last add/multiply done...
2452 static void dsp_opcode_abs(void)
2456 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);
2461 if (_Rn == 0x80000000)
2465 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2466 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2471 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2475 static void dsp_opcode_div(void)
2482 if (dsp_div_control & 1)
2484 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2485 if (dsp_remain&0x80000000)
2487 RN = (((uint64)_Rn) << 16) / _Rm;
2491 dsp_remain = _Rn % _Rm;
2492 if (dsp_remain&0x80000000)
2501 static void dsp_opcode_imultn(void)
2503 #ifdef DSP_DIS_IMULTN
2505 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);
2507 // This is OK, since this multiply won't overflow 32 bits...
2508 int32 res = (int32)((int16)RN * (int16)RM);
2509 dsp_acc = (int64)res;
2511 #ifdef DSP_DIS_IMULTN
2513 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));
2517 static void dsp_opcode_neg(void)
2521 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);
2524 SET_ZNC_SUB(0, RN, res);
2528 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2532 static void dsp_opcode_shlq(void)
2536 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);
2538 int32 r1 = 32 - IMM_1;
2539 uint32 res = RN << r1;
2540 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2544 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2548 static void dsp_opcode_shrq(void)
2552 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);
2554 int32 r1 = dsp_convert_zero[IMM_1];
2555 uint32 res = RN >> r1;
2556 SET_ZN(res); dsp_flag_c = RN & 1;
2560 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2564 static void dsp_opcode_ror(void)
2568 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);
2570 uint32 r1 = RM & 0x1F;
2571 uint32 res = (RN >> r1) | (RN << (32 - r1));
2572 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2576 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);
2580 static void dsp_opcode_rorq(void)
2584 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);
2586 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2588 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2590 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2593 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2597 static void dsp_opcode_sha(void)
2599 int32 sRm=(int32)RM;
2605 if (shift>=32) shift=32;
2606 dsp_flag_c=(_Rn&0x80000000)>>31;
2616 if (shift>=32) shift=32;
2620 _Rn=((int32)_Rn)>>1;
2628 static void dsp_opcode_sharq(void)
2630 #ifdef DSP_DIS_SHARQ
2632 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);
2634 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2635 SET_ZN(res); dsp_flag_c = RN & 0x01;
2637 #ifdef DSP_DIS_SHARQ
2639 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2643 static void dsp_opcode_sh(void)
2645 int32 sRm=(int32)RM;
2650 uint32 shift=(-sRm);
2651 if (shift>=32) shift=32;
2652 dsp_flag_c=(_Rn&0x80000000)>>31;
2662 if (shift>=32) shift=32;
2674 void dsp_opcode_addqmod(void)
2676 #ifdef DSP_DIS_ADDQMOD
2678 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);
2680 uint32 r1 = dsp_convert_zero[IMM_1];
2682 uint32 res = r2 + r1;
2683 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2685 SET_ZNC_ADD(r2, r1, res);
2686 #ifdef DSP_DIS_ADDQMOD
2688 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2692 void dsp_opcode_subqmod(void)
2694 uint32 r1 = dsp_convert_zero[IMM_1];
2696 uint32 res = r2 - r1;
2697 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2700 SET_ZNC_SUB(r2, r1, res);
2703 void dsp_opcode_mirror(void)
2706 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2710 void dsp_opcode_sat32s(void)
2712 int32 r2 = (uint32)RN;
2713 int32 temp = dsp_acc >> 32;
2714 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2719 void dsp_opcode_sat16s(void)
2722 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2728 // New pipelined DSP core
2731 static void DSP_abs(void);
2732 static void DSP_add(void);
2733 static void DSP_addc(void);
2734 static void DSP_addq(void);
2735 static void DSP_addqmod(void);
2736 static void DSP_addqt(void);
2737 static void DSP_and(void);
2738 static void DSP_bclr(void);
2739 static void DSP_bset(void);
2740 static void DSP_btst(void);
2741 static void DSP_cmp(void);
2742 static void DSP_cmpq(void);
2743 static void DSP_div(void);
2744 static void DSP_imacn(void);
2745 static void DSP_imult(void);
2746 static void DSP_imultn(void);
2747 static void DSP_illegal(void);
2748 static void DSP_jr(void);
2749 static void DSP_jump(void);
2750 static void DSP_load(void);
2751 static void DSP_loadb(void);
2752 static void DSP_loadw(void);
2753 static void DSP_load_r14_i(void);
2754 static void DSP_load_r14_r(void);
2755 static void DSP_load_r15_i(void);
2756 static void DSP_load_r15_r(void);
2757 static void DSP_mirror(void);
2758 static void DSP_mmult(void);
2759 static void DSP_move(void);
2760 static void DSP_movefa(void);
2761 static void DSP_movei(void);
2762 static void DSP_movepc(void);
2763 static void DSP_moveq(void);
2764 static void DSP_moveta(void);
2765 static void DSP_mtoi(void);
2766 static void DSP_mult(void);
2767 static void DSP_neg(void);
2768 static void DSP_nop(void);
2769 static void DSP_normi(void);
2770 static void DSP_not(void);
2771 static void DSP_or(void);
2772 static void DSP_resmac(void);
2773 static void DSP_ror(void);
2774 static void DSP_rorq(void);
2775 static void DSP_sat16s(void);
2776 static void DSP_sat32s(void);
2777 static void DSP_sh(void);
2778 static void DSP_sha(void);
2779 static void DSP_sharq(void);
2780 static void DSP_shlq(void);
2781 static void DSP_shrq(void);
2782 static void DSP_store(void);
2783 static void DSP_storeb(void);
2784 static void DSP_storew(void);
2785 static void DSP_store_r14_i(void);
2786 static void DSP_store_r14_r(void);
2787 static void DSP_store_r15_i(void);
2788 static void DSP_store_r15_r(void);
2789 static void DSP_sub(void);
2790 static void DSP_subc(void);
2791 static void DSP_subq(void);
2792 static void DSP_subqmod(void);
2793 static void DSP_subqt(void);
2794 static void DSP_xor(void);
2796 void (* DSPOpcode[64])() =
2798 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2799 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2800 DSP_neg, DSP_and, DSP_or, DSP_xor,
2801 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2803 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2804 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2805 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2806 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2808 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2809 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2810 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2811 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2813 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2814 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2815 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2816 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2819 bool readAffected[64][2] =
2821 { true, true}, { true, true}, {false, true}, {false, true},
2822 { true, true}, { true, true}, {false, true}, {false, true},
2823 {false, true}, { true, true}, { true, true}, { true, true},
2824 {false, true}, {false, true}, {false, true}, {false, true},
2826 { true, true}, { true, true}, { true, true}, {false, true},
2827 { true, true}, { true, true}, {false, true}, { true, true},
2828 {false, true}, {false, true}, { true, true}, {false, true},
2829 { true, true}, {false, true}, { true, true}, {false, true},
2831 {false, true}, {false, true}, { true, false}, {false, false},
2832 { true, false}, {false, false}, {false, false}, { true, false},
2833 { true, false}, { true, false}, {false, true}, { true, false},
2834 { true, false}, { true, true}, { true, true}, { true, true},
2836 {false, true}, { true, true}, { true, true}, {false, true},
2837 { true, false}, { true, false}, { true, true}, { true, false},
2838 { true, false}, {false, false}, { true, false}, { true, false},
2839 { true, true}, { true, true}, {false, false}, {false, true}
2842 bool isLoadStore[65] =
2844 false, false, false, false, false, false, false, false,
2845 false, false, false, false, false, false, false, false,
2847 false, false, false, false, false, false, false, false,
2848 false, false, false, false, false, false, false, false,
2850 false, false, false, false, false, false, false, true,
2851 true, true, false, true, true, true, true, true,
2853 false, true, true, false, false, false, false, false,
2854 false, false, true, true, true, true, false, false, false
2857 void FlushDSPPipeline(void)
2859 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2861 for(int i=0; i<4; i++)
2862 pipeline[i].opcode = PIPELINE_STALL;
2864 for(int i=0; i<32; i++)
2869 // New pipelined DSP execution core
2871 /*void DSPExecP(int32 cycles)
2873 // bool inhibitFetch = false;
2875 dsp_releaseTimeSlice_flag = 0;
2878 while (cycles > 0 && DSP_RUNNING)
2880 WriteLog("DSPExecP: Pipeline status...\n");
2881 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);
2882 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);
2883 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);
2884 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);
2885 WriteLog(" --> Scoreboard: ");
2886 for(int i=0; i<32; i++)
2887 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2889 // Stage 1: Instruction fetch
2890 // if (!inhibitFetch)
2892 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2893 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2894 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2895 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2896 if (pipeline[plPtrFetch].opcode == 38)
2897 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2898 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2901 // inhibitFetch = false;
2902 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2904 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2905 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);
2906 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);
2907 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);
2908 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);
2909 // Stage 2: Read registers
2910 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2911 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2912 if (scoreboard[pipeline[plPtrRead].operand2])
2913 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2914 // We have a hit in the scoreboard, so we have to stall the pipeline...
2916 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2917 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2918 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2919 pipeline[plPtrFetch] = pipeline[plPtrRead];
2920 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2924 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2925 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2926 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2928 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2929 // Shouldn't we be more selective with the register scoreboarding?
2930 // Yes, we should. !!! FIX !!!
2931 scoreboard[pipeline[plPtrRead].operand2] = true;
2932 //Advance PC here??? Yes.
2933 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2934 //This is a mangling of the pipeline stages, but what else to do???
2935 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2938 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2939 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);
2940 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);
2941 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);
2942 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);
2944 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2946 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2947 DSPOpcode[pipeline[plPtrExec].opcode]();
2948 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2949 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2954 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2955 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);
2956 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);
2957 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);
2958 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);
2959 // Stage 4: Write back register
2960 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2962 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2963 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2965 scoreboard[pipeline[plPtrWrite].operand1]
2966 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2969 // Push instructions through the pipeline...
2970 plPtrFetch = (++plPtrFetch) & 0x03;
2971 plPtrRead = (++plPtrRead) & 0x03;
2972 plPtrExec = (++plPtrExec) & 0x03;
2973 plPtrWrite = (++plPtrWrite) & 0x03;
2980 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2982 // Should be fixed now. Another problem is figuring how to do the sequence following
2983 // a branch followed with the JR & JUMP instructions...
2985 // There are two conflicting problems:
2988 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2989 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2990 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2991 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2992 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2993 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2994 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2995 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2996 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2997 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2998 DSP: Finished interrupt.
2999 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3000 ; bank 0 (where is was prepared)!
3001 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3002 F1B252: NOP [NCZ:001]
3005 // The other is when you see this at the end of an IRQ:
3008 JUMP T, (R29) ; R29 = Previous stack + 2
3009 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3011 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3012 ; 1) The STORE goes through the pipeline and is executed/written back
3013 ; 2) The pipeline is flushed
3014 ; 3) The DSP_PC is set to the new address
3015 ; 4) Execution resumes
3017 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3018 ; bank 0 instead of the current bank 1 and so goes astray!
3021 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3022 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3026 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3027 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3028 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3029 If it were done properly, the STORE write back would occur *after* (well, technically,
3030 during) the execution of the the JUMP that follows it.
3034 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3035 F1B08A: NOP [NCZ:001]
3037 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3040 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3043 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3044 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3045 F1B08A: NOP [NCZ:001]
3047 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3050 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3051 DSP: CPU -> DSP interrupt
3052 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3053 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3055 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3058 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3059 F1B006: NOP [NCZ:001]
3061 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3064 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3065 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3068 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3069 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3072 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3073 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3076 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3077 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3080 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3083 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3086 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3087 F1B0FE: NOP [NCZ:000]
3089 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3092 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3095 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3096 F1B138: NOP [NCZ:000]
3098 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3101 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3102 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3103 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3106 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3107 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3110 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3111 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3112 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3114 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3115 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3118 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3119 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3120 DSP: Finished interrupt.
3121 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3123 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3126 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3127 F1B016: NOP [NCZ:001]
3129 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3132 uint32 pcQueue1[0x400];
3134 static uint32 prevR1;
3135 //Let's try a 3 stage pipeline....
3136 //Looks like 3 stage is correct, otherwise bad things happen...
3137 void DSPExecP2(int32 cycles)
3139 dsp_releaseTimeSlice_flag = 0;
3142 while (cycles > 0 && DSP_RUNNING)
3144 /*extern uint32 totalFrames;
3145 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3146 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3147 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3149 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3152 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3154 if (dsp_pc == 0xF1B092)
3155 doDSPDis = false;//*/
3156 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3157 doDSPDis = true;//*/
3158 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3159 doDSPDis = true;//*/
3160 /*if (dsp_pc == 0xF1B0A0)
3161 doDSPDis = true;//*/
3162 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3163 doDSPDis = true;//*/
3164 //Two parter... (not sure how to write this)
3165 //if (dsp_pc == 0xF1B0D2)
3166 // prevR1 = dsp_reg[1];
3168 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3169 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3172 pcQueue1[pcQPtr1++] = dsp_pc;
3175 #ifdef DSP_DEBUG_PL2
3176 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3178 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3183 for(int i=0; i<0x400; i++)
3185 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3186 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3192 if (IMASKCleared) // If IMASK was cleared,
3194 #ifdef DSP_DEBUG_IRQ
3195 WriteLog("DSP: Finished interrupt.\n");
3197 DSPHandleIRQs(); // See if any other interrupts are pending!
3198 IMASKCleared = false;
3201 //if (dsp_flags & REGPAGE)
3202 // WriteLog(" --> REGPAGE has just been set!\n");
3203 #ifdef DSP_DEBUG_PL2
3206 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3207 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]);
3208 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]);
3209 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]);
3210 WriteLog(" --> Scoreboard: ");
3211 for(int i=0; i<32; i++)
3212 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3216 // Stage 1a: Instruction fetch
3217 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3218 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3219 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3220 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3221 if (pipeline[plPtrRead].opcode == 38)
3222 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3223 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3224 #ifdef DSP_DEBUG_PL2
3227 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3228 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3229 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]);
3230 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]);
3231 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]);
3234 // Stage 1b: Read registers
3235 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3236 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3238 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3239 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3240 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3241 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3242 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3243 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3244 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3246 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3247 // We have a hit in the scoreboard, so we have to stall the pipeline...
3248 #ifdef DSP_DEBUG_PL2
3252 WriteLog(" --> Stalling pipeline: ");
3253 if (readAffected[pipeline[plPtrRead].opcode][0])
3254 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3255 if (readAffected[pipeline[plPtrRead].opcode][1])
3256 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3260 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3261 #ifdef DSP_DEBUG_PL2
3266 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3267 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3268 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3270 // Shouldn't we be more selective with the register scoreboarding?
3271 // Yes, we should. !!! FIX !!! Kinda [DONE]
3272 #ifndef NEW_SCOREBOARD
3273 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3275 //Hopefully this will fix the dual MOVEQ # problem...
3276 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3279 //Advance PC here??? Yes.
3280 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3283 #ifdef DSP_DEBUG_PL2
3286 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3287 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]);
3288 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]);
3289 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]);
3293 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3295 #ifdef DSP_DEBUG_PL2
3297 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"));
3301 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3306 lastExec = pipeline[plPtrExec].instruction;
3307 //WriteLog("[lastExec = %04X]\n", lastExec);
3309 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3310 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3311 DSPOpcode[pipeline[plPtrExec].opcode]();
3312 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3316 //Let's not, until we do the stalling correctly...
3317 //But, we gotta while we're doing the comparison core...!
3318 //Or do we? cycles--;
3319 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3320 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3321 //to model this clock cycle behavior correctly...
3322 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3323 //don't affect the reads at stage 1...
3324 #ifdef DSP_DEBUG_STALL
3326 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3330 #ifdef DSP_DEBUG_PL2
3333 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3334 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]);
3335 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]);
3336 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]);
3340 // Stage 3: Write back register/memory address
3341 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3343 /*if (pipeline[plPtrWrite].writebackRegister == 3
3344 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3347 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3350 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3352 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3353 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3356 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3357 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3358 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3359 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3361 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3365 #ifndef NEW_SCOREBOARD
3366 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3367 scoreboard[pipeline[plPtrWrite].operand2] = false;
3369 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3370 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3371 if (scoreboard[pipeline[plPtrWrite].operand2])
3372 scoreboard[pipeline[plPtrWrite].operand2]--;
3376 // Push instructions through the pipeline...
3377 plPtrRead = (++plPtrRead) & 0x03;
3378 plPtrExec = (++plPtrExec) & 0x03;
3379 plPtrWrite = (++plPtrWrite) & 0x03;
3388 //#define DSP_DEBUG_PL3
3389 //Let's try a 2 stage pipeline....
3390 void DSPExecP3(int32 cycles)
3392 dsp_releaseTimeSlice_flag = 0;
3395 while (cycles > 0 && DSP_RUNNING)
3397 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3399 #ifdef DSP_DEBUG_PL3
3400 WriteLog("DSPExecP: Pipeline status...\n");
3401 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]);
3402 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]);
3403 WriteLog(" --> Scoreboard: ");
3404 for(int i=0; i<32; i++)
3405 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3408 // Stage 1a: Instruction fetch
3409 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3410 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3411 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3412 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3413 if (pipeline[plPtrRead].opcode == 38)
3414 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3415 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3416 #ifdef DSP_DEBUG_PL3
3417 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3418 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3419 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]);
3420 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]);
3422 // Stage 1b: Read registers
3423 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3424 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3425 // We have a hit in the scoreboard, so we have to stall the pipeline...
3426 #ifdef DSP_DEBUG_PL3
3428 WriteLog(" --> Stalling pipeline: ");
3429 if (readAffected[pipeline[plPtrRead].opcode][0])
3430 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3431 if (readAffected[pipeline[plPtrRead].opcode][1])
3432 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3435 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3436 #ifdef DSP_DEBUG_PL3
3441 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3442 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3443 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3445 // Shouldn't we be more selective with the register scoreboarding?
3446 // Yes, we should. !!! FIX !!! [Kinda DONE]
3447 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3449 //Advance PC here??? Yes.
3450 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3453 #ifdef DSP_DEBUG_PL3
3454 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3455 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]);
3456 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]);
3458 // Stage 2a: Execute
3459 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3461 #ifdef DSP_DEBUG_PL3
3462 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3464 DSPOpcode[pipeline[plPtrExec].opcode]();
3465 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3466 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3471 #ifdef DSP_DEBUG_PL3
3472 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3473 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]);
3474 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]);
3477 // Stage 2b: Write back register
3478 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3480 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3481 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3483 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3484 scoreboard[pipeline[plPtrExec].operand2] = false;
3487 // Push instructions through the pipeline...
3488 plPtrRead = (++plPtrRead) & 0x03;
3489 plPtrExec = (++plPtrExec) & 0x03;
3496 // DSP pipelined opcode handlers
3499 #define PRM pipeline[plPtrExec].reg1
3500 #define PRN pipeline[plPtrExec].reg2
3501 #define PIMM1 pipeline[plPtrExec].operand1
3502 #define PIMM2 pipeline[plPtrExec].operand2
3503 #define PRES pipeline[plPtrExec].result
3504 #define PWBR pipeline[plPtrExec].writebackRegister
3505 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3506 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3507 #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))
3508 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3510 static void DSP_abs(void)
3514 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);
3518 if (_Rn == 0x80000000)
3522 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3523 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3524 CLR_ZN; SET_Z(PRES);
3528 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3532 static void DSP_add(void)
3536 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);
3538 uint32 res = PRN + PRM;
3539 SET_ZNC_ADD(PRN, PRM, res);
3543 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);
3547 static void DSP_addc(void)
3551 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);
3553 uint32 res = PRN + PRM + dsp_flag_c;
3554 uint32 carry = dsp_flag_c;
3555 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3556 SET_ZNC_ADD(PRN + carry, PRM, res);
3557 // SET_ZNC_ADD(PRN, PRM + carry, res);
3561 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);
3565 static void DSP_addq(void)
3569 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);
3571 uint32 r1 = dsp_convert_zero[PIMM1];
3572 uint32 res = PRN + r1;
3573 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3577 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3581 static void DSP_addqmod(void)
3583 #ifdef DSP_DIS_ADDQMOD
3585 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);
3587 uint32 r1 = dsp_convert_zero[PIMM1];
3589 uint32 res = r2 + r1;
3590 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3592 SET_ZNC_ADD(r2, r1, res);
3593 #ifdef DSP_DIS_ADDQMOD
3595 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3599 static void DSP_addqt(void)
3601 #ifdef DSP_DIS_ADDQT
3603 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);
3605 PRES = PRN + dsp_convert_zero[PIMM1];
3606 #ifdef DSP_DIS_ADDQT
3608 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3612 static void DSP_and(void)
3616 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);
3622 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);
3626 static void DSP_bclr(void)
3630 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);
3632 PRES = PRN & ~(1 << PIMM1);
3636 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3640 static void DSP_bset(void)
3644 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);
3646 PRES = PRN | (1 << PIMM1);
3650 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3654 static void DSP_btst(void)
3658 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);
3660 dsp_flag_z = (~PRN >> PIMM1) & 1;
3664 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3668 static void DSP_cmp(void)
3672 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);
3674 uint32 res = PRN - PRM;
3675 SET_ZNC_SUB(PRN, PRM, res);
3679 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3683 static void DSP_cmpq(void)
3685 static int32 sqtable[32] =
3686 { 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 };
3689 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);
3691 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3692 uint32 res = PRN - r1;
3693 SET_ZNC_SUB(PRN, r1, res);
3697 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3701 static void DSP_div(void)
3703 uint32 _Rm = PRM, _Rn = PRN;
3707 if (dsp_div_control & 1)
3709 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3710 if (dsp_remain & 0x80000000)
3712 PRES = (((uint64)_Rn) << 16) / _Rm;
3716 dsp_remain = _Rn % _Rm;
3717 if (dsp_remain & 0x80000000)
3726 static void DSP_imacn(void)
3728 #ifdef DSP_DIS_IMACN
3730 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);
3732 int32 res = (int16)PRM * (int16)PRN;
3733 dsp_acc += (int64)res;
3734 //Should we AND the result to fit into 40 bits here???
3736 #ifdef DSP_DIS_IMACN
3738 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));
3742 static void DSP_imult(void)
3744 #ifdef DSP_DIS_IMULT
3746 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);
3748 PRES = (int16)PRN * (int16)PRM;
3750 #ifdef DSP_DIS_IMULT
3752 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);
3756 static void DSP_imultn(void)
3758 #ifdef DSP_DIS_IMULTN
3760 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);
3762 // This is OK, since this multiply won't overflow 32 bits...
3763 int32 res = (int32)((int16)PRN * (int16)PRM);
3764 dsp_acc = (int64)res;
3767 #ifdef DSP_DIS_IMULTN
3769 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8)(dsp_acc >> 32), (uint32)(dsp_acc & 0xFFFFFFFF));
3773 static void DSP_illegal(void)
3775 #ifdef DSP_DIS_ILLEGAL
3777 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3782 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3783 // can cause trouble because an interrupt can occur *before* the instruction following the
3784 // jump can execute... !!! FIX !!!
3785 // This can probably be solved by judicious coding in the pipeline execution core...
3786 // And should be fixed now...
3787 static void DSP_jr(void)
3790 const char * condition[32] =
3791 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3792 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3793 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3794 "???", "???", "???", "F" };
3796 //How come this is always off by 2???
3797 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);
3799 // KLUDGE: Used by BRANCH_CONDITION macro
3800 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3802 if (BRANCH_CONDITION(PIMM2))
3806 WriteLog("Branched!\n");
3808 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3809 //Account for pipeline effects...
3810 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3811 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3813 // Now that we've branched, we have to make sure that the following instruction
3814 // is executed atomically with this one and then flush the pipeline before setting
3817 // Step 1: Handle writebacks at stage 3 of pipeline
3818 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3820 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3821 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3823 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3824 scoreboard[pipeline[plPtrWrite].operand2] = false;
3826 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3828 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3830 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3831 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3834 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3835 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3836 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3837 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3839 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3843 #ifndef NEW_SCOREBOARD
3844 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3845 scoreboard[pipeline[plPtrWrite].operand2] = false;
3847 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3848 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3849 if (scoreboard[pipeline[plPtrWrite].operand2])
3850 scoreboard[pipeline[plPtrWrite].operand2]--;
3854 // Step 2: Push instruction through pipeline & execute following instruction
3855 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3856 // we effectively handle the final push of the instruction through the
3857 // pipeline when the new PC takes effect (since when we return, the
3858 // pipeline code will be executing the writeback stage. If we reverse
3859 // the execution order of the pipeline stages, this will no longer be
3861 pipeline[plPtrExec] = pipeline[plPtrRead];
3862 //This is BAD. We need to get that next opcode and execute it!
3863 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3864 // remove this crap.
3865 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3867 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3868 pipeline[plPtrExec].opcode = instruction >> 10;
3869 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3870 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3871 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3872 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3873 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3875 dsp_pc += 2; // For DSP_DIS_* accuracy
3876 DSPOpcode[pipeline[plPtrExec].opcode]();
3877 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3878 pipeline[plPtrWrite] = pipeline[plPtrExec];
3880 // Step 3: Flush pipeline & set new PC
3881 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3888 WriteLog("Branch NOT taken.\n");
3894 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3897 static void DSP_jump(void)
3900 const char * condition[32] =
3901 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3902 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3903 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3904 "???", "???", "???", "F" };
3906 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);
3908 // KLUDGE: Used by BRANCH_CONDITION macro
3909 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3911 if (BRANCH_CONDITION(PIMM2))
3915 WriteLog("Branched!\n");
3917 uint32 PCSave = PRM;
3918 // Now that we've branched, we have to make sure that the following instruction
3919 // is executed atomically with this one and then flush the pipeline before setting
3922 // Step 1: Handle writebacks at stage 3 of pipeline
3923 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3925 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3926 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3928 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3929 scoreboard[pipeline[plPtrWrite].operand2] = false;
3931 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3933 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3935 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3936 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3939 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3940 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3941 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3942 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3944 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3948 #ifndef NEW_SCOREBOARD
3949 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3950 scoreboard[pipeline[plPtrWrite].operand2] = false;
3952 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3953 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3954 if (scoreboard[pipeline[plPtrWrite].operand2])
3955 scoreboard[pipeline[plPtrWrite].operand2]--;
3959 // Step 2: Push instruction through pipeline & execute following instruction
3960 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3961 // we effectively handle the final push of the instruction through the
3962 // pipeline when the new PC takes effect (since when we return, the
3963 // pipeline code will be executing the writeback stage. If we reverse
3964 // the execution order of the pipeline stages, this will no longer be
3966 pipeline[plPtrExec] = pipeline[plPtrRead];
3967 //This is BAD. We need to get that next opcode and execute it!
3968 //Also, same problem in JR!
3969 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3970 // remove this crap.
3971 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3973 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3974 pipeline[plPtrExec].opcode = instruction >> 10;
3975 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3976 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3977 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3978 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3979 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3981 dsp_pc += 2; // For DSP_DIS_* accuracy
3982 DSPOpcode[pipeline[plPtrExec].opcode]();
3983 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3984 pipeline[plPtrWrite] = pipeline[plPtrExec];
3986 // Step 3: Flush pipeline & set new PC
3987 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3994 WriteLog("Branch NOT taken.\n");
4002 static void DSP_load(void)
4006 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);
4008 #ifdef DSP_CORRECT_ALIGNMENT
4009 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4011 PRES = DSPReadLong(PRM, DSP);
4015 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4019 static void DSP_loadb(void)
4021 #ifdef DSP_DIS_LOADB
4023 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);
4025 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4026 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4028 PRES = JaguarReadByte(PRM, DSP);
4029 #ifdef DSP_DIS_LOADB
4031 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4035 static void DSP_loadw(void)
4037 #ifdef DSP_DIS_LOADW
4039 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);
4041 #ifdef DSP_CORRECT_ALIGNMENT
4042 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4043 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4045 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4047 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4048 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4050 PRES = JaguarReadWord(PRM, DSP);
4052 #ifdef DSP_DIS_LOADW
4054 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4058 static void DSP_load_r14_i(void)
4060 #ifdef DSP_DIS_LOAD14I
4062 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);
4064 #ifdef DSP_CORRECT_ALIGNMENT
4065 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4067 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4069 #ifdef DSP_DIS_LOAD14I
4071 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4075 static void DSP_load_r14_r(void)
4077 #ifdef DSP_DIS_LOAD14R
4079 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);
4081 #ifdef DSP_CORRECT_ALIGNMENT
4082 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4084 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4086 #ifdef DSP_DIS_LOAD14R
4088 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4092 static void DSP_load_r15_i(void)
4094 #ifdef DSP_DIS_LOAD15I
4096 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);
4098 #ifdef DSP_CORRECT_ALIGNMENT
4099 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4101 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4103 #ifdef DSP_DIS_LOAD15I
4105 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4109 static void DSP_load_r15_r(void)
4111 #ifdef DSP_DIS_LOAD15R
4113 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);
4115 #ifdef DSP_CORRECT_ALIGNMENT
4116 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4118 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4120 #ifdef DSP_DIS_LOAD15R
4122 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4126 static void DSP_mirror(void)
4129 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4133 static void DSP_mmult(void)
4135 int count = dsp_matrix_control&0x0f;
4136 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4140 if (!(dsp_matrix_control & 0x10))
4142 for (int i = 0; i < count; i++)
4146 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4148 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4149 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4156 for (int i = 0; i < count; i++)
4160 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4162 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4163 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4169 PRES = res = (int32)accum;
4171 //NOTE: The flags are set based upon the last add/multiply done...
4175 static void DSP_move(void)
4179 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);
4184 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);
4188 static void DSP_movefa(void)
4190 #ifdef DSP_DIS_MOVEFA
4192 // 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);
4193 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);
4195 // PRES = ALTERNATE_RM;
4196 PRES = dsp_alternate_reg[PIMM1];
4197 #ifdef DSP_DIS_MOVEFA
4199 // 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);
4200 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);
4204 static void DSP_movei(void)
4206 #ifdef DSP_DIS_MOVEI
4208 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);
4210 // // This instruction is followed by 32-bit value in LSW / MSW format...
4211 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4213 #ifdef DSP_DIS_MOVEI
4215 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4219 static void DSP_movepc(void)
4221 #ifdef DSP_DIS_MOVEPC
4223 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);
4225 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4226 // PRES = dsp_pc - 2;
4227 //Account for pipeline effects...
4228 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4229 #ifdef DSP_DIS_MOVEPC
4231 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4235 static void DSP_moveq(void)
4237 #ifdef DSP_DIS_MOVEQ
4239 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);
4242 #ifdef DSP_DIS_MOVEQ
4244 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4248 static void DSP_moveta(void)
4250 #ifdef DSP_DIS_MOVETA
4252 // 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);
4253 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]);
4255 // ALTERNATE_RN = PRM;
4256 dsp_alternate_reg[PIMM2] = PRM;
4258 #ifdef DSP_DIS_MOVETA
4260 // 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);
4261 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]);
4265 static void DSP_mtoi(void)
4267 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4271 static void DSP_mult(void)
4275 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);
4277 PRES = (uint16)PRM * (uint16)PRN;
4281 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);
4285 static void DSP_neg(void)
4289 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);
4292 SET_ZNC_SUB(0, PRN, res);
4296 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4300 static void DSP_nop(void)
4304 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4309 static void DSP_normi(void)
4316 while ((_Rm & 0xffc00000) == 0)
4321 while ((_Rm & 0xff800000) != 0)
4331 static void DSP_not(void)
4335 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);
4341 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4345 static void DSP_or(void)
4349 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);
4355 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);
4359 static void DSP_resmac(void)
4361 #ifdef DSP_DIS_RESMAC
4363 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));
4365 PRES = (uint32)dsp_acc;
4366 #ifdef DSP_DIS_RESMAC
4368 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4372 static void DSP_ror(void)
4376 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);
4378 uint32 r1 = PRM & 0x1F;
4379 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4380 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4384 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);
4388 static void DSP_rorq(void)
4392 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);
4394 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4396 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4398 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4401 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4405 static void DSP_sat16s(void)
4408 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4413 static void DSP_sat32s(void)
4415 int32 r2 = (uint32)PRN;
4416 int32 temp = dsp_acc >> 32;
4417 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4422 static void DSP_sh(void)
4424 int32 sRm = (int32)PRM;
4429 uint32 shift = -sRm;
4434 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4449 dsp_flag_c = _Rn & 0x1;
4462 static void DSP_sha(void)
4464 int32 sRm = (int32)PRM;
4469 uint32 shift = -sRm;
4474 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4489 dsp_flag_c = _Rn & 0x1;
4493 _Rn = ((int32)_Rn) >> 1;
4502 static void DSP_sharq(void)
4504 #ifdef DSP_DIS_SHARQ
4506 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);
4508 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4509 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4511 #ifdef DSP_DIS_SHARQ
4513 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4517 static void DSP_shlq(void)
4521 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);
4523 int32 r1 = 32 - PIMM1;
4524 uint32 res = PRN << r1;
4525 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4529 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4533 static void DSP_shrq(void)
4537 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);
4539 int32 r1 = dsp_convert_zero[PIMM1];
4540 uint32 res = PRN >> r1;
4541 SET_ZN(res); dsp_flag_c = PRN & 1;
4545 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4549 static void DSP_store(void)
4551 #ifdef DSP_DIS_STORE
4553 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);
4555 // DSPWriteLong(PRM, PRN, DSP);
4557 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4558 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4560 pipeline[plPtrExec].address = PRM;
4562 pipeline[plPtrExec].value = PRN;
4563 pipeline[plPtrExec].type = TYPE_DWORD;
4567 static void DSP_storeb(void)
4569 #ifdef DSP_DIS_STOREB
4571 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);
4573 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4574 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4576 // JaguarWriteByte(PRM, PRN, DSP);
4579 pipeline[plPtrExec].address = PRM;
4581 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4583 pipeline[plPtrExec].value = PRN & 0xFF;
4584 pipeline[plPtrExec].type = TYPE_DWORD;
4588 pipeline[plPtrExec].value = PRN;
4589 pipeline[plPtrExec].type = TYPE_BYTE;
4595 static void DSP_storew(void)
4597 #ifdef DSP_DIS_STOREW
4599 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);
4601 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4602 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4604 // JaguarWriteWord(PRM, PRN, DSP);
4607 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4608 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4610 pipeline[plPtrExec].address = PRM;
4613 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4615 pipeline[plPtrExec].value = PRN & 0xFFFF;
4616 pipeline[plPtrExec].type = TYPE_DWORD;
4620 pipeline[plPtrExec].value = PRN;
4621 pipeline[plPtrExec].type = TYPE_WORD;
4626 static void DSP_store_r14_i(void)
4628 #ifdef DSP_DIS_STORE14I
4630 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));
4632 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4634 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4635 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4637 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4639 pipeline[plPtrExec].value = PRN;
4640 pipeline[plPtrExec].type = TYPE_DWORD;
4644 static void DSP_store_r14_r(void)
4646 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4648 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4649 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4651 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4653 pipeline[plPtrExec].value = PRN;
4654 pipeline[plPtrExec].type = TYPE_DWORD;
4658 static void DSP_store_r15_i(void)
4660 #ifdef DSP_DIS_STORE15I
4662 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));
4664 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4666 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4667 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4669 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4671 pipeline[plPtrExec].value = PRN;
4672 pipeline[plPtrExec].type = TYPE_DWORD;
4676 static void DSP_store_r15_r(void)
4678 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4680 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4681 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4683 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4685 pipeline[plPtrExec].value = PRN;
4686 pipeline[plPtrExec].type = TYPE_DWORD;
4690 static void DSP_sub(void)
4694 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);
4696 uint32 res = PRN - PRM;
4697 SET_ZNC_SUB(PRN, PRM, res);
4701 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);
4705 static void DSP_subc(void)
4709 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);
4711 uint32 res = PRN - PRM - dsp_flag_c;
4712 uint32 borrow = dsp_flag_c;
4713 SET_ZNC_SUB(PRN - borrow, PRM, res);
4717 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);
4721 static void DSP_subq(void)
4725 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);
4727 uint32 r1 = dsp_convert_zero[PIMM1];
4728 uint32 res = PRN - r1;
4729 SET_ZNC_SUB(PRN, r1, res);
4733 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4737 static void DSP_subqmod(void)
4739 uint32 r1 = dsp_convert_zero[PIMM1];
4741 uint32 res = r2 - r1;
4742 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4744 SET_ZNC_SUB(r2, r1, res);
4747 static void DSP_subqt(void)
4749 #ifdef DSP_DIS_SUBQT
4751 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);
4753 PRES = PRN - dsp_convert_zero[PIMM1];
4754 #ifdef DSP_DIS_SUBQT
4756 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4760 static void DSP_xor(void)
4764 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);
4770 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);