4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James L. Hammons
7 // (C) 2010 Underground Software
9 // JLH = James L. Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
18 #include <SDL.h> // Used only for SDL_GetTicks...
29 //#define DSP_DEBUG_IRQ
30 //#define DSP_DEBUG_PL2
31 //#define DSP_DEBUG_STALL
32 //#define DSP_DEBUG_CC
33 #define NEW_SCOREBOARD
35 // Disassembly definitions
41 #define DSP_DIS_ADDQMOD
51 #define DSP_DIS_IMULTN
52 #define DSP_DIS_ILLEGAL
56 #define DSP_DIS_LOAD14I
57 #define DSP_DIS_LOAD14R
58 #define DSP_DIS_LOAD15I
59 #define DSP_DIS_LOAD15R
65 #define DSP_DIS_MOVEFA
66 #define DSP_DIS_MOVEPC // Pipeline only!
67 #define DSP_DIS_MOVETA
73 #define DSP_DIS_RESMAC
80 #define DSP_DIS_STORE14I
81 #define DSP_DIS_STORE15I
82 #define DSP_DIS_STOREB
83 #define DSP_DIS_STOREW
90 bool doDSPDis = false;
91 //bool doDSPDis = true;
126 + load_r15_indexed 284500
128 + store_r15_indexed 47416
132 + load_r14_ri 1229448
135 // Pipeline structures
137 const bool affectsScoreboard[64] =
139 true, true, true, true,
140 true, true, true, true,
141 true, true, true, true,
142 true, false, true, true,
144 true, true, false, true,
145 false, true, true, true,
146 true, true, true, true,
147 true, true, false, false,
149 true, true, true, true,
150 false, true, true, true,
151 true, true, true, true,
152 true, false, false, false,
154 true, false, false, true,
155 false, false, true, true,
156 true, false, true, true,
157 false, false, false, true
163 uint8 opcode, operand1, operand2;
164 uint32 reg1, reg2, areg1, areg2;
166 uint8 writebackRegister;
167 // General memory store...
176 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
177 #ifndef NEW_SCOREBOARD
180 uint8 scoreboard[32];
182 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
183 PipelineStage pipeline[4];
184 bool IMASKCleared = false;
186 // DSP flags (old--have to get rid of this crap)
188 #define CINT0FLAG 0x00200
189 #define CINT1FLAG 0x00400
190 #define CINT2FLAG 0x00800
191 #define CINT3FLAG 0x01000
192 #define CINT4FLAG 0x02000
193 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
194 #define CINT5FLAG 0x20000 /* DSP only */
198 #define ZERO_FLAG 0x00001
199 #define CARRY_FLAG 0x00002
200 #define NEGA_FLAG 0x00004
201 #define IMASK 0x00008
202 #define INT_ENA0 0x00010
203 #define INT_ENA1 0x00020
204 #define INT_ENA2 0x00040
205 #define INT_ENA3 0x00080
206 #define INT_ENA4 0x00100
207 #define INT_CLR0 0x00200
208 #define INT_CLR1 0x00400
209 #define INT_CLR2 0x00800
210 #define INT_CLR3 0x01000
211 #define INT_CLR4 0x02000
212 #define REGPAGE 0x04000
213 #define DMAEN 0x08000
214 #define INT_ENA5 0x10000
215 #define INT_CLR5 0x20000
219 #define DSPGO 0x00001
220 #define CPUINT 0x00002
221 #define DSPINT0 0x00004
222 #define SINGLE_STEP 0x00008
223 #define SINGLE_GO 0x00010
225 #define INT_LAT0 0x00040
226 #define INT_LAT1 0x00080
227 #define INT_LAT2 0x00100
228 #define INT_LAT3 0x00200
229 #define INT_LAT4 0x00400
230 #define BUS_HOG 0x00800
231 #define VERSION 0x0F000
232 #define INT_LAT5 0x10000
234 extern uint32 jaguar_mainRom_crc32;
236 // Is opcode 62 *really* a NOP? Seems like it...
237 static void dsp_opcode_abs(void);
238 static void dsp_opcode_add(void);
239 static void dsp_opcode_addc(void);
240 static void dsp_opcode_addq(void);
241 static void dsp_opcode_addqmod(void);
242 static void dsp_opcode_addqt(void);
243 static void dsp_opcode_and(void);
244 static void dsp_opcode_bclr(void);
245 static void dsp_opcode_bset(void);
246 static void dsp_opcode_btst(void);
247 static void dsp_opcode_cmp(void);
248 static void dsp_opcode_cmpq(void);
249 static void dsp_opcode_div(void);
250 static void dsp_opcode_imacn(void);
251 static void dsp_opcode_imult(void);
252 static void dsp_opcode_imultn(void);
253 static void dsp_opcode_jr(void);
254 static void dsp_opcode_jump(void);
255 static void dsp_opcode_load(void);
256 static void dsp_opcode_loadb(void);
257 static void dsp_opcode_loadw(void);
258 static void dsp_opcode_load_r14_indexed(void);
259 static void dsp_opcode_load_r14_ri(void);
260 static void dsp_opcode_load_r15_indexed(void);
261 static void dsp_opcode_load_r15_ri(void);
262 static void dsp_opcode_mirror(void);
263 static void dsp_opcode_mmult(void);
264 static void dsp_opcode_move(void);
265 static void dsp_opcode_movei(void);
266 static void dsp_opcode_movefa(void);
267 static void dsp_opcode_move_pc(void);
268 static void dsp_opcode_moveq(void);
269 static void dsp_opcode_moveta(void);
270 static void dsp_opcode_mtoi(void);
271 static void dsp_opcode_mult(void);
272 static void dsp_opcode_neg(void);
273 static void dsp_opcode_nop(void);
274 static void dsp_opcode_normi(void);
275 static void dsp_opcode_not(void);
276 static void dsp_opcode_or(void);
277 static void dsp_opcode_resmac(void);
278 static void dsp_opcode_ror(void);
279 static void dsp_opcode_rorq(void);
280 static void dsp_opcode_xor(void);
281 static void dsp_opcode_sat16s(void);
282 static void dsp_opcode_sat32s(void);
283 static void dsp_opcode_sh(void);
284 static void dsp_opcode_sha(void);
285 static void dsp_opcode_sharq(void);
286 static void dsp_opcode_shlq(void);
287 static void dsp_opcode_shrq(void);
288 static void dsp_opcode_store(void);
289 static void dsp_opcode_storeb(void);
290 static void dsp_opcode_storew(void);
291 static void dsp_opcode_store_r14_indexed(void);
292 static void dsp_opcode_store_r14_ri(void);
293 static void dsp_opcode_store_r15_indexed(void);
294 static void dsp_opcode_store_r15_ri(void);
295 static void dsp_opcode_sub(void);
296 static void dsp_opcode_subc(void);
297 static void dsp_opcode_subq(void);
298 static void dsp_opcode_subqmod(void);
299 static void dsp_opcode_subqt(void);
301 uint8 dsp_opcode_cycles[64] =
303 3, 3, 3, 3, 3, 3, 3, 3,
304 3, 3, 3, 3, 3, 3, 3, 3,
305 3, 3, 1, 3, 1, 18, 3, 3,
306 3, 3, 3, 3, 3, 3, 3, 3,
307 3, 3, 2, 2, 2, 2, 3, 4,
308 5, 4, 5, 6, 6, 1, 1, 1,
309 1, 2, 2, 2, 1, 1, 9, 3,
310 3, 1, 6, 6, 2, 2, 3, 3
312 //Here's a QnD kludge...
313 //This is wrong, wrong, WRONG, but it seems to work for the time being...
314 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
315 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
316 /*uint8 dsp_opcode_cycles[64] =
318 1, 1, 1, 1, 1, 1, 1, 1,
319 1, 1, 1, 1, 1, 1, 1, 1,
320 1, 1, 1, 1, 1, 9, 1, 1,
321 1, 1, 1, 1, 1, 1, 1, 1,
322 1, 1, 1, 1, 1, 1, 1, 2,
323 2, 2, 2, 3, 3, 1, 1, 1,
324 1, 1, 1, 1, 1, 1, 4, 1,
325 1, 1, 3, 3, 1, 1, 1, 1
328 void (* dsp_opcode[64])() =
330 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
331 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
332 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
333 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
334 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
335 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
336 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
337 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
338 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
339 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
340 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
341 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
342 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
343 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
344 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
345 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
348 uint32 dsp_opcode_use[65];
350 const char * dsp_opcode_str[65]=
352 "add", "addc", "addq", "addqt",
353 "sub", "subc", "subq", "subqt",
354 "neg", "and", "or", "xor",
355 "not", "btst", "bset", "bclr",
356 "mult", "imult", "imultn", "resmac",
357 "imacn", "div", "abs", "sh",
358 "shlq", "shrq", "sha", "sharq",
359 "ror", "rorq", "cmp", "cmpq",
360 "subqmod", "sat16s", "move", "moveq",
361 "moveta", "movefa", "movei", "loadb",
362 "loadw", "load", "sat32s", "load_r14_indexed",
363 "load_r15_indexed", "storeb", "storew", "store",
364 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
365 "jump", "jr", "mmult", "mtoi",
366 "normi", "nop", "load_r14_ri", "load_r15_ri",
367 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
372 static uint64 dsp_acc; // 40 bit register, NOT 32!
373 static uint32 dsp_remain;
374 static uint32 dsp_modulo;
375 static uint32 dsp_flags;
376 static uint32 dsp_matrix_control;
377 static uint32 dsp_pointer_to_matrix;
378 static uint32 dsp_data_organization;
380 static uint32 dsp_div_control;
381 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
382 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
383 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
385 static uint32 dsp_opcode_first_parameter;
386 static uint32 dsp_opcode_second_parameter;
388 #define DSP_RUNNING (dsp_control & 0x01)
390 #define RM dsp_reg[dsp_opcode_first_parameter]
391 #define RN dsp_reg[dsp_opcode_second_parameter]
392 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
393 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
394 #define IMM_1 dsp_opcode_first_parameter
395 #define IMM_2 dsp_opcode_second_parameter
397 #define CLR_Z (dsp_flag_z = 0)
398 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
399 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
400 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
401 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
402 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
403 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
404 #define SET_ZN(r) SET_N(r); SET_Z(r)
405 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
406 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
408 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 };
409 uint8 * dsp_branch_condition_table = NULL;
410 static uint16 * mirror_table = NULL;
411 static uint8 dsp_ram_8[0x2000];
413 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
415 static uint32 dsp_in_exec = 0;
416 static uint32 dsp_releaseTimeSlice_flag = 0;
421 // Comparison core vars (used only for core comparison! :-)
422 static uint64 count = 0;
423 static uint8 ram1[0x2000], ram2[0x2000];
424 static uint32 regs1[64], regs2[64];
425 static uint32 ctrl1[14], ctrl2[14];
428 // Private function prototypes
430 void DSPDumpRegisters(void);
431 void DSPDumpDisassembly(void);
432 void FlushDSPPipeline(void);
435 void dsp_reset_stats(void)
437 for(int i=0; i<65; i++)
438 dsp_opcode_use[i] = 0;
441 void DSPReleaseTimeslice(void)
443 //This does absolutely nothing!!! !!! FIX !!!
444 dsp_releaseTimeSlice_flag = 1;
447 void dsp_build_branch_condition_table(void)
449 // Allocate the mirror table
451 mirror_table = (uint16 *)malloc(65536 * sizeof(uint16));
453 // Fill in the mirror table
455 for(int i=0; i<65536; i++)
456 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
457 ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
458 ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
459 ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
460 ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
461 ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
462 ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
463 ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
465 if (!dsp_branch_condition_table)
467 dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8));
469 // Fill in the condition table
470 if (dsp_branch_condition_table)
472 for(int i=0; i<8; i++)
474 for(int j=0; j<32; j++)
481 if (!(i & ZERO_FLAG))
484 if (i & (CARRY_FLAG << (j >> 4)))
487 if (!(i & (CARRY_FLAG << (j >> 4))))
489 dsp_branch_condition_table[i * 32 + j] = result;
496 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
498 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
499 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
501 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
504 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
506 if (offset==0xF1CFE0)
509 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
510 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
512 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
514 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
516 if ((offset&0x03)==0)
519 if ((offset&0x03)==1)
520 return((data>>16)&0xff);
522 if ((offset&0x03)==2)
523 return((data>>8)&0xff);
525 if ((offset&0x03)==3)
529 return JaguarReadByte(offset, who);
532 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
534 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
535 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
537 offset &= 0xFFFFFFFE;
539 /* if (jaguar_mainRom_crc32==0xa74a97cd)
541 if (offset==0xF1A114) return(0x0000);
542 if (offset==0xF1A116) return(0x0000);
543 if (offset==0xF1B000) return(0x1234);
544 if (offset==0xF1B002) return(0x5678);
547 if (jaguar_mainRom_crc32==0x7ae20823)
549 if (offset==0xF1B9D8) return(0x0000);
550 if (offset==0xF1B9Da) return(0x0000);
551 if (offset==0xF1B2C0) return(0x0000);
552 if (offset==0xF1B2C2) return(0x0000);
555 // pour permettre � wolfenstein 3d de tourner sans le dsp
556 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
560 // pour permettre � nba jam de tourner sans le dsp
561 /* if (jaguar_mainRom_crc32==0x4faddb18)
563 if (offset==0xf1b2c0) return(0);
564 if (offset==0xf1b2c2) return(0);
565 if (offset==0xf1b240) return(0);
566 if (offset==0xf1b242) return(0);
567 if (offset==0xF1B340) return(0);
568 if (offset==0xF1B342) return(0);
569 if (offset==0xF1BAD8) return(0);
570 if (offset==0xF1BADA) return(0);
571 if (offset==0xF1B040) return(0);
572 if (offset==0xF1B042) return(0);
573 if (offset==0xF1B0C0) return(0);
574 if (offset==0xF1B0C2) return(0);
575 if (offset==0xF1B140) return(0);
576 if (offset==0xF1B142) return(0);
577 if (offset==0xF1B1C0) return(0);
578 if (offset==0xF1B1C2) return(0);
581 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
583 offset -= DSP_WORK_RAM_BASE;
584 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
586 return GET16(dsp_ram_8, offset);
588 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
590 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
593 return data & 0xFFFF;
598 return JaguarReadWord(offset, who);
601 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
603 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
604 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
607 offset &= 0xFFFFFFFC;
608 /*if (offset == 0xF1BCF4)
610 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));
611 DSPDumpDisassembly();
613 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
615 offset -= DSP_WORK_RAM_BASE;
616 return GET32(dsp_ram_8, offset);
618 //NOTE: Didn't return DSP_ACCUM!!!
619 //Mebbe it's not 'spose to! Yes, it is!
620 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
625 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
626 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
627 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
629 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
630 return dsp_flags & 0xFFFFC1FF;
631 case 0x04: return dsp_matrix_control;
632 case 0x08: return dsp_pointer_to_matrix;
633 case 0x0C: return dsp_data_organization;
634 case 0x10: return dsp_pc;
635 case 0x14: return dsp_control;
636 case 0x18: return dsp_modulo;
637 case 0x1C: return dsp_remain;
639 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
641 // unaligned long read-- !!! FIX !!!
645 return JaguarReadLong(offset, who);
648 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
650 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
651 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
653 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
655 offset -= DSP_WORK_RAM_BASE;
656 dsp_ram_8[offset] = data;
657 //This is rather stupid! !!! FIX !!!
658 /* if (dsp_in_exec == 0)
660 m68k_end_timeslice();
661 gpu_releaseTimeslice();
665 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
667 uint32 reg = offset & 0x1C;
668 int bytenum = offset & 0x03;
670 if ((reg >= 0x1C) && (reg <= 0x1F))
671 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
674 //This looks funky. !!! FIX !!!
675 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
676 bytenum = 3 - bytenum; // convention motorola !!!
677 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
678 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
682 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
683 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
684 JaguarWriteByte(offset, data, who);
687 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
689 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
690 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
691 offset &= 0xFFFFFFFE;
692 /*if (offset == 0xF1BCF4)
694 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
696 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
697 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
699 /*if (offset == 0xF1B2F4)
701 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
703 offset -= DSP_WORK_RAM_BASE;
704 dsp_ram_8[offset] = data >> 8;
705 dsp_ram_8[offset+1] = data & 0xFF;
706 //This is rather stupid! !!! FIX !!!
707 /* if (dsp_in_exec == 0)
709 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
710 m68k_end_timeslice();
711 gpu_releaseTimeslice();
715 SET16(ram1, offset, data),
716 SET16(ram2, offset, data);
721 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
723 if ((offset & 0x1C) == 0x1C)
726 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
728 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
732 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
734 old_data = (old_data&0xffff0000)|(data&0xffff);
736 old_data = (old_data&0xffff)|((data&0xffff)<<16);
737 DSPWriteLong(offset & 0xffffffc, old_data, who);
742 JaguarWriteWord(offset, data, who);
745 //bool badWrite = false;
746 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
748 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
749 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
751 offset &= 0xFFFFFFFC;
752 /*if (offset == 0xF1BCF4)
754 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
756 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
757 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
759 /*if (offset == 0xF1BE2C)
761 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
763 offset -= DSP_WORK_RAM_BASE;
764 SET32(dsp_ram_8, offset, data);
767 SET32(ram1, offset, data),
768 SET32(ram2, offset, data);
773 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
781 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
783 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
784 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
786 dsp_flag_z = dsp_flags & 0x01;
787 dsp_flag_c = (dsp_flags >> 1) & 0x01;
788 dsp_flag_n = (dsp_flags >> 2) & 0x01;
789 DSPUpdateRegisterBanks();
790 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
791 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
792 /* if (IMASKCleared) // If IMASK was cleared,
795 WriteLog("DSP: Finished interrupt.\n");
797 DSPHandleIRQs(); // see if any other interrupts need servicing!
802 if (/*4-8, 16*/data & 0x101F0)
803 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
804 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
805 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
806 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
807 /*if (data & 0x00020) // CD BIOS DSP code...
809 //001AC1BA: movea.l #$1AC200, A0
810 //001AC1C0: move.l #$1AC68C, D0
813 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
814 uint32 j = 0xF1B97C;//0x1AC200;
815 while (j <= 0xF1BE08)//0x1AC68C)
818 j += dasmjag(JAGUAR_DSP, buffer, j);
819 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
820 WriteLog("\t%08X: %s\n", oldj, buffer);
827 dsp_matrix_control = data;
830 // According to JTRM, only lines 2-11 are addressable, the rest being
831 // hardwired to $F1Bxxx.
832 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
835 dsp_data_organization = data;
840 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
845 ctrl1[0] = ctrl2[0] = data;
852 WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
854 bool wasRunning = DSP_RUNNING;
855 // uint32 dsp_was_running = DSP_RUNNING;
856 // Check for DSP -> CPU interrupt
860 WriteLog("DSP: DSP -> CPU interrupt\n");
863 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility?
864 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
866 JERRYSetPendingIRQ(IRQ2_DSP);
867 DSPReleaseTimeslice();
868 m68k_set_irq(7); // Set 68000 NMI...
872 // Check for CPU -> DSP interrupt
876 WriteLog("DSP: CPU -> DSP interrupt\n");
878 m68k_end_timeslice();
879 GPUReleaseTimeslice();
880 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
884 if (data & SINGLE_STEP)
886 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
889 // Protect writes to VERSION and the interrupt latches...
890 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
891 dsp_control = (dsp_control & mask) | (data & ~mask);
895 ctrl1[8] = ctrl2[8] = dsp_control;
899 // if dsp wasn't running but is now running
900 // execute a few cycles
901 //This is just plain wrong, wrong, WRONG!
902 #ifndef DSP_SINGLE_STEPPING
903 /* if (!dsp_was_running && DSP_RUNNING)
908 //This is WRONG! !!! FIX !!!
909 if (dsp_control & 0x18)
914 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
916 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
919 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
920 // !!! FIX !!! [DONE]
924 m68k_end_timeslice();
926 GPUReleaseTimeslice();
930 //DSPDumpDisassembly();
938 dsp_div_control = data;
940 // default: // unaligned long read
946 //We don't have to break this up like this! We CAN do 32 bit writes!
947 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
948 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
949 //if (offset > 0xF1FFFF)
951 JaguarWriteLong(offset, data, who);
955 // Update the DSP register file pointers depending on REGPAGE bit
957 void DSPUpdateRegisterBanks(void)
959 int bank = (dsp_flags & REGPAGE);
961 if (dsp_flags & IMASK)
962 bank = 0; // IMASK forces main bank to be bank 0
965 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
967 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
971 // Check for and handle any asserted DSP IRQs
973 void DSPHandleIRQs(void)
975 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
978 // Get the active interrupt bits (latches) & interrupt mask (enables)
979 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
980 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
982 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
985 if (!bits) // Bail if nothing is enabled
988 int which = 0; // Determine which interrupt
1002 #ifdef DSP_DEBUG_IRQ
1003 WriteLog("DSP: Generating interrupt #%i...", which);
1006 //if (which == 0) doDSPDis = true;
1008 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1009 // directly into the pipeline, it has the side effect of ensuring that the
1010 // instruction interrupted also gets to do its writeback. We simulate that
1012 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1014 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1015 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1017 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1018 scoreboard[pipeline[plPtrWrite].operand2] = false;
1020 //This should be execute (or should it?--not sure now!)
1021 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1022 //and what just executed is now in the Write position...). So why didn't it do the
1023 //writeback into register 0?
1024 #ifdef DSP_DEBUG_IRQ
1025 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1026 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]);
1027 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]);
1028 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]);
1030 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1032 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1034 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1035 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1038 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1039 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1040 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1041 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1043 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1047 #ifndef NEW_SCOREBOARD
1048 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1049 scoreboard[pipeline[plPtrWrite].operand2] = false;
1051 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1052 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1053 if (scoreboard[pipeline[plPtrWrite].operand2])
1054 scoreboard[pipeline[plPtrWrite].operand2]--;
1061 ctrl2[4] = dsp_flags;
1064 DSPUpdateRegisterBanks();
1065 #ifdef DSP_DEBUG_IRQ
1066 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1067 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]);
1070 // subqt #4,r31 ; pre-decrement stack pointer
1071 // move pc,r30 ; address of interrupted code
1072 // store r30,(r31) ; store return address
1079 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1080 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1081 //It missed the place that it was supposed to come back to, so this is WRONG!
1083 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1085 // R -> baz (<- PC points here)
1086 // E -> bar (when it should point here!)
1089 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1090 // which means (assuming they're all 2 bytes long) that the code below will come back on
1091 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1092 // instruction stream...
1094 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1095 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1098 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1102 // movei #service_address,r30 ; pointer to ISR entry
1103 // jump (r30) ; jump to ISR
1105 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1108 ctrl2[0] = regs2[30] = dsp_pc;
1115 // Non-pipelined version...
1117 void DSPHandleIRQsNP(void)
1121 memcpy(dsp_ram_8, ram1, 0x2000);
1122 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1123 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1126 dsp_remain = ctrl1[2];
1127 dsp_modulo = ctrl1[3];
1128 dsp_flags = ctrl1[4];
1129 dsp_matrix_control = ctrl1[5];
1130 dsp_pointer_to_matrix = ctrl1[6];
1131 dsp_data_organization = ctrl1[7];
1132 dsp_control = ctrl1[8];
1133 dsp_div_control = ctrl1[9];
1134 IMASKCleared = ctrl1[10];
1135 dsp_flag_z = ctrl1[11];
1136 dsp_flag_n = ctrl1[12];
1137 dsp_flag_c = ctrl1[13];
1138 DSPUpdateRegisterBanks();
1141 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1144 // Get the active interrupt bits (latches) & interrupt mask (enables)
1145 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1146 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1148 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1151 if (!bits) // Bail if nothing is enabled
1154 int which = 0; // Determine which interrupt
1168 #ifdef DSP_DEBUG_IRQ
1169 WriteLog("DSP: Generating interrupt #%i...", which);
1175 ctrl1[4] = dsp_flags;
1178 DSPUpdateRegisterBanks();
1179 #ifdef DSP_DEBUG_IRQ
1180 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1183 // subqt #4,r31 ; pre-decrement stack pointer
1184 // move pc,r30 ; address of interrupted code
1185 // store r30,(r31) ; store return address
1192 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1195 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1199 // movei #service_address,r30 ; pointer to ISR entry
1200 // jump (r30) ; jump to ISR
1202 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1205 ctrl1[0] = regs1[30] = dsp_pc;
1211 // Set the specified DSP IRQ line to a given state
1213 void DSPSetIRQLine(int irqline, int state)
1215 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1216 uint32 mask = INT_LAT0 << irqline;
1217 dsp_control &= ~mask; // Clear the latch bit
1220 ctrl1[8] = ctrl2[8] = dsp_control;
1226 dsp_control |= mask; // Set the latch bit
1230 ctrl1[8] = ctrl2[8] = dsp_control;
1236 // Not sure if this is correct behavior, but according to JTRM,
1237 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1238 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1239 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1244 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1245 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1246 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1248 dsp_build_branch_condition_table();
1254 dsp_pc = 0x00F1B000;
1255 dsp_acc = 0x00000000;
1256 dsp_remain = 0x00000000;
1257 dsp_modulo = 0xFFFFFFFF;
1258 dsp_flags = 0x00040000;
1259 dsp_matrix_control = 0x00000000;
1260 dsp_pointer_to_matrix = 0x00000000;
1261 dsp_data_organization = 0xFFFFFFFF;
1262 dsp_control = 0x00002000; // Report DSP version 2
1263 dsp_div_control = 0x00000000;
1266 dsp_reg = dsp_reg_bank_0;
1267 dsp_alternate_reg = dsp_reg_bank_1;
1269 for(int i=0; i<32; i++)
1270 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1273 IMASKCleared = false;
1276 memset(dsp_ram_8, 0xFF, 0x2000);
1279 void DSPDumpDisassembly(void)
1283 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1284 uint32 j = 0xF1B000;
1285 while (j <= 0xF1CFFF)
1288 j += dasmjag(JAGUAR_DSP, buffer, j);
1289 WriteLog("\t%08X: %s\n", oldj, buffer);
1293 void DSPDumpRegisters(void)
1295 //Shoud add modulus, etc to dump here...
1296 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1297 WriteLog("\nRegisters bank 0\n");
1298 for(int j=0; j<8; j++)
1300 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1301 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1302 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1303 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1304 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1306 WriteLog("Registers bank 1\n");
1307 for(int j=0; j<8; j++)
1309 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1310 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1311 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1312 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1313 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1320 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1321 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1323 // get the active interrupt bits
1324 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1325 // get the interrupt mask
1326 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1328 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1329 WriteLog("\nRegisters bank 0\n");
1330 for(int j=0; j<8; j++)
1332 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1333 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1334 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1335 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1336 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1338 WriteLog("\nRegisters bank 1\n");
1341 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1342 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1343 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1344 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1345 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1349 static char buffer[512];
1350 j = DSP_WORK_RAM_BASE;
1351 while (j <= 0xF1BFFF)
1354 j += dasmjag(JAGUAR_DSP, buffer, j);
1355 WriteLog("\t%08X: %s\n", oldj, buffer);
1358 WriteLog("DSP opcodes use:\n");
1361 if (dsp_opcode_use[i])
1362 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1365 // memory_free(dsp_ram_8);
1366 // memory_free(dsp_reg_bank_0);
1367 // memory_free(dsp_reg_bank_1);
1368 if (dsp_branch_condition_table)
1369 free(dsp_branch_condition_table);
1378 // DSP comparison core...
1381 static uint16 lastExec;
1382 void DSPExecComp(int32 cycles)
1384 while (cycles > 0 && DSP_RUNNING)
1386 // Load up vars for non-pipelined core
1387 memcpy(dsp_ram_8, ram1, 0x2000);
1388 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1389 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1392 dsp_remain = ctrl1[2];
1393 dsp_modulo = ctrl1[3];
1394 dsp_flags = ctrl1[4];
1395 dsp_matrix_control = ctrl1[5];
1396 dsp_pointer_to_matrix = ctrl1[6];
1397 dsp_data_organization = ctrl1[7];
1398 dsp_control = ctrl1[8];
1399 dsp_div_control = ctrl1[9];
1400 IMASKCleared = ctrl1[10];
1401 dsp_flag_z = ctrl1[11];
1402 dsp_flag_n = ctrl1[12];
1403 dsp_flag_c = ctrl1[13];
1404 DSPUpdateRegisterBanks();
1406 // Decrement cycles based on non-pipelined core...
1407 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1408 cycles -= dsp_opcode_cycles[instr1 >> 10];
1410 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1411 DSPExec(1); // Do *one* instruction
1414 memcpy(ram1, dsp_ram_8, 0x2000);
1415 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1416 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1419 ctrl1[2] = dsp_remain;
1420 ctrl1[3] = dsp_modulo;
1421 ctrl1[4] = dsp_flags;
1422 ctrl1[5] = dsp_matrix_control;
1423 ctrl1[6] = dsp_pointer_to_matrix;
1424 ctrl1[7] = dsp_data_organization;
1425 ctrl1[8] = dsp_control;
1426 ctrl1[9] = dsp_div_control;
1427 ctrl1[10] = IMASKCleared;
1428 ctrl1[11] = dsp_flag_z;
1429 ctrl1[12] = dsp_flag_n;
1430 ctrl1[13] = dsp_flag_c;
1432 // Load up vars for pipelined core
1433 memcpy(dsp_ram_8, ram2, 0x2000);
1434 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1435 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1438 dsp_remain = ctrl2[2];
1439 dsp_modulo = ctrl2[3];
1440 dsp_flags = ctrl2[4];
1441 dsp_matrix_control = ctrl2[5];
1442 dsp_pointer_to_matrix = ctrl2[6];
1443 dsp_data_organization = ctrl2[7];
1444 dsp_control = ctrl2[8];
1445 dsp_div_control = ctrl2[9];
1446 IMASKCleared = ctrl2[10];
1447 dsp_flag_z = ctrl2[11];
1448 dsp_flag_n = ctrl2[12];
1449 dsp_flag_c = ctrl2[13];
1450 DSPUpdateRegisterBanks();
1452 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1453 DSPExecP2(1); // Do *one* instruction
1456 memcpy(ram2, dsp_ram_8, 0x2000);
1457 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1458 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1461 ctrl2[2] = dsp_remain;
1462 ctrl2[3] = dsp_modulo;
1463 ctrl2[4] = dsp_flags;
1464 ctrl2[5] = dsp_matrix_control;
1465 ctrl2[6] = dsp_pointer_to_matrix;
1466 ctrl2[7] = dsp_data_organization;
1467 ctrl2[8] = dsp_control;
1468 ctrl2[9] = dsp_div_control;
1469 ctrl2[10] = IMASKCleared;
1470 ctrl2[11] = dsp_flag_z;
1471 ctrl2[12] = dsp_flag_n;
1472 ctrl2[13] = dsp_flag_c;
1474 if (instr1 != lastExec)
1476 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1478 // 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));
1479 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1480 // if (ctrl1[0] < ppc) // P ran ahead of NP
1481 //How to test this crap???
1484 DSPExecP2(1); // Do one more instruction
1487 memcpy(ram2, dsp_ram_8, 0x2000);
1488 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1489 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1492 ctrl2[2] = dsp_remain;
1493 ctrl2[3] = dsp_modulo;
1494 ctrl2[4] = dsp_flags;
1495 ctrl2[5] = dsp_matrix_control;
1496 ctrl2[6] = dsp_pointer_to_matrix;
1497 ctrl2[7] = dsp_data_organization;
1498 ctrl2[8] = dsp_control;
1499 ctrl2[9] = dsp_div_control;
1500 ctrl2[10] = IMASKCleared;
1501 ctrl2[11] = dsp_flag_z;
1502 ctrl2[12] = dsp_flag_n;
1503 ctrl2[13] = dsp_flag_c;
1505 // else // NP ran ahead of P
1506 if (instr1 != lastExec) // Must be the other way...
1509 // Load up vars for non-pipelined core
1510 memcpy(dsp_ram_8, ram1, 0x2000);
1511 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1512 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1515 dsp_remain = ctrl1[2];
1516 dsp_modulo = ctrl1[3];
1517 dsp_flags = ctrl1[4];
1518 dsp_matrix_control = ctrl1[5];
1519 dsp_pointer_to_matrix = ctrl1[6];
1520 dsp_data_organization = ctrl1[7];
1521 dsp_control = ctrl1[8];
1522 dsp_div_control = ctrl1[9];
1523 IMASKCleared = ctrl1[10];
1524 dsp_flag_z = ctrl1[11];
1525 dsp_flag_n = ctrl1[12];
1526 dsp_flag_c = ctrl1[13];
1527 DSPUpdateRegisterBanks();
1529 for(int k=0; k<2; k++)
1531 // Decrement cycles based on non-pipelined core...
1532 instr1 = DSPReadWord(dsp_pc, DSP);
1533 cycles -= dsp_opcode_cycles[instr1 >> 10];
1535 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1536 DSPExec(1); // Do *one* instruction
1540 memcpy(ram1, dsp_ram_8, 0x2000);
1541 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1542 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1545 ctrl1[2] = dsp_remain;
1546 ctrl1[3] = dsp_modulo;
1547 ctrl1[4] = dsp_flags;
1548 ctrl1[5] = dsp_matrix_control;
1549 ctrl1[6] = dsp_pointer_to_matrix;
1550 ctrl1[7] = dsp_data_organization;
1551 ctrl1[8] = dsp_control;
1552 ctrl1[9] = dsp_div_control;
1553 ctrl1[10] = IMASKCleared;
1554 ctrl1[11] = dsp_flag_z;
1555 ctrl1[12] = dsp_flag_n;
1556 ctrl1[13] = dsp_flag_c;
1560 if (instr1 != lastExec)
1562 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1564 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1565 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1578 // DSP execution core
1580 //static bool R20Set = false, tripwire = false;
1581 //static uint32 pcQueue[32], ptrPCQ = 0;
1582 void DSPExec(int32 cycles)
1584 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1585 dsp_check_if_i2s_interrupt_needed();*/
1587 #ifdef DSP_SINGLE_STEPPING
1588 if (dsp_control & 0x18)
1591 dsp_control &= ~0x10;
1594 //There is *no* good reason to do this here!
1596 dsp_releaseTimeSlice_flag = 0;
1599 while (cycles > 0 && DSP_RUNNING)
1601 /*extern uint32 totalFrames;
1602 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1603 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1604 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1606 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1609 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1611 if (dsp_pc == 0xF1B092)
1612 doDSPDis = false;//*/
1613 /*if (dsp_pc == 0xF1B140)
1614 doDSPDis = true;//*/
1616 if (IMASKCleared) // If IMASK was cleared,
1618 #ifdef DSP_DEBUG_IRQ
1619 WriteLog("DSP: Finished interrupt.\n");
1621 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1622 IMASKCleared = false;
1627 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1628 for(int i=0; i<80; i+=4)
1629 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1632 /*if (dsp_pc == 0xF1B55E)
1634 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1636 /*if (dsp_pc == 0xF1B7D2) // Start here???
1638 pcQueue[ptrPCQ++] = dsp_pc;
1640 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1641 uint32 index = opcode >> 10;
1642 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1643 dsp_opcode_second_parameter = opcode & 0x1F;
1645 dsp_opcode[index]();
1646 dsp_opcode_use[index]++;
1647 cycles -= dsp_opcode_cycles[index];
1648 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1650 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1653 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1655 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1657 DSPDumpDisassembly();
1660 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1663 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1666 WriteLog("\nBacktrace:\n");
1667 for(int i=0; i<32; i++)
1669 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1670 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1680 // DSP opcode handlers
1683 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1684 // can cause trouble because an interrupt can occur *before* the instruction following the
1685 // jump can execute... !!! FIX !!!
1686 static void dsp_opcode_jump(void)
1689 const char * condition[32] =
1690 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1691 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1692 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1693 "???", "???", "???", "F" };
1695 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);
1698 /* dsp_flag_c=dsp_flag_c?1:0;
1699 dsp_flag_z=dsp_flag_z?1:0;
1700 dsp_flag_n=dsp_flag_n?1:0;*/
1701 // KLUDGE: Used by BRANCH_CONDITION
1702 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1704 if (BRANCH_CONDITION(IMM_2))
1708 WriteLog("Branched!\n");
1710 uint32 delayed_pc = RM;
1712 dsp_pc = delayed_pc;
1717 WriteLog("Branch NOT taken.\n");
1721 static void dsp_opcode_jr(void)
1724 const char * condition[32] =
1725 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1726 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1727 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1728 "???", "???", "???", "F" };
1730 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);
1733 /* dsp_flag_c=dsp_flag_c?1:0;
1734 dsp_flag_z=dsp_flag_z?1:0;
1735 dsp_flag_n=dsp_flag_n?1:0;*/
1736 // KLUDGE: Used by BRANCH_CONDITION
1737 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1739 if (BRANCH_CONDITION(IMM_2))
1743 WriteLog("Branched!\n");
1745 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1746 int32 delayed_pc = dsp_pc + (offset * 2);
1748 dsp_pc = delayed_pc;
1753 WriteLog("Branch NOT taken.\n");
1757 static void dsp_opcode_add(void)
1761 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);
1763 uint32 res = RN + RM;
1764 SET_ZNC_ADD(RN, RM, res);
1768 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);
1772 static void dsp_opcode_addc(void)
1776 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);
1778 uint32 res = RN + RM + dsp_flag_c;
1779 uint32 carry = dsp_flag_c;
1780 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1781 SET_ZNC_ADD(RN + carry, RM, res);
1782 // SET_ZNC_ADD(RN, RM + carry, res);
1786 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);
1790 static void dsp_opcode_addq(void)
1794 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);
1796 uint32 r1 = dsp_convert_zero[IMM_1];
1797 uint32 res = RN + r1;
1798 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1802 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1806 static void dsp_opcode_sub(void)
1810 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);
1812 uint32 res = RN - RM;
1813 SET_ZNC_SUB(RN, RM, res);
1817 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);
1821 static void dsp_opcode_subc(void)
1825 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);
1827 uint32 res = RN - RM - dsp_flag_c;
1828 uint32 borrow = dsp_flag_c;
1829 SET_ZNC_SUB(RN - borrow, RM, res);
1833 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);
1837 static void dsp_opcode_subq(void)
1841 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);
1843 uint32 r1 = dsp_convert_zero[IMM_1];
1844 uint32 res = RN - r1;
1845 SET_ZNC_SUB(RN, r1, res);
1849 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1853 static void dsp_opcode_cmp(void)
1857 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);
1859 uint32 res = RN - RM;
1860 SET_ZNC_SUB(RN, RM, res);
1863 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1867 static void dsp_opcode_cmpq(void)
1869 static int32 sqtable[32] =
1870 { 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 };
1873 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);
1875 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1876 uint32 res = RN - r1;
1877 SET_ZNC_SUB(RN, r1, res);
1880 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1884 static void dsp_opcode_and(void)
1888 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);
1894 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);
1898 static void dsp_opcode_or(void)
1902 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);
1908 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);
1912 static void dsp_opcode_xor(void)
1916 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);
1922 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);
1926 static void dsp_opcode_not(void)
1930 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);
1936 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1940 static void dsp_opcode_move_pc(void)
1945 static void dsp_opcode_store_r14_indexed(void)
1947 #ifdef DSP_DIS_STORE14I
1949 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));
1951 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1954 static void dsp_opcode_store_r15_indexed(void)
1956 #ifdef DSP_DIS_STORE15I
1958 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));
1960 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1963 static void dsp_opcode_load_r14_ri(void)
1965 #ifdef DSP_DIS_LOAD14R
1967 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);
1969 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1970 #ifdef DSP_DIS_LOAD14R
1972 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1976 static void dsp_opcode_load_r15_ri(void)
1978 #ifdef DSP_DIS_LOAD15R
1980 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);
1982 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1983 #ifdef DSP_DIS_LOAD15R
1985 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1989 static void dsp_opcode_store_r14_ri(void)
1991 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1994 static void dsp_opcode_store_r15_ri(void)
1996 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1999 static void dsp_opcode_nop(void)
2003 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2007 static void dsp_opcode_storeb(void)
2009 #ifdef DSP_DIS_STOREB
2011 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);
2013 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2014 DSPWriteLong(RM, RN & 0xFF, DSP);
2016 JaguarWriteByte(RM, RN, DSP);
2019 static void dsp_opcode_storew(void)
2021 #ifdef DSP_DIS_STOREW
2023 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);
2025 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2026 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2028 JaguarWriteWord(RM, RN, DSP);
2031 static void dsp_opcode_store(void)
2033 #ifdef DSP_DIS_STORE
2035 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);
2037 DSPWriteLong(RM, RN, DSP);
2040 static void dsp_opcode_loadb(void)
2042 #ifdef DSP_DIS_LOADB
2044 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);
2046 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2047 RN = DSPReadLong(RM, DSP) & 0xFF;
2049 RN = JaguarReadByte(RM, DSP);
2050 #ifdef DSP_DIS_LOADB
2052 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2056 static void dsp_opcode_loadw(void)
2058 #ifdef DSP_DIS_LOADW
2060 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);
2062 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2063 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2065 RN = JaguarReadWord(RM, DSP);
2066 #ifdef DSP_DIS_LOADW
2068 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2072 static void dsp_opcode_load(void)
2076 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);
2078 RN = DSPReadLong(RM, DSP);
2081 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2085 static void dsp_opcode_load_r14_indexed(void)
2087 #ifdef DSP_DIS_LOAD14I
2089 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);
2091 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2092 #ifdef DSP_DIS_LOAD14I
2094 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2098 static void dsp_opcode_load_r15_indexed(void)
2100 #ifdef DSP_DIS_LOAD15I
2102 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);
2104 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2105 #ifdef DSP_DIS_LOAD15I
2107 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2111 static void dsp_opcode_movei(void)
2113 #ifdef DSP_DIS_MOVEI
2115 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);
2117 // This instruction is followed by 32-bit value in LSW / MSW format...
2118 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2120 #ifdef DSP_DIS_MOVEI
2122 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2126 static void dsp_opcode_moveta(void)
2128 #ifdef DSP_DIS_MOVETA
2130 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);
2133 #ifdef DSP_DIS_MOVETA
2135 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);
2139 static void dsp_opcode_movefa(void)
2141 #ifdef DSP_DIS_MOVEFA
2143 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);
2146 #ifdef DSP_DIS_MOVEFA
2148 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);
2152 static void dsp_opcode_move(void)
2156 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);
2161 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);
2165 static void dsp_opcode_moveq(void)
2167 #ifdef DSP_DIS_MOVEQ
2169 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);
2172 #ifdef DSP_DIS_MOVEQ
2174 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2178 static void dsp_opcode_resmac(void)
2180 #ifdef DSP_DIS_RESMAC
2182 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));
2184 RN = (uint32)dsp_acc;
2185 #ifdef DSP_DIS_RESMAC
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_imult(void)
2193 #ifdef DSP_DIS_IMULT
2195 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);
2197 RN = (int16)RN * (int16)RM;
2199 #ifdef DSP_DIS_IMULT
2201 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);
2205 static void dsp_opcode_mult(void)
2209 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);
2211 RN = (uint16)RM * (uint16)RN;
2215 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);
2219 static void dsp_opcode_bclr(void)
2223 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);
2225 uint32 res = RN & ~(1 << IMM_1);
2230 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2234 static void dsp_opcode_btst(void)
2238 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);
2240 dsp_flag_z = (~RN >> IMM_1) & 1;
2243 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2247 static void dsp_opcode_bset(void)
2251 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);
2253 uint32 res = RN | (1 << IMM_1);
2258 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2262 static void dsp_opcode_subqt(void)
2264 #ifdef DSP_DIS_SUBQT
2266 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);
2268 RN -= dsp_convert_zero[IMM_1];
2269 #ifdef DSP_DIS_SUBQT
2271 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2275 static void dsp_opcode_addqt(void)
2277 #ifdef DSP_DIS_ADDQT
2279 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);
2281 RN += dsp_convert_zero[IMM_1];
2282 #ifdef DSP_DIS_ADDQT
2284 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2288 static void dsp_opcode_imacn(void)
2290 #ifdef DSP_DIS_IMACN
2292 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);
2294 int32 res = (int16)RM * (int16)RN;
2295 dsp_acc += (int64)res;
2296 //Should we AND the result to fit into 40 bits here???
2297 #ifdef DSP_DIS_IMACN
2299 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));
2303 static void dsp_opcode_mtoi(void)
2305 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2309 static void dsp_opcode_normi(void)
2316 while ((_Rm & 0xffc00000) == 0)
2321 while ((_Rm & 0xff800000) != 0)
2331 static void dsp_opcode_mmult(void)
2333 int count = dsp_matrix_control&0x0f;
2334 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2338 if (!(dsp_matrix_control & 0x10))
2340 for (int i = 0; i < count; i++)
2344 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2346 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2347 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2354 for (int i = 0; i < count; i++)
2358 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2360 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2361 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2366 RN = res = (int32)accum;
2368 //NOTE: The flags are set based upon the last add/multiply done...
2372 static void dsp_opcode_abs(void)
2376 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);
2381 if (_Rn == 0x80000000)
2385 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2386 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2391 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2395 static void dsp_opcode_div(void)
2402 if (dsp_div_control & 1)
2404 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2405 if (dsp_remain&0x80000000)
2407 RN = (((uint64)_Rn) << 16) / _Rm;
2411 dsp_remain = _Rn % _Rm;
2412 if (dsp_remain&0x80000000)
2421 static void dsp_opcode_imultn(void)
2423 #ifdef DSP_DIS_IMULTN
2425 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);
2427 // This is OK, since this multiply won't overflow 32 bits...
2428 int32 res = (int32)((int16)RN * (int16)RM);
2429 dsp_acc = (int64)res;
2431 #ifdef DSP_DIS_IMULTN
2433 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));
2437 static void dsp_opcode_neg(void)
2441 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);
2444 SET_ZNC_SUB(0, RN, res);
2448 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2452 static void dsp_opcode_shlq(void)
2456 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);
2458 int32 r1 = 32 - IMM_1;
2459 uint32 res = RN << r1;
2460 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2464 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2468 static void dsp_opcode_shrq(void)
2472 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);
2474 int32 r1 = dsp_convert_zero[IMM_1];
2475 uint32 res = RN >> r1;
2476 SET_ZN(res); dsp_flag_c = RN & 1;
2480 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2484 static void dsp_opcode_ror(void)
2488 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);
2490 uint32 r1 = RM & 0x1F;
2491 uint32 res = (RN >> r1) | (RN << (32 - r1));
2492 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2496 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);
2500 static void dsp_opcode_rorq(void)
2504 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);
2506 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2508 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2510 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2513 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2517 static void dsp_opcode_sha(void)
2519 int32 sRm=(int32)RM;
2525 if (shift>=32) shift=32;
2526 dsp_flag_c=(_Rn&0x80000000)>>31;
2536 if (shift>=32) shift=32;
2540 _Rn=((int32)_Rn)>>1;
2548 static void dsp_opcode_sharq(void)
2550 #ifdef DSP_DIS_SHARQ
2552 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);
2554 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2555 SET_ZN(res); dsp_flag_c = RN & 0x01;
2557 #ifdef DSP_DIS_SHARQ
2559 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2563 static void dsp_opcode_sh(void)
2565 int32 sRm=(int32)RM;
2570 uint32 shift=(-sRm);
2571 if (shift>=32) shift=32;
2572 dsp_flag_c=(_Rn&0x80000000)>>31;
2582 if (shift>=32) shift=32;
2594 void dsp_opcode_addqmod(void)
2596 #ifdef DSP_DIS_ADDQMOD
2598 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);
2600 uint32 r1 = dsp_convert_zero[IMM_1];
2602 uint32 res = r2 + r1;
2603 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2605 SET_ZNC_ADD(r2, r1, res);
2606 #ifdef DSP_DIS_ADDQMOD
2608 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2612 void dsp_opcode_subqmod(void)
2614 uint32 r1 = dsp_convert_zero[IMM_1];
2616 uint32 res = r2 - r1;
2617 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2620 SET_ZNC_SUB(r2, r1, res);
2623 void dsp_opcode_mirror(void)
2626 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2630 void dsp_opcode_sat32s(void)
2632 int32 r2 = (uint32)RN;
2633 int32 temp = dsp_acc >> 32;
2634 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2639 void dsp_opcode_sat16s(void)
2642 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2648 // New pipelined DSP core
2651 static void DSP_abs(void);
2652 static void DSP_add(void);
2653 static void DSP_addc(void);
2654 static void DSP_addq(void);
2655 static void DSP_addqmod(void);
2656 static void DSP_addqt(void);
2657 static void DSP_and(void);
2658 static void DSP_bclr(void);
2659 static void DSP_bset(void);
2660 static void DSP_btst(void);
2661 static void DSP_cmp(void);
2662 static void DSP_cmpq(void);
2663 static void DSP_div(void);
2664 static void DSP_imacn(void);
2665 static void DSP_imult(void);
2666 static void DSP_imultn(void);
2667 static void DSP_illegal(void);
2668 static void DSP_jr(void);
2669 static void DSP_jump(void);
2670 static void DSP_load(void);
2671 static void DSP_loadb(void);
2672 static void DSP_loadw(void);
2673 static void DSP_load_r14_i(void);
2674 static void DSP_load_r14_r(void);
2675 static void DSP_load_r15_i(void);
2676 static void DSP_load_r15_r(void);
2677 static void DSP_mirror(void);
2678 static void DSP_mmult(void);
2679 static void DSP_move(void);
2680 static void DSP_movefa(void);
2681 static void DSP_movei(void);
2682 static void DSP_movepc(void);
2683 static void DSP_moveq(void);
2684 static void DSP_moveta(void);
2685 static void DSP_mtoi(void);
2686 static void DSP_mult(void);
2687 static void DSP_neg(void);
2688 static void DSP_nop(void);
2689 static void DSP_normi(void);
2690 static void DSP_not(void);
2691 static void DSP_or(void);
2692 static void DSP_resmac(void);
2693 static void DSP_ror(void);
2694 static void DSP_rorq(void);
2695 static void DSP_sat16s(void);
2696 static void DSP_sat32s(void);
2697 static void DSP_sh(void);
2698 static void DSP_sha(void);
2699 static void DSP_sharq(void);
2700 static void DSP_shlq(void);
2701 static void DSP_shrq(void);
2702 static void DSP_store(void);
2703 static void DSP_storeb(void);
2704 static void DSP_storew(void);
2705 static void DSP_store_r14_i(void);
2706 static void DSP_store_r14_r(void);
2707 static void DSP_store_r15_i(void);
2708 static void DSP_store_r15_r(void);
2709 static void DSP_sub(void);
2710 static void DSP_subc(void);
2711 static void DSP_subq(void);
2712 static void DSP_subqmod(void);
2713 static void DSP_subqt(void);
2714 static void DSP_xor(void);
2716 void (* DSPOpcode[64])() =
2718 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2719 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2720 DSP_neg, DSP_and, DSP_or, DSP_xor,
2721 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2723 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2724 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2725 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2726 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2728 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2729 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2730 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2731 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2733 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2734 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2735 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2736 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2739 bool readAffected[64][2] =
2741 { true, true}, { true, true}, {false, true}, {false, true},
2742 { true, true}, { true, true}, {false, true}, {false, true},
2743 {false, true}, { true, true}, { true, true}, { true, true},
2744 {false, true}, {false, true}, {false, true}, {false, true},
2746 { true, true}, { true, true}, { true, true}, {false, true},
2747 { true, true}, { true, true}, {false, true}, { true, true},
2748 {false, true}, {false, true}, { true, true}, {false, true},
2749 { true, true}, {false, true}, { true, true}, {false, true},
2751 {false, true}, {false, true}, { true, false}, {false, false},
2752 { true, false}, {false, false}, {false, false}, { true, false},
2753 { true, false}, { true, false}, {false, true}, { true, false},
2754 { true, false}, { true, true}, { true, true}, { true, true},
2756 {false, true}, { true, true}, { true, true}, {false, true},
2757 { true, false}, { true, false}, { true, true}, { true, false},
2758 { true, false}, {false, false}, { true, false}, { true, false},
2759 { true, true}, { true, true}, {false, false}, {false, true}
2762 bool isLoadStore[65] =
2764 false, false, false, false, false, false, false, false,
2765 false, false, false, false, false, false, false, false,
2767 false, false, false, false, false, false, false, false,
2768 false, false, false, false, false, false, false, false,
2770 false, false, false, false, false, false, false, true,
2771 true, true, false, true, true, true, true, true,
2773 false, true, true, false, false, false, false, false,
2774 false, false, true, true, true, true, false, false, false
2777 void FlushDSPPipeline(void)
2779 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2781 for(int i=0; i<4; i++)
2782 pipeline[i].opcode = PIPELINE_STALL;
2784 for(int i=0; i<32; i++)
2789 // New pipelined DSP execution core
2791 /*void DSPExecP(int32 cycles)
2793 // bool inhibitFetch = false;
2795 dsp_releaseTimeSlice_flag = 0;
2798 while (cycles > 0 && DSP_RUNNING)
2800 WriteLog("DSPExecP: Pipeline status...\n");
2801 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);
2802 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);
2803 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);
2804 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);
2805 WriteLog(" --> Scoreboard: ");
2806 for(int i=0; i<32; i++)
2807 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2809 // Stage 1: Instruction fetch
2810 // if (!inhibitFetch)
2812 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2813 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2814 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2815 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2816 if (pipeline[plPtrFetch].opcode == 38)
2817 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2818 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2821 // inhibitFetch = false;
2822 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2824 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2825 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);
2826 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);
2827 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);
2828 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);
2829 // Stage 2: Read registers
2830 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2831 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2832 if (scoreboard[pipeline[plPtrRead].operand2])
2833 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2834 // We have a hit in the scoreboard, so we have to stall the pipeline...
2836 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2837 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2838 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2839 pipeline[plPtrFetch] = pipeline[plPtrRead];
2840 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2844 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2845 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2846 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2848 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2849 // Shouldn't we be more selective with the register scoreboarding?
2850 // Yes, we should. !!! FIX !!!
2851 scoreboard[pipeline[plPtrRead].operand2] = true;
2852 //Advance PC here??? Yes.
2853 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2854 //This is a mangling of the pipeline stages, but what else to do???
2855 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2858 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2859 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);
2860 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);
2861 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);
2862 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);
2864 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2866 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2867 DSPOpcode[pipeline[plPtrExec].opcode]();
2868 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2869 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2874 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2875 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);
2876 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);
2877 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);
2878 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);
2879 // Stage 4: Write back register
2880 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2882 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2883 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2885 scoreboard[pipeline[plPtrWrite].operand1]
2886 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2889 // Push instructions through the pipeline...
2890 plPtrFetch = (++plPtrFetch) & 0x03;
2891 plPtrRead = (++plPtrRead) & 0x03;
2892 plPtrExec = (++plPtrExec) & 0x03;
2893 plPtrWrite = (++plPtrWrite) & 0x03;
2900 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2902 // Should be fixed now. Another problem is figuring how to do the sequence following
2903 // a branch followed with the JR & JUMP instructions...
2905 // There are two conflicting problems:
2908 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2909 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2910 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2911 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2912 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2913 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2914 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2915 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2916 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2917 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2918 DSP: Finished interrupt.
2919 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2920 ; bank 0 (where is was prepared)!
2921 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2922 F1B252: NOP [NCZ:001]
2925 // The other is when you see this at the end of an IRQ:
2928 JUMP T, (R29) ; R29 = Previous stack + 2
2929 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2931 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2932 ; 1) The STORE goes through the pipeline and is executed/written back
2933 ; 2) The pipeline is flushed
2934 ; 3) The DSP_PC is set to the new address
2935 ; 4) Execution resumes
2937 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2938 ; bank 0 instead of the current bank 1 and so goes astray!
2941 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2942 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2946 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2947 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2948 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2949 If it were done properly, the STORE write back would occur *after* (well, technically,
2950 during) the execution of the the JUMP that follows it.
2954 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2955 F1B08A: NOP [NCZ:001]
2957 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2960 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2963 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2964 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2965 F1B08A: NOP [NCZ:001]
2967 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2970 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2971 DSP: CPU -> DSP interrupt
2972 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2973 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2975 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2978 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2979 F1B006: NOP [NCZ:001]
2981 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2984 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2985 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2988 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2989 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2992 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2993 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2996 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2997 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3000 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3003 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3006 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3007 F1B0FE: NOP [NCZ:000]
3009 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3012 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3015 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3016 F1B138: NOP [NCZ:000]
3018 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3021 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3022 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3023 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3026 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3027 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3030 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3031 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3032 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3034 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3035 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3038 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3039 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3040 DSP: Finished interrupt.
3041 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3043 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3046 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3047 F1B016: NOP [NCZ:001]
3049 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3052 uint32 pcQueue1[0x400];
3054 static uint32 prevR1;
3055 //Let's try a 3 stage pipeline....
3056 //Looks like 3 stage is correct, otherwise bad things happen...
3057 void DSPExecP2(int32 cycles)
3059 dsp_releaseTimeSlice_flag = 0;
3062 while (cycles > 0 && DSP_RUNNING)
3064 /*extern uint32 totalFrames;
3065 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3066 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3067 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3069 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3072 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3074 if (dsp_pc == 0xF1B092)
3075 doDSPDis = false;//*/
3076 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3077 doDSPDis = true;//*/
3078 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3079 doDSPDis = true;//*/
3080 /*if (dsp_pc == 0xF1B0A0)
3081 doDSPDis = true;//*/
3082 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3083 doDSPDis = true;//*/
3084 //Two parter... (not sure how to write this)
3085 //if (dsp_pc == 0xF1B0D2)
3086 // prevR1 = dsp_reg[1];
3088 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3089 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3092 pcQueue1[pcQPtr1++] = dsp_pc;
3095 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3097 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3102 for(int i=0; i<0x400; i++)
3104 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3105 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3109 if (IMASKCleared) // If IMASK was cleared,
3111 #ifdef DSP_DEBUG_IRQ
3112 WriteLog("DSP: Finished interrupt.\n");
3114 DSPHandleIRQs(); // See if any other interrupts are pending!
3115 IMASKCleared = false;
3118 //if (dsp_flags & REGPAGE)
3119 // WriteLog(" --> REGPAGE has just been set!\n");
3120 #ifdef DSP_DEBUG_PL2
3123 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3124 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]);
3125 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]);
3126 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]);
3127 WriteLog(" --> Scoreboard: ");
3128 for(int i=0; i<32; i++)
3129 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3133 // Stage 1a: Instruction fetch
3134 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3135 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3136 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3137 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3138 if (pipeline[plPtrRead].opcode == 38)
3139 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3140 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3141 #ifdef DSP_DEBUG_PL2
3144 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3145 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3146 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]);
3147 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]);
3148 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]);
3151 // Stage 1b: Read registers
3152 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3153 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3155 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3156 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3157 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3158 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3159 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3160 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3161 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3163 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3164 // We have a hit in the scoreboard, so we have to stall the pipeline...
3165 #ifdef DSP_DEBUG_PL2
3169 WriteLog(" --> Stalling pipeline: ");
3170 if (readAffected[pipeline[plPtrRead].opcode][0])
3171 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3172 if (readAffected[pipeline[plPtrRead].opcode][1])
3173 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3177 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3178 #ifdef DSP_DEBUG_PL2
3183 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3184 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3185 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3187 // Shouldn't we be more selective with the register scoreboarding?
3188 // Yes, we should. !!! FIX !!! Kinda [DONE]
3189 #ifndef NEW_SCOREBOARD
3190 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3192 //Hopefully this will fix the dual MOVEQ # problem...
3193 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3196 //Advance PC here??? Yes.
3197 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3200 #ifdef DSP_DEBUG_PL2
3203 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3204 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]);
3205 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]);
3206 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 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3213 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"));
3214 #ifdef DSP_DEBUG_PL2
3217 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3222 lastExec = pipeline[plPtrExec].instruction;
3223 //WriteLog("[lastExec = %04X]\n", lastExec);
3225 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3226 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3227 DSPOpcode[pipeline[plPtrExec].opcode]();
3228 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3232 //Let's not, until we do the stalling correctly...
3233 //But, we gotta while we're doing the comparison core...!
3234 //Or do we? cycles--;
3235 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3236 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3237 //to model this clock cycle behavior correctly...
3238 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3239 //don't affect the reads at stage 1...
3240 #ifdef DSP_DEBUG_STALL
3242 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3246 #ifdef DSP_DEBUG_PL2
3249 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3250 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]);
3251 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]);
3252 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]);
3256 // Stage 3: Write back register/memory address
3257 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3259 /*if (pipeline[plPtrWrite].writebackRegister == 3
3260 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3263 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3266 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3268 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3269 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3272 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3273 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3274 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3275 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3277 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3281 #ifndef NEW_SCOREBOARD
3282 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3283 scoreboard[pipeline[plPtrWrite].operand2] = false;
3285 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3286 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3287 if (scoreboard[pipeline[plPtrWrite].operand2])
3288 scoreboard[pipeline[plPtrWrite].operand2]--;
3292 // Push instructions through the pipeline...
3293 plPtrRead = (++plPtrRead) & 0x03;
3294 plPtrExec = (++plPtrExec) & 0x03;
3295 plPtrWrite = (++plPtrWrite) & 0x03;
3304 //#define DSP_DEBUG_PL3
3305 //Let's try a 2 stage pipeline....
3306 void DSPExecP3(int32 cycles)
3308 dsp_releaseTimeSlice_flag = 0;
3311 while (cycles > 0 && DSP_RUNNING)
3313 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3315 #ifdef DSP_DEBUG_PL3
3316 WriteLog("DSPExecP: Pipeline status...\n");
3317 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]);
3318 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]);
3319 WriteLog(" --> Scoreboard: ");
3320 for(int i=0; i<32; i++)
3321 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3324 // Stage 1a: Instruction fetch
3325 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3326 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3327 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3328 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3329 if (pipeline[plPtrRead].opcode == 38)
3330 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3331 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3332 #ifdef DSP_DEBUG_PL3
3333 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3334 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3335 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]);
3336 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]);
3338 // Stage 1b: Read registers
3339 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3340 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3341 // We have a hit in the scoreboard, so we have to stall the pipeline...
3342 #ifdef DSP_DEBUG_PL3
3344 WriteLog(" --> Stalling pipeline: ");
3345 if (readAffected[pipeline[plPtrRead].opcode][0])
3346 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3347 if (readAffected[pipeline[plPtrRead].opcode][1])
3348 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3351 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3352 #ifdef DSP_DEBUG_PL3
3357 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3358 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3359 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3361 // Shouldn't we be more selective with the register scoreboarding?
3362 // Yes, we should. !!! FIX !!! [Kinda DONE]
3363 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3365 //Advance PC here??? Yes.
3366 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3369 #ifdef DSP_DEBUG_PL3
3370 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3371 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]);
3372 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]);
3374 // Stage 2a: Execute
3375 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3377 #ifdef DSP_DEBUG_PL3
3378 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3380 DSPOpcode[pipeline[plPtrExec].opcode]();
3381 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3382 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3387 #ifdef DSP_DEBUG_PL3
3388 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3389 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]);
3390 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]);
3393 // Stage 2b: Write back register
3394 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3396 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3397 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3399 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3400 scoreboard[pipeline[plPtrExec].operand2] = false;
3403 // Push instructions through the pipeline...
3404 plPtrRead = (++plPtrRead) & 0x03;
3405 plPtrExec = (++plPtrExec) & 0x03;
3412 // DSP pipelined opcode handlers
3415 #define PRM pipeline[plPtrExec].reg1
3416 #define PRN pipeline[plPtrExec].reg2
3417 #define PIMM1 pipeline[plPtrExec].operand1
3418 #define PIMM2 pipeline[plPtrExec].operand2
3419 #define PRES pipeline[plPtrExec].result
3420 #define PWBR pipeline[plPtrExec].writebackRegister
3421 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3422 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3423 #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))
3424 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3426 static void DSP_abs(void)
3430 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);
3434 if (_Rn == 0x80000000)
3438 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3439 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3440 CLR_ZN; SET_Z(PRES);
3444 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3448 static void DSP_add(void)
3452 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);
3454 uint32 res = PRN + PRM;
3455 SET_ZNC_ADD(PRN, PRM, res);
3459 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);
3463 static void DSP_addc(void)
3467 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);
3469 uint32 res = PRN + PRM + dsp_flag_c;
3470 uint32 carry = dsp_flag_c;
3471 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3472 SET_ZNC_ADD(PRN + carry, PRM, res);
3473 // SET_ZNC_ADD(PRN, PRM + carry, res);
3477 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);
3481 static void DSP_addq(void)
3485 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);
3487 uint32 r1 = dsp_convert_zero[PIMM1];
3488 uint32 res = PRN + r1;
3489 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3493 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3497 static void DSP_addqmod(void)
3499 #ifdef DSP_DIS_ADDQMOD
3501 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);
3503 uint32 r1 = dsp_convert_zero[PIMM1];
3505 uint32 res = r2 + r1;
3506 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3508 SET_ZNC_ADD(r2, r1, res);
3509 #ifdef DSP_DIS_ADDQMOD
3511 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3515 static void DSP_addqt(void)
3517 #ifdef DSP_DIS_ADDQT
3519 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);
3521 PRES = PRN + dsp_convert_zero[PIMM1];
3522 #ifdef DSP_DIS_ADDQT
3524 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3528 static void DSP_and(void)
3532 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);
3538 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);
3542 static void DSP_bclr(void)
3546 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);
3548 PRES = PRN & ~(1 << PIMM1);
3552 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3556 static void DSP_bset(void)
3560 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);
3562 PRES = PRN | (1 << PIMM1);
3566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3570 static void DSP_btst(void)
3574 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);
3576 dsp_flag_z = (~PRN >> PIMM1) & 1;
3580 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3584 static void DSP_cmp(void)
3588 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);
3590 uint32 res = PRN - PRM;
3591 SET_ZNC_SUB(PRN, PRM, res);
3595 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3599 static void DSP_cmpq(void)
3601 static int32 sqtable[32] =
3602 { 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 };
3605 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);
3607 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3608 uint32 res = PRN - r1;
3609 SET_ZNC_SUB(PRN, r1, res);
3613 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3617 static void DSP_div(void)
3619 uint32 _Rm = PRM, _Rn = PRN;
3623 if (dsp_div_control & 1)
3625 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3626 if (dsp_remain & 0x80000000)
3628 PRES = (((uint64)_Rn) << 16) / _Rm;
3632 dsp_remain = _Rn % _Rm;
3633 if (dsp_remain & 0x80000000)
3642 static void DSP_imacn(void)
3644 #ifdef DSP_DIS_IMACN
3646 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);
3648 int32 res = (int16)PRM * (int16)PRN;
3649 dsp_acc += (int64)res;
3650 //Should we AND the result to fit into 40 bits here???
3652 #ifdef DSP_DIS_IMACN
3654 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));
3658 static void DSP_imult(void)
3660 #ifdef DSP_DIS_IMULT
3662 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);
3664 PRES = (int16)PRN * (int16)PRM;
3666 #ifdef DSP_DIS_IMULT
3668 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);
3672 static void DSP_imultn(void)
3674 #ifdef DSP_DIS_IMULTN
3676 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);
3678 // This is OK, since this multiply won't overflow 32 bits...
3679 int32 res = (int32)((int16)PRN * (int16)PRM);
3680 dsp_acc = (int64)res;
3683 #ifdef DSP_DIS_IMULTN
3685 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));
3689 static void DSP_illegal(void)
3691 #ifdef DSP_DIS_ILLEGAL
3693 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3698 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3699 // can cause trouble because an interrupt can occur *before* the instruction following the
3700 // jump can execute... !!! FIX !!!
3701 // This can probably be solved by judicious coding in the pipeline execution core...
3702 // And should be fixed now...
3703 static void DSP_jr(void)
3706 const char * condition[32] =
3707 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3708 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3709 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3710 "???", "???", "???", "F" };
3712 //How come this is always off by 2???
3713 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);
3715 // KLUDGE: Used by BRANCH_CONDITION macro
3716 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3718 if (BRANCH_CONDITION(PIMM2))
3722 WriteLog("Branched!\n");
3724 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3725 //Account for pipeline effects...
3726 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3727 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3729 // Now that we've branched, we have to make sure that the following instruction
3730 // is executed atomically with this one and then flush the pipeline before setting
3733 // Step 1: Handle writebacks at stage 3 of pipeline
3734 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3736 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3737 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3739 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3740 scoreboard[pipeline[plPtrWrite].operand2] = false;
3742 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3744 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3746 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3747 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3750 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3751 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3752 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3753 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3755 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3759 #ifndef NEW_SCOREBOARD
3760 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3761 scoreboard[pipeline[plPtrWrite].operand2] = false;
3763 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3764 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3765 if (scoreboard[pipeline[plPtrWrite].operand2])
3766 scoreboard[pipeline[plPtrWrite].operand2]--;
3770 // Step 2: Push instruction through pipeline & execute following instruction
3771 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3772 // we effectively handle the final push of the instruction through the
3773 // pipeline when the new PC takes effect (since when we return, the
3774 // pipeline code will be executing the writeback stage. If we reverse
3775 // the execution order of the pipeline stages, this will no longer be
3777 pipeline[plPtrExec] = pipeline[plPtrRead];
3778 //This is BAD. We need to get that next opcode and execute it!
3779 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3780 // remove this crap.
3781 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3783 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3784 pipeline[plPtrExec].opcode = instruction >> 10;
3785 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3786 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3787 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3788 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3789 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3791 dsp_pc += 2; // For DSP_DIS_* accuracy
3792 DSPOpcode[pipeline[plPtrExec].opcode]();
3793 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3794 pipeline[plPtrWrite] = pipeline[plPtrExec];
3796 // Step 3: Flush pipeline & set new PC
3797 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3804 WriteLog("Branch NOT taken.\n");
3810 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3813 static void DSP_jump(void)
3816 const char * condition[32] =
3817 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3818 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3819 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3820 "???", "???", "???", "F" };
3822 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);
3824 // KLUDGE: Used by BRANCH_CONDITION macro
3825 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3827 if (BRANCH_CONDITION(PIMM2))
3831 WriteLog("Branched!\n");
3833 uint32 PCSave = PRM;
3834 // Now that we've branched, we have to make sure that the following instruction
3835 // is executed atomically with this one and then flush the pipeline before setting
3838 // Step 1: Handle writebacks at stage 3 of pipeline
3839 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3841 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3842 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3844 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3845 scoreboard[pipeline[plPtrWrite].operand2] = false;
3847 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3849 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3851 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3852 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3855 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3856 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3857 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3858 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3860 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3864 #ifndef NEW_SCOREBOARD
3865 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3866 scoreboard[pipeline[plPtrWrite].operand2] = false;
3868 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3869 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3870 if (scoreboard[pipeline[plPtrWrite].operand2])
3871 scoreboard[pipeline[plPtrWrite].operand2]--;
3875 // Step 2: Push instruction through pipeline & execute following instruction
3876 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3877 // we effectively handle the final push of the instruction through the
3878 // pipeline when the new PC takes effect (since when we return, the
3879 // pipeline code will be executing the writeback stage. If we reverse
3880 // the execution order of the pipeline stages, this will no longer be
3882 pipeline[plPtrExec] = pipeline[plPtrRead];
3883 //This is BAD. We need to get that next opcode and execute it!
3884 //Also, same problem in JR!
3885 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3886 // remove this crap.
3887 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3889 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3890 pipeline[plPtrExec].opcode = instruction >> 10;
3891 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3892 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3893 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3894 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3895 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3897 dsp_pc += 2; // For DSP_DIS_* accuracy
3898 DSPOpcode[pipeline[plPtrExec].opcode]();
3899 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3900 pipeline[plPtrWrite] = pipeline[plPtrExec];
3902 // Step 3: Flush pipeline & set new PC
3903 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3910 WriteLog("Branch NOT taken.\n");
3918 static void DSP_load(void)
3922 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);
3924 PRES = DSPReadLong(PRM, DSP);
3927 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3931 static void DSP_loadb(void)
3933 #ifdef DSP_DIS_LOADB
3935 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);
3937 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3938 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3940 PRES = JaguarReadByte(PRM, DSP);
3941 #ifdef DSP_DIS_LOADB
3943 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3947 static void DSP_loadw(void)
3949 #ifdef DSP_DIS_LOADW
3951 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);
3953 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3954 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3956 PRES = JaguarReadWord(PRM, DSP);
3957 #ifdef DSP_DIS_LOADW
3959 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3963 static void DSP_load_r14_i(void)
3965 #ifdef DSP_DIS_LOAD14I
3967 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);
3969 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3970 #ifdef DSP_DIS_LOAD14I
3972 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3976 static void DSP_load_r14_r(void)
3978 #ifdef DSP_DIS_LOAD14R
3980 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);
3982 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3983 #ifdef DSP_DIS_LOAD14R
3985 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3989 static void DSP_load_r15_i(void)
3991 #ifdef DSP_DIS_LOAD15I
3993 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);
3995 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3996 #ifdef DSP_DIS_LOAD15I
3998 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4002 static void DSP_load_r15_r(void)
4004 #ifdef DSP_DIS_LOAD15R
4006 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);
4008 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4009 #ifdef DSP_DIS_LOAD15R
4011 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4015 static void DSP_mirror(void)
4018 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4022 static void DSP_mmult(void)
4024 int count = dsp_matrix_control&0x0f;
4025 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4029 if (!(dsp_matrix_control & 0x10))
4031 for (int i = 0; i < count; i++)
4035 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4037 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4038 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4045 for (int i = 0; i < count; i++)
4049 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4051 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4052 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4058 PRES = res = (int32)accum;
4060 //NOTE: The flags are set based upon the last add/multiply done...
4064 static void DSP_move(void)
4068 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);
4073 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);
4077 static void DSP_movefa(void)
4079 #ifdef DSP_DIS_MOVEFA
4081 // 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);
4082 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);
4084 // PRES = ALTERNATE_RM;
4085 PRES = dsp_alternate_reg[PIMM1];
4086 #ifdef DSP_DIS_MOVEFA
4088 // 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);
4089 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);
4093 static void DSP_movei(void)
4095 #ifdef DSP_DIS_MOVEI
4097 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);
4099 // // This instruction is followed by 32-bit value in LSW / MSW format...
4100 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4102 #ifdef DSP_DIS_MOVEI
4104 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4108 static void DSP_movepc(void)
4110 #ifdef DSP_DIS_MOVEPC
4112 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);
4114 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4115 // PRES = dsp_pc - 2;
4116 //Account for pipeline effects...
4117 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4118 #ifdef DSP_DIS_MOVEPC
4120 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4124 static void DSP_moveq(void)
4126 #ifdef DSP_DIS_MOVEQ
4128 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);
4131 #ifdef DSP_DIS_MOVEQ
4133 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4137 static void DSP_moveta(void)
4139 #ifdef DSP_DIS_MOVETA
4141 // 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);
4142 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]);
4144 // ALTERNATE_RN = PRM;
4145 dsp_alternate_reg[PIMM2] = PRM;
4147 #ifdef DSP_DIS_MOVETA
4149 // 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);
4150 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]);
4154 static void DSP_mtoi(void)
4156 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4160 static void DSP_mult(void)
4164 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);
4166 PRES = (uint16)PRM * (uint16)PRN;
4170 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);
4174 static void DSP_neg(void)
4178 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);
4181 SET_ZNC_SUB(0, PRN, res);
4185 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4189 static void DSP_nop(void)
4193 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4198 static void DSP_normi(void)
4205 while ((_Rm & 0xffc00000) == 0)
4210 while ((_Rm & 0xff800000) != 0)
4220 static void DSP_not(void)
4224 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);
4230 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4234 static void DSP_or(void)
4238 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);
4244 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);
4248 static void DSP_resmac(void)
4250 #ifdef DSP_DIS_RESMAC
4252 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));
4254 PRES = (uint32)dsp_acc;
4255 #ifdef DSP_DIS_RESMAC
4257 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4261 static void DSP_ror(void)
4265 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);
4267 uint32 r1 = PRM & 0x1F;
4268 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4269 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4273 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);
4277 static void DSP_rorq(void)
4281 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);
4283 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4285 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4287 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4290 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4294 static void DSP_sat16s(void)
4297 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4302 static void DSP_sat32s(void)
4304 int32 r2 = (uint32)PRN;
4305 int32 temp = dsp_acc >> 32;
4306 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4311 static void DSP_sh(void)
4313 int32 sRm = (int32)PRM;
4318 uint32 shift = -sRm;
4323 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4338 dsp_flag_c = _Rn & 0x1;
4351 static void DSP_sha(void)
4353 int32 sRm = (int32)PRM;
4358 uint32 shift = -sRm;
4363 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4378 dsp_flag_c = _Rn & 0x1;
4382 _Rn = ((int32)_Rn) >> 1;
4391 static void DSP_sharq(void)
4393 #ifdef DSP_DIS_SHARQ
4395 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);
4397 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4398 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4400 #ifdef DSP_DIS_SHARQ
4402 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4406 static void DSP_shlq(void)
4410 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);
4412 int32 r1 = 32 - PIMM1;
4413 uint32 res = PRN << r1;
4414 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4418 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4422 static void DSP_shrq(void)
4426 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);
4428 int32 r1 = dsp_convert_zero[PIMM1];
4429 uint32 res = PRN >> r1;
4430 SET_ZN(res); dsp_flag_c = PRN & 1;
4434 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4438 static void DSP_store(void)
4440 #ifdef DSP_DIS_STORE
4442 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);
4444 // DSPWriteLong(PRM, PRN, DSP);
4446 pipeline[plPtrExec].address = PRM;
4447 pipeline[plPtrExec].value = PRN;
4448 pipeline[plPtrExec].type = TYPE_DWORD;
4452 static void DSP_storeb(void)
4454 #ifdef DSP_DIS_STOREB
4456 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);
4458 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4459 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4461 // JaguarWriteByte(PRM, PRN, DSP);
4464 pipeline[plPtrExec].address = PRM;
4466 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4468 pipeline[plPtrExec].value = PRN & 0xFF;
4469 pipeline[plPtrExec].type = TYPE_DWORD;
4473 pipeline[plPtrExec].value = PRN;
4474 pipeline[plPtrExec].type = TYPE_BYTE;
4480 static void DSP_storew(void)
4482 #ifdef DSP_DIS_STOREW
4484 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);
4486 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4487 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4489 // JaguarWriteWord(PRM, PRN, DSP);
4492 pipeline[plPtrExec].address = PRM;
4494 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4496 pipeline[plPtrExec].value = PRN & 0xFFFF;
4497 pipeline[plPtrExec].type = TYPE_DWORD;
4501 pipeline[plPtrExec].value = PRN;
4502 pipeline[plPtrExec].type = TYPE_WORD;
4507 static void DSP_store_r14_i(void)
4509 #ifdef DSP_DIS_STORE14I
4511 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));
4513 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4515 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4516 pipeline[plPtrExec].value = PRN;
4517 pipeline[plPtrExec].type = TYPE_DWORD;
4521 static void DSP_store_r14_r(void)
4523 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4525 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4526 pipeline[plPtrExec].value = PRN;
4527 pipeline[plPtrExec].type = TYPE_DWORD;
4531 static void DSP_store_r15_i(void)
4533 #ifdef DSP_DIS_STORE15I
4535 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));
4537 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4539 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4540 pipeline[plPtrExec].value = PRN;
4541 pipeline[plPtrExec].type = TYPE_DWORD;
4545 static void DSP_store_r15_r(void)
4547 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4549 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4550 pipeline[plPtrExec].value = PRN;
4551 pipeline[plPtrExec].type = TYPE_DWORD;
4555 static void DSP_sub(void)
4559 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);
4561 uint32 res = PRN - PRM;
4562 SET_ZNC_SUB(PRN, PRM, res);
4566 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);
4570 static void DSP_subc(void)
4574 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);
4576 uint32 res = PRN - PRM - dsp_flag_c;
4577 uint32 borrow = dsp_flag_c;
4578 SET_ZNC_SUB(PRN - borrow, PRM, res);
4582 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);
4586 static void DSP_subq(void)
4590 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);
4592 uint32 r1 = dsp_convert_zero[PIMM1];
4593 uint32 res = PRN - r1;
4594 SET_ZNC_SUB(PRN, r1, res);
4598 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4602 static void DSP_subqmod(void)
4604 uint32 r1 = dsp_convert_zero[PIMM1];
4606 uint32 res = r2 - r1;
4607 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4609 SET_ZNC_SUB(r2, r1, res);
4612 static void DSP_subqt(void)
4614 #ifdef DSP_DIS_SUBQT
4616 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);
4618 PRES = PRN - dsp_convert_zero[PIMM1];
4619 #ifdef DSP_DIS_SUBQT
4621 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4625 static void DSP_xor(void)
4629 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);
4635 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);