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? (YES)
864 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
865 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
867 JERRYSetPendingIRQ(IRQ2_DSP);
868 DSPReleaseTimeslice();
869 m68k_set_irq(2); // Set 68000 IPL 2...
873 // Check for CPU -> DSP interrupt
877 WriteLog("DSP: CPU -> DSP interrupt\n");
879 m68k_end_timeslice();
880 GPUReleaseTimeslice();
881 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
885 if (data & SINGLE_STEP)
887 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
890 // Protect writes to VERSION and the interrupt latches...
891 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
892 dsp_control = (dsp_control & mask) | (data & ~mask);
896 ctrl1[8] = ctrl2[8] = dsp_control;
900 // if dsp wasn't running but is now running
901 // execute a few cycles
902 //This is just plain wrong, wrong, WRONG!
903 #ifndef DSP_SINGLE_STEPPING
904 /* if (!dsp_was_running && DSP_RUNNING)
909 //This is WRONG! !!! FIX !!!
910 if (dsp_control & 0x18)
915 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
917 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
920 //This isn't exactly right either--we don't know if it was the M68K or the GPU writing here...
921 // !!! FIX !!! [DONE]
925 m68k_end_timeslice();
927 GPUReleaseTimeslice();
931 //DSPDumpDisassembly();
939 dsp_div_control = data;
941 // default: // unaligned long read
947 //We don't have to break this up like this! We CAN do 32 bit writes!
948 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
949 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
950 //if (offset > 0xF1FFFF)
952 JaguarWriteLong(offset, data, who);
956 // Update the DSP register file pointers depending on REGPAGE bit
958 void DSPUpdateRegisterBanks(void)
960 int bank = (dsp_flags & REGPAGE);
962 if (dsp_flags & IMASK)
963 bank = 0; // IMASK forces main bank to be bank 0
966 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
968 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
972 // Check for and handle any asserted DSP IRQs
974 void DSPHandleIRQs(void)
976 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
979 // Get the active interrupt bits (latches) & interrupt mask (enables)
980 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
981 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
983 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
986 if (!bits) // Bail if nothing is enabled
989 int which = 0; // Determine which interrupt
1003 #ifdef DSP_DEBUG_IRQ
1004 WriteLog("DSP: Generating interrupt #%i...", which);
1007 //if (which == 0) doDSPDis = true;
1009 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1010 // directly into the pipeline, it has the side effect of ensuring that the
1011 // instruction interrupted also gets to do its writeback. We simulate that
1013 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1015 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1016 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1018 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1019 scoreboard[pipeline[plPtrWrite].operand2] = false;
1021 //This should be execute (or should it?--not sure now!)
1022 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1023 //and what just executed is now in the Write position...). So why didn't it do the
1024 //writeback into register 0?
1025 #ifdef DSP_DEBUG_IRQ
1026 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1027 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]);
1028 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]);
1029 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]);
1031 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1033 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1035 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1036 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1039 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1040 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1041 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1042 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1044 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1048 #ifndef NEW_SCOREBOARD
1049 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1050 scoreboard[pipeline[plPtrWrite].operand2] = false;
1052 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1053 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1054 if (scoreboard[pipeline[plPtrWrite].operand2])
1055 scoreboard[pipeline[plPtrWrite].operand2]--;
1062 ctrl2[4] = dsp_flags;
1065 DSPUpdateRegisterBanks();
1066 #ifdef DSP_DEBUG_IRQ
1067 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1068 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]);
1071 // subqt #4,r31 ; pre-decrement stack pointer
1072 // move pc,r30 ; address of interrupted code
1073 // store r30,(r31) ; store return address
1080 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1081 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1082 //It missed the place that it was supposed to come back to, so this is WRONG!
1084 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1086 // R -> baz (<- PC points here)
1087 // E -> bar (when it should point here!)
1090 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1091 // which means (assuming they're all 2 bytes long) that the code below will come back on
1092 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1093 // instruction stream...
1095 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1096 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1099 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1103 // movei #service_address,r30 ; pointer to ISR entry
1104 // jump (r30) ; jump to ISR
1106 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1109 ctrl2[0] = regs2[30] = dsp_pc;
1116 // Non-pipelined version...
1118 void DSPHandleIRQsNP(void)
1122 memcpy(dsp_ram_8, ram1, 0x2000);
1123 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1124 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1127 dsp_remain = ctrl1[2];
1128 dsp_modulo = ctrl1[3];
1129 dsp_flags = ctrl1[4];
1130 dsp_matrix_control = ctrl1[5];
1131 dsp_pointer_to_matrix = ctrl1[6];
1132 dsp_data_organization = ctrl1[7];
1133 dsp_control = ctrl1[8];
1134 dsp_div_control = ctrl1[9];
1135 IMASKCleared = ctrl1[10];
1136 dsp_flag_z = ctrl1[11];
1137 dsp_flag_n = ctrl1[12];
1138 dsp_flag_c = ctrl1[13];
1139 DSPUpdateRegisterBanks();
1142 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1145 // Get the active interrupt bits (latches) & interrupt mask (enables)
1146 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1147 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1149 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1152 if (!bits) // Bail if nothing is enabled
1155 int which = 0; // Determine which interrupt
1169 #ifdef DSP_DEBUG_IRQ
1170 WriteLog("DSP: Generating interrupt #%i...", which);
1176 ctrl1[4] = dsp_flags;
1179 DSPUpdateRegisterBanks();
1180 #ifdef DSP_DEBUG_IRQ
1181 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1184 // subqt #4,r31 ; pre-decrement stack pointer
1185 // move pc,r30 ; address of interrupted code
1186 // store r30,(r31) ; store return address
1193 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1196 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1200 // movei #service_address,r30 ; pointer to ISR entry
1201 // jump (r30) ; jump to ISR
1203 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1206 ctrl1[0] = regs1[30] = dsp_pc;
1212 // Set the specified DSP IRQ line to a given state
1214 void DSPSetIRQLine(int irqline, int state)
1216 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1217 uint32 mask = INT_LAT0 << irqline;
1218 dsp_control &= ~mask; // Clear the latch bit
1221 ctrl1[8] = ctrl2[8] = dsp_control;
1227 dsp_control |= mask; // Set the latch bit
1231 ctrl1[8] = ctrl2[8] = dsp_control;
1237 // Not sure if this is correct behavior, but according to JTRM,
1238 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1239 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1240 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1245 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1246 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1247 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1249 dsp_build_branch_condition_table();
1255 dsp_pc = 0x00F1B000;
1256 dsp_acc = 0x00000000;
1257 dsp_remain = 0x00000000;
1258 dsp_modulo = 0xFFFFFFFF;
1259 dsp_flags = 0x00040000;
1260 dsp_matrix_control = 0x00000000;
1261 dsp_pointer_to_matrix = 0x00000000;
1262 dsp_data_organization = 0xFFFFFFFF;
1263 dsp_control = 0x00002000; // Report DSP version 2
1264 dsp_div_control = 0x00000000;
1267 dsp_reg = dsp_reg_bank_0;
1268 dsp_alternate_reg = dsp_reg_bank_1;
1270 for(int i=0; i<32; i++)
1271 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1274 IMASKCleared = false;
1277 memset(dsp_ram_8, 0xFF, 0x2000);
1280 void DSPDumpDisassembly(void)
1284 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1285 uint32 j = 0xF1B000;
1286 while (j <= 0xF1CFFF)
1289 j += dasmjag(JAGUAR_DSP, buffer, j);
1290 WriteLog("\t%08X: %s\n", oldj, buffer);
1294 void DSPDumpRegisters(void)
1296 //Shoud add modulus, etc to dump here...
1297 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1298 WriteLog("\nRegisters bank 0\n");
1299 for(int j=0; j<8; j++)
1301 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1302 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1303 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1304 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1305 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1307 WriteLog("Registers bank 1\n");
1308 for(int j=0; j<8; j++)
1310 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1311 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1312 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1313 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1314 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1321 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
1322 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1324 // get the active interrupt bits
1325 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1326 // get the interrupt mask
1327 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1329 WriteLog("DSP: pending=%08X enabled=%08X\n", bits, mask);
1330 WriteLog("\nRegisters bank 0\n");
1331 for(int j=0; j<8; j++)
1333 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1334 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1335 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1336 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1337 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1339 WriteLog("\nRegisters bank 1\n");
1342 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1343 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1344 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1345 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1346 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1350 static char buffer[512];
1351 j = DSP_WORK_RAM_BASE;
1352 while (j <= 0xF1BFFF)
1355 j += dasmjag(JAGUAR_DSP, buffer, j);
1356 WriteLog("\t%08X: %s\n", oldj, buffer);
1359 WriteLog("DSP opcodes use:\n");
1362 if (dsp_opcode_use[i])
1363 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1366 // memory_free(dsp_ram_8);
1367 // memory_free(dsp_reg_bank_0);
1368 // memory_free(dsp_reg_bank_1);
1369 if (dsp_branch_condition_table)
1370 free(dsp_branch_condition_table);
1379 // DSP comparison core...
1382 static uint16 lastExec;
1383 void DSPExecComp(int32 cycles)
1385 while (cycles > 0 && DSP_RUNNING)
1387 // Load up vars for non-pipelined core
1388 memcpy(dsp_ram_8, ram1, 0x2000);
1389 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1390 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1393 dsp_remain = ctrl1[2];
1394 dsp_modulo = ctrl1[3];
1395 dsp_flags = ctrl1[4];
1396 dsp_matrix_control = ctrl1[5];
1397 dsp_pointer_to_matrix = ctrl1[6];
1398 dsp_data_organization = ctrl1[7];
1399 dsp_control = ctrl1[8];
1400 dsp_div_control = ctrl1[9];
1401 IMASKCleared = ctrl1[10];
1402 dsp_flag_z = ctrl1[11];
1403 dsp_flag_n = ctrl1[12];
1404 dsp_flag_c = ctrl1[13];
1405 DSPUpdateRegisterBanks();
1407 // Decrement cycles based on non-pipelined core...
1408 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1409 cycles -= dsp_opcode_cycles[instr1 >> 10];
1411 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1412 DSPExec(1); // Do *one* instruction
1415 memcpy(ram1, dsp_ram_8, 0x2000);
1416 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1417 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1420 ctrl1[2] = dsp_remain;
1421 ctrl1[3] = dsp_modulo;
1422 ctrl1[4] = dsp_flags;
1423 ctrl1[5] = dsp_matrix_control;
1424 ctrl1[6] = dsp_pointer_to_matrix;
1425 ctrl1[7] = dsp_data_organization;
1426 ctrl1[8] = dsp_control;
1427 ctrl1[9] = dsp_div_control;
1428 ctrl1[10] = IMASKCleared;
1429 ctrl1[11] = dsp_flag_z;
1430 ctrl1[12] = dsp_flag_n;
1431 ctrl1[13] = dsp_flag_c;
1433 // Load up vars for pipelined core
1434 memcpy(dsp_ram_8, ram2, 0x2000);
1435 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1436 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1439 dsp_remain = ctrl2[2];
1440 dsp_modulo = ctrl2[3];
1441 dsp_flags = ctrl2[4];
1442 dsp_matrix_control = ctrl2[5];
1443 dsp_pointer_to_matrix = ctrl2[6];
1444 dsp_data_organization = ctrl2[7];
1445 dsp_control = ctrl2[8];
1446 dsp_div_control = ctrl2[9];
1447 IMASKCleared = ctrl2[10];
1448 dsp_flag_z = ctrl2[11];
1449 dsp_flag_n = ctrl2[12];
1450 dsp_flag_c = ctrl2[13];
1451 DSPUpdateRegisterBanks();
1453 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1454 DSPExecP2(1); // Do *one* instruction
1457 memcpy(ram2, dsp_ram_8, 0x2000);
1458 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1459 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1462 ctrl2[2] = dsp_remain;
1463 ctrl2[3] = dsp_modulo;
1464 ctrl2[4] = dsp_flags;
1465 ctrl2[5] = dsp_matrix_control;
1466 ctrl2[6] = dsp_pointer_to_matrix;
1467 ctrl2[7] = dsp_data_organization;
1468 ctrl2[8] = dsp_control;
1469 ctrl2[9] = dsp_div_control;
1470 ctrl2[10] = IMASKCleared;
1471 ctrl2[11] = dsp_flag_z;
1472 ctrl2[12] = dsp_flag_n;
1473 ctrl2[13] = dsp_flag_c;
1475 if (instr1 != lastExec)
1477 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1479 // 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));
1480 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1481 // if (ctrl1[0] < ppc) // P ran ahead of NP
1482 //How to test this crap???
1485 DSPExecP2(1); // Do one more instruction
1488 memcpy(ram2, dsp_ram_8, 0x2000);
1489 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1490 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1493 ctrl2[2] = dsp_remain;
1494 ctrl2[3] = dsp_modulo;
1495 ctrl2[4] = dsp_flags;
1496 ctrl2[5] = dsp_matrix_control;
1497 ctrl2[6] = dsp_pointer_to_matrix;
1498 ctrl2[7] = dsp_data_organization;
1499 ctrl2[8] = dsp_control;
1500 ctrl2[9] = dsp_div_control;
1501 ctrl2[10] = IMASKCleared;
1502 ctrl2[11] = dsp_flag_z;
1503 ctrl2[12] = dsp_flag_n;
1504 ctrl2[13] = dsp_flag_c;
1506 // else // NP ran ahead of P
1507 if (instr1 != lastExec) // Must be the other way...
1510 // Load up vars for non-pipelined core
1511 memcpy(dsp_ram_8, ram1, 0x2000);
1512 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1513 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1516 dsp_remain = ctrl1[2];
1517 dsp_modulo = ctrl1[3];
1518 dsp_flags = ctrl1[4];
1519 dsp_matrix_control = ctrl1[5];
1520 dsp_pointer_to_matrix = ctrl1[6];
1521 dsp_data_organization = ctrl1[7];
1522 dsp_control = ctrl1[8];
1523 dsp_div_control = ctrl1[9];
1524 IMASKCleared = ctrl1[10];
1525 dsp_flag_z = ctrl1[11];
1526 dsp_flag_n = ctrl1[12];
1527 dsp_flag_c = ctrl1[13];
1528 DSPUpdateRegisterBanks();
1530 for(int k=0; k<2; k++)
1532 // Decrement cycles based on non-pipelined core...
1533 instr1 = DSPReadWord(dsp_pc, DSP);
1534 cycles -= dsp_opcode_cycles[instr1 >> 10];
1536 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1537 DSPExec(1); // Do *one* instruction
1541 memcpy(ram1, dsp_ram_8, 0x2000);
1542 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1543 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1546 ctrl1[2] = dsp_remain;
1547 ctrl1[3] = dsp_modulo;
1548 ctrl1[4] = dsp_flags;
1549 ctrl1[5] = dsp_matrix_control;
1550 ctrl1[6] = dsp_pointer_to_matrix;
1551 ctrl1[7] = dsp_data_organization;
1552 ctrl1[8] = dsp_control;
1553 ctrl1[9] = dsp_div_control;
1554 ctrl1[10] = IMASKCleared;
1555 ctrl1[11] = dsp_flag_z;
1556 ctrl1[12] = dsp_flag_n;
1557 ctrl1[13] = dsp_flag_c;
1561 if (instr1 != lastExec)
1563 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1565 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1566 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1579 // DSP execution core
1581 //static bool R20Set = false, tripwire = false;
1582 //static uint32 pcQueue[32], ptrPCQ = 0;
1583 void DSPExec(int32 cycles)
1585 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1586 dsp_check_if_i2s_interrupt_needed();*/
1588 #ifdef DSP_SINGLE_STEPPING
1589 if (dsp_control & 0x18)
1592 dsp_control &= ~0x10;
1595 //There is *no* good reason to do this here!
1597 dsp_releaseTimeSlice_flag = 0;
1600 while (cycles > 0 && DSP_RUNNING)
1602 /*extern uint32 totalFrames;
1603 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1604 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1605 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1607 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1610 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1612 if (dsp_pc == 0xF1B092)
1613 doDSPDis = false;//*/
1614 /*if (dsp_pc == 0xF1B140)
1615 doDSPDis = true;//*/
1617 if (IMASKCleared) // If IMASK was cleared,
1619 #ifdef DSP_DEBUG_IRQ
1620 WriteLog("DSP: Finished interrupt.\n");
1622 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1623 IMASKCleared = false;
1628 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1629 for(int i=0; i<80; i+=4)
1630 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1633 /*if (dsp_pc == 0xF1B55E)
1635 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1637 /*if (dsp_pc == 0xF1B7D2) // Start here???
1639 pcQueue[ptrPCQ++] = dsp_pc;
1641 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1642 uint32 index = opcode >> 10;
1643 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1644 dsp_opcode_second_parameter = opcode & 0x1F;
1646 dsp_opcode[index]();
1647 dsp_opcode_use[index]++;
1648 cycles -= dsp_opcode_cycles[index];
1649 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1651 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1654 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1656 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1658 DSPDumpDisassembly();
1661 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1664 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1667 WriteLog("\nBacktrace:\n");
1668 for(int i=0; i<32; i++)
1670 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1671 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1681 // DSP opcode handlers
1684 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1685 // can cause trouble because an interrupt can occur *before* the instruction following the
1686 // jump can execute... !!! FIX !!!
1687 static void dsp_opcode_jump(void)
1690 const char * condition[32] =
1691 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1692 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1693 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1694 "???", "???", "???", "F" };
1696 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);
1699 /* dsp_flag_c=dsp_flag_c?1:0;
1700 dsp_flag_z=dsp_flag_z?1:0;
1701 dsp_flag_n=dsp_flag_n?1:0;*/
1702 // KLUDGE: Used by BRANCH_CONDITION
1703 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1705 if (BRANCH_CONDITION(IMM_2))
1709 WriteLog("Branched!\n");
1711 uint32 delayed_pc = RM;
1713 dsp_pc = delayed_pc;
1718 WriteLog("Branch NOT taken.\n");
1722 static void dsp_opcode_jr(void)
1725 const char * condition[32] =
1726 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1727 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1728 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1729 "???", "???", "???", "F" };
1731 WriteLog("%06X: 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);
1734 /* dsp_flag_c=dsp_flag_c?1:0;
1735 dsp_flag_z=dsp_flag_z?1:0;
1736 dsp_flag_n=dsp_flag_n?1:0;*/
1737 // KLUDGE: Used by BRANCH_CONDITION
1738 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1740 if (BRANCH_CONDITION(IMM_2))
1744 WriteLog("Branched!\n");
1746 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1747 int32 delayed_pc = dsp_pc + (offset * 2);
1749 dsp_pc = delayed_pc;
1754 WriteLog("Branch NOT taken.\n");
1758 static void dsp_opcode_add(void)
1762 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);
1764 uint32 res = RN + RM;
1765 SET_ZNC_ADD(RN, RM, res);
1769 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);
1773 static void dsp_opcode_addc(void)
1777 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);
1779 uint32 res = RN + RM + dsp_flag_c;
1780 uint32 carry = dsp_flag_c;
1781 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1782 SET_ZNC_ADD(RN + carry, RM, res);
1783 // SET_ZNC_ADD(RN, RM + carry, res);
1787 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);
1791 static void dsp_opcode_addq(void)
1795 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);
1797 uint32 r1 = dsp_convert_zero[IMM_1];
1798 uint32 res = RN + r1;
1799 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1803 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1807 static void dsp_opcode_sub(void)
1811 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);
1813 uint32 res = RN - RM;
1814 SET_ZNC_SUB(RN, RM, res);
1818 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);
1822 static void dsp_opcode_subc(void)
1826 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);
1828 uint32 res = RN - RM - dsp_flag_c;
1829 uint32 borrow = dsp_flag_c;
1830 SET_ZNC_SUB(RN - borrow, RM, res);
1834 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);
1838 static void dsp_opcode_subq(void)
1842 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);
1844 uint32 r1 = dsp_convert_zero[IMM_1];
1845 uint32 res = RN - r1;
1846 SET_ZNC_SUB(RN, r1, res);
1850 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1854 static void dsp_opcode_cmp(void)
1858 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);
1860 uint32 res = RN - RM;
1861 SET_ZNC_SUB(RN, RM, res);
1864 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1868 static void dsp_opcode_cmpq(void)
1870 static int32 sqtable[32] =
1871 { 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 };
1874 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);
1876 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1877 uint32 res = RN - r1;
1878 SET_ZNC_SUB(RN, r1, res);
1881 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1885 static void dsp_opcode_and(void)
1889 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);
1895 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);
1899 static void dsp_opcode_or(void)
1903 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);
1909 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);
1913 static void dsp_opcode_xor(void)
1917 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);
1923 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);
1927 static void dsp_opcode_not(void)
1931 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);
1937 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1941 static void dsp_opcode_move_pc(void)
1946 static void dsp_opcode_store_r14_indexed(void)
1948 #ifdef DSP_DIS_STORE14I
1950 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));
1952 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1955 static void dsp_opcode_store_r15_indexed(void)
1957 #ifdef DSP_DIS_STORE15I
1959 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));
1961 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1964 static void dsp_opcode_load_r14_ri(void)
1966 #ifdef DSP_DIS_LOAD14R
1968 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);
1970 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1971 #ifdef DSP_DIS_LOAD14R
1973 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1977 static void dsp_opcode_load_r15_ri(void)
1979 #ifdef DSP_DIS_LOAD15R
1981 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);
1983 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1984 #ifdef DSP_DIS_LOAD15R
1986 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1990 static void dsp_opcode_store_r14_ri(void)
1992 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1995 static void dsp_opcode_store_r15_ri(void)
1997 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2000 static void dsp_opcode_nop(void)
2004 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2008 static void dsp_opcode_storeb(void)
2010 #ifdef DSP_DIS_STOREB
2012 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);
2014 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2015 DSPWriteLong(RM, RN & 0xFF, DSP);
2017 JaguarWriteByte(RM, RN, DSP);
2020 static void dsp_opcode_storew(void)
2022 #ifdef DSP_DIS_STOREW
2024 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);
2026 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2027 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2029 JaguarWriteWord(RM, RN, DSP);
2032 static void dsp_opcode_store(void)
2034 #ifdef DSP_DIS_STORE
2036 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);
2038 DSPWriteLong(RM, RN, DSP);
2041 static void dsp_opcode_loadb(void)
2043 #ifdef DSP_DIS_LOADB
2045 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);
2047 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2048 RN = DSPReadLong(RM, DSP) & 0xFF;
2050 RN = JaguarReadByte(RM, DSP);
2051 #ifdef DSP_DIS_LOADB
2053 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2057 static void dsp_opcode_loadw(void)
2059 #ifdef DSP_DIS_LOADW
2061 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);
2063 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2064 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2066 RN = JaguarReadWord(RM, DSP);
2067 #ifdef DSP_DIS_LOADW
2069 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2073 static void dsp_opcode_load(void)
2077 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);
2079 RN = DSPReadLong(RM, DSP);
2082 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2086 static void dsp_opcode_load_r14_indexed(void)
2088 #ifdef DSP_DIS_LOAD14I
2090 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);
2092 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2093 #ifdef DSP_DIS_LOAD14I
2095 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2099 static void dsp_opcode_load_r15_indexed(void)
2101 #ifdef DSP_DIS_LOAD15I
2103 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);
2105 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2106 #ifdef DSP_DIS_LOAD15I
2108 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2112 static void dsp_opcode_movei(void)
2114 #ifdef DSP_DIS_MOVEI
2116 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);
2118 // This instruction is followed by 32-bit value in LSW / MSW format...
2119 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2121 #ifdef DSP_DIS_MOVEI
2123 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2127 static void dsp_opcode_moveta(void)
2129 #ifdef DSP_DIS_MOVETA
2131 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);
2134 #ifdef DSP_DIS_MOVETA
2136 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);
2140 static void dsp_opcode_movefa(void)
2142 #ifdef DSP_DIS_MOVEFA
2144 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);
2147 #ifdef DSP_DIS_MOVEFA
2149 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);
2153 static void dsp_opcode_move(void)
2157 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);
2162 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);
2166 static void dsp_opcode_moveq(void)
2168 #ifdef DSP_DIS_MOVEQ
2170 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);
2173 #ifdef DSP_DIS_MOVEQ
2175 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2179 static void dsp_opcode_resmac(void)
2181 #ifdef DSP_DIS_RESMAC
2183 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));
2185 RN = (uint32)dsp_acc;
2186 #ifdef DSP_DIS_RESMAC
2188 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2192 static void dsp_opcode_imult(void)
2194 #ifdef DSP_DIS_IMULT
2196 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);
2198 RN = (int16)RN * (int16)RM;
2200 #ifdef DSP_DIS_IMULT
2202 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);
2206 static void dsp_opcode_mult(void)
2210 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);
2212 RN = (uint16)RM * (uint16)RN;
2216 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);
2220 static void dsp_opcode_bclr(void)
2224 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);
2226 uint32 res = RN & ~(1 << IMM_1);
2231 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2235 static void dsp_opcode_btst(void)
2239 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);
2241 dsp_flag_z = (~RN >> IMM_1) & 1;
2244 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2248 static void dsp_opcode_bset(void)
2252 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);
2254 uint32 res = RN | (1 << IMM_1);
2259 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2263 static void dsp_opcode_subqt(void)
2265 #ifdef DSP_DIS_SUBQT
2267 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);
2269 RN -= dsp_convert_zero[IMM_1];
2270 #ifdef DSP_DIS_SUBQT
2272 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2276 static void dsp_opcode_addqt(void)
2278 #ifdef DSP_DIS_ADDQT
2280 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);
2282 RN += dsp_convert_zero[IMM_1];
2283 #ifdef DSP_DIS_ADDQT
2285 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2289 static void dsp_opcode_imacn(void)
2291 #ifdef DSP_DIS_IMACN
2293 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);
2295 int32 res = (int16)RM * (int16)RN;
2296 dsp_acc += (int64)res;
2297 //Should we AND the result to fit into 40 bits here???
2298 #ifdef DSP_DIS_IMACN
2300 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));
2304 static void dsp_opcode_mtoi(void)
2306 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2310 static void dsp_opcode_normi(void)
2317 while ((_Rm & 0xffc00000) == 0)
2322 while ((_Rm & 0xff800000) != 0)
2332 static void dsp_opcode_mmult(void)
2334 int count = dsp_matrix_control&0x0f;
2335 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
2339 if (!(dsp_matrix_control & 0x10))
2341 for (int i = 0; i < count; i++)
2345 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2347 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2348 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2355 for (int i = 0; i < count; i++)
2359 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2361 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2362 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2367 RN = res = (int32)accum;
2369 //NOTE: The flags are set based upon the last add/multiply done...
2373 static void dsp_opcode_abs(void)
2377 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);
2382 if (_Rn == 0x80000000)
2386 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2387 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2392 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2396 static void dsp_opcode_div(void)
2403 if (dsp_div_control & 1)
2405 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2406 if (dsp_remain&0x80000000)
2408 RN = (((uint64)_Rn) << 16) / _Rm;
2412 dsp_remain = _Rn % _Rm;
2413 if (dsp_remain&0x80000000)
2422 static void dsp_opcode_imultn(void)
2424 #ifdef DSP_DIS_IMULTN
2426 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);
2428 // This is OK, since this multiply won't overflow 32 bits...
2429 int32 res = (int32)((int16)RN * (int16)RM);
2430 dsp_acc = (int64)res;
2432 #ifdef DSP_DIS_IMULTN
2434 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));
2438 static void dsp_opcode_neg(void)
2442 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);
2445 SET_ZNC_SUB(0, RN, res);
2449 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2453 static void dsp_opcode_shlq(void)
2457 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);
2459 int32 r1 = 32 - IMM_1;
2460 uint32 res = RN << r1;
2461 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2465 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2469 static void dsp_opcode_shrq(void)
2473 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);
2475 int32 r1 = dsp_convert_zero[IMM_1];
2476 uint32 res = RN >> r1;
2477 SET_ZN(res); dsp_flag_c = RN & 1;
2481 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2485 static void dsp_opcode_ror(void)
2489 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);
2491 uint32 r1 = RM & 0x1F;
2492 uint32 res = (RN >> r1) | (RN << (32 - r1));
2493 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2497 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);
2501 static void dsp_opcode_rorq(void)
2505 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);
2507 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2509 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2511 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2514 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2518 static void dsp_opcode_sha(void)
2520 int32 sRm=(int32)RM;
2526 if (shift>=32) shift=32;
2527 dsp_flag_c=(_Rn&0x80000000)>>31;
2537 if (shift>=32) shift=32;
2541 _Rn=((int32)_Rn)>>1;
2549 static void dsp_opcode_sharq(void)
2551 #ifdef DSP_DIS_SHARQ
2553 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);
2555 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2556 SET_ZN(res); dsp_flag_c = RN & 0x01;
2558 #ifdef DSP_DIS_SHARQ
2560 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2564 static void dsp_opcode_sh(void)
2566 int32 sRm=(int32)RM;
2571 uint32 shift=(-sRm);
2572 if (shift>=32) shift=32;
2573 dsp_flag_c=(_Rn&0x80000000)>>31;
2583 if (shift>=32) shift=32;
2595 void dsp_opcode_addqmod(void)
2597 #ifdef DSP_DIS_ADDQMOD
2599 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);
2601 uint32 r1 = dsp_convert_zero[IMM_1];
2603 uint32 res = r2 + r1;
2604 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2606 SET_ZNC_ADD(r2, r1, res);
2607 #ifdef DSP_DIS_ADDQMOD
2609 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2613 void dsp_opcode_subqmod(void)
2615 uint32 r1 = dsp_convert_zero[IMM_1];
2617 uint32 res = r2 - r1;
2618 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2621 SET_ZNC_SUB(r2, r1, res);
2624 void dsp_opcode_mirror(void)
2627 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2631 void dsp_opcode_sat32s(void)
2633 int32 r2 = (uint32)RN;
2634 int32 temp = dsp_acc >> 32;
2635 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2640 void dsp_opcode_sat16s(void)
2643 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2649 // New pipelined DSP core
2652 static void DSP_abs(void);
2653 static void DSP_add(void);
2654 static void DSP_addc(void);
2655 static void DSP_addq(void);
2656 static void DSP_addqmod(void);
2657 static void DSP_addqt(void);
2658 static void DSP_and(void);
2659 static void DSP_bclr(void);
2660 static void DSP_bset(void);
2661 static void DSP_btst(void);
2662 static void DSP_cmp(void);
2663 static void DSP_cmpq(void);
2664 static void DSP_div(void);
2665 static void DSP_imacn(void);
2666 static void DSP_imult(void);
2667 static void DSP_imultn(void);
2668 static void DSP_illegal(void);
2669 static void DSP_jr(void);
2670 static void DSP_jump(void);
2671 static void DSP_load(void);
2672 static void DSP_loadb(void);
2673 static void DSP_loadw(void);
2674 static void DSP_load_r14_i(void);
2675 static void DSP_load_r14_r(void);
2676 static void DSP_load_r15_i(void);
2677 static void DSP_load_r15_r(void);
2678 static void DSP_mirror(void);
2679 static void DSP_mmult(void);
2680 static void DSP_move(void);
2681 static void DSP_movefa(void);
2682 static void DSP_movei(void);
2683 static void DSP_movepc(void);
2684 static void DSP_moveq(void);
2685 static void DSP_moveta(void);
2686 static void DSP_mtoi(void);
2687 static void DSP_mult(void);
2688 static void DSP_neg(void);
2689 static void DSP_nop(void);
2690 static void DSP_normi(void);
2691 static void DSP_not(void);
2692 static void DSP_or(void);
2693 static void DSP_resmac(void);
2694 static void DSP_ror(void);
2695 static void DSP_rorq(void);
2696 static void DSP_sat16s(void);
2697 static void DSP_sat32s(void);
2698 static void DSP_sh(void);
2699 static void DSP_sha(void);
2700 static void DSP_sharq(void);
2701 static void DSP_shlq(void);
2702 static void DSP_shrq(void);
2703 static void DSP_store(void);
2704 static void DSP_storeb(void);
2705 static void DSP_storew(void);
2706 static void DSP_store_r14_i(void);
2707 static void DSP_store_r14_r(void);
2708 static void DSP_store_r15_i(void);
2709 static void DSP_store_r15_r(void);
2710 static void DSP_sub(void);
2711 static void DSP_subc(void);
2712 static void DSP_subq(void);
2713 static void DSP_subqmod(void);
2714 static void DSP_subqt(void);
2715 static void DSP_xor(void);
2717 void (* DSPOpcode[64])() =
2719 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2720 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2721 DSP_neg, DSP_and, DSP_or, DSP_xor,
2722 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2724 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2725 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2726 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2727 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2729 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2730 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2731 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2732 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2734 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2735 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2736 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2737 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2740 bool readAffected[64][2] =
2742 { true, true}, { true, true}, {false, true}, {false, true},
2743 { true, true}, { true, true}, {false, true}, {false, true},
2744 {false, true}, { true, true}, { true, true}, { true, true},
2745 {false, true}, {false, true}, {false, true}, {false, true},
2747 { true, true}, { true, true}, { true, true}, {false, true},
2748 { true, true}, { true, true}, {false, true}, { true, true},
2749 {false, true}, {false, true}, { true, true}, {false, true},
2750 { true, true}, {false, true}, { true, true}, {false, true},
2752 {false, true}, {false, true}, { true, false}, {false, false},
2753 { true, false}, {false, false}, {false, false}, { true, false},
2754 { true, false}, { true, false}, {false, true}, { true, false},
2755 { true, false}, { true, true}, { true, true}, { true, true},
2757 {false, true}, { true, true}, { true, true}, {false, true},
2758 { true, false}, { true, false}, { true, true}, { true, false},
2759 { true, false}, {false, false}, { true, false}, { true, false},
2760 { true, true}, { true, true}, {false, false}, {false, true}
2763 bool isLoadStore[65] =
2765 false, false, false, false, false, false, false, false,
2766 false, false, false, false, false, false, false, false,
2768 false, false, false, false, false, false, false, false,
2769 false, false, false, false, false, false, false, false,
2771 false, false, false, false, false, false, false, true,
2772 true, true, false, true, true, true, true, true,
2774 false, true, true, false, false, false, false, false,
2775 false, false, true, true, true, true, false, false, false
2778 void FlushDSPPipeline(void)
2780 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2782 for(int i=0; i<4; i++)
2783 pipeline[i].opcode = PIPELINE_STALL;
2785 for(int i=0; i<32; i++)
2790 // New pipelined DSP execution core
2792 /*void DSPExecP(int32 cycles)
2794 // bool inhibitFetch = false;
2796 dsp_releaseTimeSlice_flag = 0;
2799 while (cycles > 0 && DSP_RUNNING)
2801 WriteLog("DSPExecP: Pipeline status...\n");
2802 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);
2803 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);
2804 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);
2805 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);
2806 WriteLog(" --> Scoreboard: ");
2807 for(int i=0; i<32; i++)
2808 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2810 // Stage 1: Instruction fetch
2811 // if (!inhibitFetch)
2813 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2814 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2815 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2816 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2817 if (pipeline[plPtrFetch].opcode == 38)
2818 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2819 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2822 // inhibitFetch = false;
2823 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2825 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2826 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);
2827 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);
2828 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);
2829 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);
2830 // Stage 2: Read registers
2831 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2832 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2833 if (scoreboard[pipeline[plPtrRead].operand2])
2834 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2835 // We have a hit in the scoreboard, so we have to stall the pipeline...
2837 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2838 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2839 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2840 pipeline[plPtrFetch] = pipeline[plPtrRead];
2841 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2845 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2846 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2847 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2849 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2850 // Shouldn't we be more selective with the register scoreboarding?
2851 // Yes, we should. !!! FIX !!!
2852 scoreboard[pipeline[plPtrRead].operand2] = true;
2853 //Advance PC here??? Yes.
2854 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2855 //This is a mangling of the pipeline stages, but what else to do???
2856 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2859 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2860 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);
2861 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);
2862 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);
2863 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);
2865 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2867 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2868 DSPOpcode[pipeline[plPtrExec].opcode]();
2869 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2870 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2875 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2876 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);
2877 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);
2878 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);
2879 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);
2880 // Stage 4: Write back register
2881 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2883 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2884 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2886 scoreboard[pipeline[plPtrWrite].operand1]
2887 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2890 // Push instructions through the pipeline...
2891 plPtrFetch = (++plPtrFetch) & 0x03;
2892 plPtrRead = (++plPtrRead) & 0x03;
2893 plPtrExec = (++plPtrExec) & 0x03;
2894 plPtrWrite = (++plPtrWrite) & 0x03;
2901 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2903 // Should be fixed now. Another problem is figuring how to do the sequence following
2904 // a branch followed with the JR & JUMP instructions...
2906 // There are two conflicting problems:
2909 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2910 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2911 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2912 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2913 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2914 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2915 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2916 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2917 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2918 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2919 DSP: Finished interrupt.
2920 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2921 ; bank 0 (where is was prepared)!
2922 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2923 F1B252: NOP [NCZ:001]
2926 // The other is when you see this at the end of an IRQ:
2929 JUMP T, (R29) ; R29 = Previous stack + 2
2930 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2932 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2933 ; 1) The STORE goes through the pipeline and is executed/written back
2934 ; 2) The pipeline is flushed
2935 ; 3) The DSP_PC is set to the new address
2936 ; 4) Execution resumes
2938 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2939 ; bank 0 instead of the current bank 1 and so goes astray!
2942 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2943 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2947 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2948 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2949 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2950 If it were done properly, the STORE write back would occur *after* (well, technically,
2951 during) the execution of the the JUMP that follows it.
2955 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2956 F1B08A: NOP [NCZ:001]
2958 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2961 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2964 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2965 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2966 F1B08A: NOP [NCZ:001]
2968 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2971 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2972 DSP: CPU -> DSP interrupt
2973 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2974 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2976 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2979 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2980 F1B006: NOP [NCZ:001]
2982 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
2985 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
2986 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
2989 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
2990 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
2993 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
2994 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
2997 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
2998 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3001 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3004 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3007 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3008 F1B0FE: NOP [NCZ:000]
3010 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3013 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3016 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3017 F1B138: NOP [NCZ:000]
3019 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3022 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3023 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3024 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3027 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3028 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3031 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3032 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3033 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3035 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3036 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3039 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3040 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3041 DSP: Finished interrupt.
3042 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3044 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3047 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3048 F1B016: NOP [NCZ:001]
3050 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3053 uint32 pcQueue1[0x400];
3055 static uint32 prevR1;
3056 //Let's try a 3 stage pipeline....
3057 //Looks like 3 stage is correct, otherwise bad things happen...
3058 void DSPExecP2(int32 cycles)
3060 dsp_releaseTimeSlice_flag = 0;
3063 while (cycles > 0 && DSP_RUNNING)
3065 /*extern uint32 totalFrames;
3066 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3067 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3068 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3070 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3073 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3075 if (dsp_pc == 0xF1B092)
3076 doDSPDis = false;//*/
3077 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3078 doDSPDis = true;//*/
3079 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3080 doDSPDis = true;//*/
3081 /*if (dsp_pc == 0xF1B0A0)
3082 doDSPDis = true;//*/
3083 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3084 doDSPDis = true;//*/
3085 //Two parter... (not sure how to write this)
3086 //if (dsp_pc == 0xF1B0D2)
3087 // prevR1 = dsp_reg[1];
3089 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3090 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3093 pcQueue1[pcQPtr1++] = dsp_pc;
3096 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3098 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3103 for(int i=0; i<0x400; i++)
3105 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3106 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3110 if (IMASKCleared) // If IMASK was cleared,
3112 #ifdef DSP_DEBUG_IRQ
3113 WriteLog("DSP: Finished interrupt.\n");
3115 DSPHandleIRQs(); // See if any other interrupts are pending!
3116 IMASKCleared = false;
3119 //if (dsp_flags & REGPAGE)
3120 // WriteLog(" --> REGPAGE has just been set!\n");
3121 #ifdef DSP_DEBUG_PL2
3124 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3125 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]);
3126 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]);
3127 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]);
3128 WriteLog(" --> Scoreboard: ");
3129 for(int i=0; i<32; i++)
3130 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3134 // Stage 1a: Instruction fetch
3135 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3136 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3137 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3138 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3139 if (pipeline[plPtrRead].opcode == 38)
3140 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3141 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3142 #ifdef DSP_DEBUG_PL2
3145 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3146 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3147 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]);
3148 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]);
3149 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]);
3152 // Stage 1b: Read registers
3153 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3154 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3156 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3157 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3158 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3159 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3160 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3161 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3162 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3164 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3165 // We have a hit in the scoreboard, so we have to stall the pipeline...
3166 #ifdef DSP_DEBUG_PL2
3170 WriteLog(" --> Stalling pipeline: ");
3171 if (readAffected[pipeline[plPtrRead].opcode][0])
3172 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3173 if (readAffected[pipeline[plPtrRead].opcode][1])
3174 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3178 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3179 #ifdef DSP_DEBUG_PL2
3184 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3185 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3186 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3188 // Shouldn't we be more selective with the register scoreboarding?
3189 // Yes, we should. !!! FIX !!! Kinda [DONE]
3190 #ifndef NEW_SCOREBOARD
3191 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3193 //Hopefully this will fix the dual MOVEQ # problem...
3194 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3197 //Advance PC here??? Yes.
3198 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3201 #ifdef DSP_DEBUG_PL2
3204 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3205 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]);
3206 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]);
3207 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]);
3211 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3214 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"));
3215 #ifdef DSP_DEBUG_PL2
3218 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3223 lastExec = pipeline[plPtrExec].instruction;
3224 //WriteLog("[lastExec = %04X]\n", lastExec);
3226 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3227 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3228 DSPOpcode[pipeline[plPtrExec].opcode]();
3229 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3233 //Let's not, until we do the stalling correctly...
3234 //But, we gotta while we're doing the comparison core...!
3235 //Or do we? cycles--;
3236 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3237 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3238 //to model this clock cycle behavior correctly...
3239 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3240 //don't affect the reads at stage 1...
3241 #ifdef DSP_DEBUG_STALL
3243 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3247 #ifdef DSP_DEBUG_PL2
3250 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3251 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]);
3252 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]);
3253 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
3257 // Stage 3: Write back register/memory address
3258 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3260 /*if (pipeline[plPtrWrite].writebackRegister == 3
3261 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3264 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3267 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3269 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3270 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3273 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3274 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3275 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3276 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3278 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3282 #ifndef NEW_SCOREBOARD
3283 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3284 scoreboard[pipeline[plPtrWrite].operand2] = false;
3286 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3287 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3288 if (scoreboard[pipeline[plPtrWrite].operand2])
3289 scoreboard[pipeline[plPtrWrite].operand2]--;
3293 // Push instructions through the pipeline...
3294 plPtrRead = (++plPtrRead) & 0x03;
3295 plPtrExec = (++plPtrExec) & 0x03;
3296 plPtrWrite = (++plPtrWrite) & 0x03;
3305 //#define DSP_DEBUG_PL3
3306 //Let's try a 2 stage pipeline....
3307 void DSPExecP3(int32 cycles)
3309 dsp_releaseTimeSlice_flag = 0;
3312 while (cycles > 0 && DSP_RUNNING)
3314 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3316 #ifdef DSP_DEBUG_PL3
3317 WriteLog("DSPExecP: Pipeline status...\n");
3318 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]);
3319 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]);
3320 WriteLog(" --> Scoreboard: ");
3321 for(int i=0; i<32; i++)
3322 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3325 // Stage 1a: Instruction fetch
3326 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3327 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3328 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3329 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3330 if (pipeline[plPtrRead].opcode == 38)
3331 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3332 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3333 #ifdef DSP_DEBUG_PL3
3334 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3335 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3336 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]);
3337 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]);
3339 // Stage 1b: Read registers
3340 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3341 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3342 // We have a hit in the scoreboard, so we have to stall the pipeline...
3343 #ifdef DSP_DEBUG_PL3
3345 WriteLog(" --> Stalling pipeline: ");
3346 if (readAffected[pipeline[plPtrRead].opcode][0])
3347 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3348 if (readAffected[pipeline[plPtrRead].opcode][1])
3349 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3352 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3353 #ifdef DSP_DEBUG_PL3
3358 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3359 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3360 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3362 // Shouldn't we be more selective with the register scoreboarding?
3363 // Yes, we should. !!! FIX !!! [Kinda DONE]
3364 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3366 //Advance PC here??? Yes.
3367 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3370 #ifdef DSP_DEBUG_PL3
3371 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3372 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]);
3373 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]);
3375 // Stage 2a: Execute
3376 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3378 #ifdef DSP_DEBUG_PL3
3379 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3381 DSPOpcode[pipeline[plPtrExec].opcode]();
3382 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3383 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3388 #ifdef DSP_DEBUG_PL3
3389 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3390 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]);
3391 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]);
3394 // Stage 2b: Write back register
3395 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3397 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3398 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3400 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3401 scoreboard[pipeline[plPtrExec].operand2] = false;
3404 // Push instructions through the pipeline...
3405 plPtrRead = (++plPtrRead) & 0x03;
3406 plPtrExec = (++plPtrExec) & 0x03;
3413 // DSP pipelined opcode handlers
3416 #define PRM pipeline[plPtrExec].reg1
3417 #define PRN pipeline[plPtrExec].reg2
3418 #define PIMM1 pipeline[plPtrExec].operand1
3419 #define PIMM2 pipeline[plPtrExec].operand2
3420 #define PRES pipeline[plPtrExec].result
3421 #define PWBR pipeline[plPtrExec].writebackRegister
3422 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3423 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3424 #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))
3425 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3427 static void DSP_abs(void)
3431 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);
3435 if (_Rn == 0x80000000)
3439 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3440 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3441 CLR_ZN; SET_Z(PRES);
3445 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3449 static void DSP_add(void)
3453 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);
3455 uint32 res = PRN + PRM;
3456 SET_ZNC_ADD(PRN, PRM, res);
3460 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);
3464 static void DSP_addc(void)
3468 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);
3470 uint32 res = PRN + PRM + dsp_flag_c;
3471 uint32 carry = dsp_flag_c;
3472 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3473 SET_ZNC_ADD(PRN + carry, PRM, res);
3474 // SET_ZNC_ADD(PRN, PRM + carry, res);
3478 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);
3482 static void DSP_addq(void)
3486 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);
3488 uint32 r1 = dsp_convert_zero[PIMM1];
3489 uint32 res = PRN + r1;
3490 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3494 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3498 static void DSP_addqmod(void)
3500 #ifdef DSP_DIS_ADDQMOD
3502 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);
3504 uint32 r1 = dsp_convert_zero[PIMM1];
3506 uint32 res = r2 + r1;
3507 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3509 SET_ZNC_ADD(r2, r1, res);
3510 #ifdef DSP_DIS_ADDQMOD
3512 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3516 static void DSP_addqt(void)
3518 #ifdef DSP_DIS_ADDQT
3520 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);
3522 PRES = PRN + dsp_convert_zero[PIMM1];
3523 #ifdef DSP_DIS_ADDQT
3525 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3529 static void DSP_and(void)
3533 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);
3539 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);
3543 static void DSP_bclr(void)
3547 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);
3549 PRES = PRN & ~(1 << PIMM1);
3553 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3557 static void DSP_bset(void)
3561 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);
3563 PRES = PRN | (1 << PIMM1);
3567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3571 static void DSP_btst(void)
3575 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);
3577 dsp_flag_z = (~PRN >> PIMM1) & 1;
3581 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3585 static void DSP_cmp(void)
3589 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);
3591 uint32 res = PRN - PRM;
3592 SET_ZNC_SUB(PRN, PRM, res);
3596 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3600 static void DSP_cmpq(void)
3602 static int32 sqtable[32] =
3603 { 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 };
3606 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);
3608 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3609 uint32 res = PRN - r1;
3610 SET_ZNC_SUB(PRN, r1, res);
3614 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3618 static void DSP_div(void)
3620 uint32 _Rm = PRM, _Rn = PRN;
3624 if (dsp_div_control & 1)
3626 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3627 if (dsp_remain & 0x80000000)
3629 PRES = (((uint64)_Rn) << 16) / _Rm;
3633 dsp_remain = _Rn % _Rm;
3634 if (dsp_remain & 0x80000000)
3643 static void DSP_imacn(void)
3645 #ifdef DSP_DIS_IMACN
3647 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);
3649 int32 res = (int16)PRM * (int16)PRN;
3650 dsp_acc += (int64)res;
3651 //Should we AND the result to fit into 40 bits here???
3653 #ifdef DSP_DIS_IMACN
3655 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));
3659 static void DSP_imult(void)
3661 #ifdef DSP_DIS_IMULT
3663 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);
3665 PRES = (int16)PRN * (int16)PRM;
3667 #ifdef DSP_DIS_IMULT
3669 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);
3673 static void DSP_imultn(void)
3675 #ifdef DSP_DIS_IMULTN
3677 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);
3679 // This is OK, since this multiply won't overflow 32 bits...
3680 int32 res = (int32)((int16)PRN * (int16)PRM);
3681 dsp_acc = (int64)res;
3684 #ifdef DSP_DIS_IMULTN
3686 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));
3690 static void DSP_illegal(void)
3692 #ifdef DSP_DIS_ILLEGAL
3694 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3699 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3700 // can cause trouble because an interrupt can occur *before* the instruction following the
3701 // jump can execute... !!! FIX !!!
3702 // This can probably be solved by judicious coding in the pipeline execution core...
3703 // And should be fixed now...
3704 static void DSP_jr(void)
3707 const char * condition[32] =
3708 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3709 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3710 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3711 "???", "???", "???", "F" };
3713 //How come this is always off by 2???
3714 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);
3716 // KLUDGE: Used by BRANCH_CONDITION macro
3717 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3719 if (BRANCH_CONDITION(PIMM2))
3723 WriteLog("Branched!\n");
3725 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3726 //Account for pipeline effects...
3727 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3728 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3730 // Now that we've branched, we have to make sure that the following instruction
3731 // is executed atomically with this one and then flush the pipeline before setting
3734 // Step 1: Handle writebacks at stage 3 of pipeline
3735 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3737 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3738 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3740 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3741 scoreboard[pipeline[plPtrWrite].operand2] = false;
3743 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3745 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3747 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3748 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3751 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3752 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3753 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3754 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3756 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3760 #ifndef NEW_SCOREBOARD
3761 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3762 scoreboard[pipeline[plPtrWrite].operand2] = false;
3764 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3765 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3766 if (scoreboard[pipeline[plPtrWrite].operand2])
3767 scoreboard[pipeline[plPtrWrite].operand2]--;
3771 // Step 2: Push instruction through pipeline & execute following instruction
3772 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3773 // we effectively handle the final push of the instruction through the
3774 // pipeline when the new PC takes effect (since when we return, the
3775 // pipeline code will be executing the writeback stage. If we reverse
3776 // the execution order of the pipeline stages, this will no longer be
3778 pipeline[plPtrExec] = pipeline[plPtrRead];
3779 //This is BAD. We need to get that next opcode and execute it!
3780 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3781 // remove this crap.
3782 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3784 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3785 pipeline[plPtrExec].opcode = instruction >> 10;
3786 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3787 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3788 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3789 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3790 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3792 dsp_pc += 2; // For DSP_DIS_* accuracy
3793 DSPOpcode[pipeline[plPtrExec].opcode]();
3794 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3795 pipeline[plPtrWrite] = pipeline[plPtrExec];
3797 // Step 3: Flush pipeline & set new PC
3798 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3805 WriteLog("Branch NOT taken.\n");
3811 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3814 static void DSP_jump(void)
3817 const char * condition[32] =
3818 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3819 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3820 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3821 "???", "???", "???", "F" };
3823 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);
3825 // KLUDGE: Used by BRANCH_CONDITION macro
3826 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3828 if (BRANCH_CONDITION(PIMM2))
3832 WriteLog("Branched!\n");
3834 uint32 PCSave = PRM;
3835 // Now that we've branched, we have to make sure that the following instruction
3836 // is executed atomically with this one and then flush the pipeline before setting
3839 // Step 1: Handle writebacks at stage 3 of pipeline
3840 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3842 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3843 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3845 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3846 scoreboard[pipeline[plPtrWrite].operand2] = false;
3848 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3850 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3852 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3853 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3856 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3857 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3858 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3859 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3861 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3865 #ifndef NEW_SCOREBOARD
3866 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3867 scoreboard[pipeline[plPtrWrite].operand2] = false;
3869 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3870 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3871 if (scoreboard[pipeline[plPtrWrite].operand2])
3872 scoreboard[pipeline[plPtrWrite].operand2]--;
3876 // Step 2: Push instruction through pipeline & execute following instruction
3877 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3878 // we effectively handle the final push of the instruction through the
3879 // pipeline when the new PC takes effect (since when we return, the
3880 // pipeline code will be executing the writeback stage. If we reverse
3881 // the execution order of the pipeline stages, this will no longer be
3883 pipeline[plPtrExec] = pipeline[plPtrRead];
3884 //This is BAD. We need to get that next opcode and execute it!
3885 //Also, same problem in JR!
3886 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3887 // remove this crap.
3888 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3890 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3891 pipeline[plPtrExec].opcode = instruction >> 10;
3892 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3893 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3894 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3895 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3896 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3898 dsp_pc += 2; // For DSP_DIS_* accuracy
3899 DSPOpcode[pipeline[plPtrExec].opcode]();
3900 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3901 pipeline[plPtrWrite] = pipeline[plPtrExec];
3903 // Step 3: Flush pipeline & set new PC
3904 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3911 WriteLog("Branch NOT taken.\n");
3919 static void DSP_load(void)
3923 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);
3925 PRES = DSPReadLong(PRM, DSP);
3928 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3932 static void DSP_loadb(void)
3934 #ifdef DSP_DIS_LOADB
3936 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);
3938 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3939 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3941 PRES = JaguarReadByte(PRM, DSP);
3942 #ifdef DSP_DIS_LOADB
3944 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3948 static void DSP_loadw(void)
3950 #ifdef DSP_DIS_LOADW
3952 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);
3954 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3955 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3957 PRES = JaguarReadWord(PRM, DSP);
3958 #ifdef DSP_DIS_LOADW
3960 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3964 static void DSP_load_r14_i(void)
3966 #ifdef DSP_DIS_LOAD14I
3968 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);
3970 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
3971 #ifdef DSP_DIS_LOAD14I
3973 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3977 static void DSP_load_r14_r(void)
3979 #ifdef DSP_DIS_LOAD14R
3981 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);
3983 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
3984 #ifdef DSP_DIS_LOAD14R
3986 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3990 static void DSP_load_r15_i(void)
3992 #ifdef DSP_DIS_LOAD15I
3994 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);
3996 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
3997 #ifdef DSP_DIS_LOAD15I
3999 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4003 static void DSP_load_r15_r(void)
4005 #ifdef DSP_DIS_LOAD15R
4007 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);
4009 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4010 #ifdef DSP_DIS_LOAD15R
4012 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4016 static void DSP_mirror(void)
4019 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4023 static void DSP_mmult(void)
4025 int count = dsp_matrix_control&0x0f;
4026 uint32 addr = dsp_pointer_to_matrix; // in the gpu ram
4030 if (!(dsp_matrix_control & 0x10))
4032 for (int i = 0; i < count; i++)
4036 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4038 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4039 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4046 for (int i = 0; i < count; i++)
4050 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4052 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4053 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4059 PRES = res = (int32)accum;
4061 //NOTE: The flags are set based upon the last add/multiply done...
4065 static void DSP_move(void)
4069 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);
4074 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);
4078 static void DSP_movefa(void)
4080 #ifdef DSP_DIS_MOVEFA
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, ALTERNATE_RM, PIMM2, PRN);
4083 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);
4085 // PRES = ALTERNATE_RM;
4086 PRES = dsp_alternate_reg[PIMM1];
4087 #ifdef DSP_DIS_MOVEFA
4089 // 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);
4090 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);
4094 static void DSP_movei(void)
4096 #ifdef DSP_DIS_MOVEI
4098 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);
4100 // // This instruction is followed by 32-bit value in LSW / MSW format...
4101 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4103 #ifdef DSP_DIS_MOVEI
4105 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4109 static void DSP_movepc(void)
4111 #ifdef DSP_DIS_MOVEPC
4113 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);
4115 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4116 // PRES = dsp_pc - 2;
4117 //Account for pipeline effects...
4118 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4119 #ifdef DSP_DIS_MOVEPC
4121 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4125 static void DSP_moveq(void)
4127 #ifdef DSP_DIS_MOVEQ
4129 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);
4132 #ifdef DSP_DIS_MOVEQ
4134 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4138 static void DSP_moveta(void)
4140 #ifdef DSP_DIS_MOVETA
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, ALTERNATE_RN);
4143 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]);
4145 // ALTERNATE_RN = PRM;
4146 dsp_alternate_reg[PIMM2] = PRM;
4148 #ifdef DSP_DIS_MOVETA
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, ALTERNATE_RN);
4151 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]);
4155 static void DSP_mtoi(void)
4157 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4161 static void DSP_mult(void)
4165 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);
4167 PRES = (uint16)PRM * (uint16)PRN;
4171 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);
4175 static void DSP_neg(void)
4179 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);
4182 SET_ZNC_SUB(0, PRN, res);
4186 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4190 static void DSP_nop(void)
4194 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4199 static void DSP_normi(void)
4206 while ((_Rm & 0xffc00000) == 0)
4211 while ((_Rm & 0xff800000) != 0)
4221 static void DSP_not(void)
4225 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);
4231 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4235 static void DSP_or(void)
4239 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);
4245 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);
4249 static void DSP_resmac(void)
4251 #ifdef DSP_DIS_RESMAC
4253 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));
4255 PRES = (uint32)dsp_acc;
4256 #ifdef DSP_DIS_RESMAC
4258 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4262 static void DSP_ror(void)
4266 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);
4268 uint32 r1 = PRM & 0x1F;
4269 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4270 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4274 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);
4278 static void DSP_rorq(void)
4282 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);
4284 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4286 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4288 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4291 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4295 static void DSP_sat16s(void)
4298 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4303 static void DSP_sat32s(void)
4305 int32 r2 = (uint32)PRN;
4306 int32 temp = dsp_acc >> 32;
4307 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4312 static void DSP_sh(void)
4314 int32 sRm = (int32)PRM;
4319 uint32 shift = -sRm;
4324 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4339 dsp_flag_c = _Rn & 0x1;
4352 static void DSP_sha(void)
4354 int32 sRm = (int32)PRM;
4359 uint32 shift = -sRm;
4364 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4379 dsp_flag_c = _Rn & 0x1;
4383 _Rn = ((int32)_Rn) >> 1;
4392 static void DSP_sharq(void)
4394 #ifdef DSP_DIS_SHARQ
4396 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);
4398 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4399 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4401 #ifdef DSP_DIS_SHARQ
4403 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4407 static void DSP_shlq(void)
4411 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);
4413 int32 r1 = 32 - PIMM1;
4414 uint32 res = PRN << r1;
4415 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4419 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4423 static void DSP_shrq(void)
4427 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);
4429 int32 r1 = dsp_convert_zero[PIMM1];
4430 uint32 res = PRN >> r1;
4431 SET_ZN(res); dsp_flag_c = PRN & 1;
4435 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4439 static void DSP_store(void)
4441 #ifdef DSP_DIS_STORE
4443 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);
4445 // DSPWriteLong(PRM, PRN, DSP);
4447 pipeline[plPtrExec].address = PRM;
4448 pipeline[plPtrExec].value = PRN;
4449 pipeline[plPtrExec].type = TYPE_DWORD;
4453 static void DSP_storeb(void)
4455 #ifdef DSP_DIS_STOREB
4457 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);
4459 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4460 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4462 // JaguarWriteByte(PRM, PRN, DSP);
4465 pipeline[plPtrExec].address = PRM;
4467 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4469 pipeline[plPtrExec].value = PRN & 0xFF;
4470 pipeline[plPtrExec].type = TYPE_DWORD;
4474 pipeline[plPtrExec].value = PRN;
4475 pipeline[plPtrExec].type = TYPE_BYTE;
4481 static void DSP_storew(void)
4483 #ifdef DSP_DIS_STOREW
4485 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);
4487 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4488 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4490 // JaguarWriteWord(PRM, PRN, DSP);
4493 pipeline[plPtrExec].address = PRM;
4495 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4497 pipeline[plPtrExec].value = PRN & 0xFFFF;
4498 pipeline[plPtrExec].type = TYPE_DWORD;
4502 pipeline[plPtrExec].value = PRN;
4503 pipeline[plPtrExec].type = TYPE_WORD;
4508 static void DSP_store_r14_i(void)
4510 #ifdef DSP_DIS_STORE14I
4512 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));
4514 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4516 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4517 pipeline[plPtrExec].value = PRN;
4518 pipeline[plPtrExec].type = TYPE_DWORD;
4522 static void DSP_store_r14_r(void)
4524 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4526 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4527 pipeline[plPtrExec].value = PRN;
4528 pipeline[plPtrExec].type = TYPE_DWORD;
4532 static void DSP_store_r15_i(void)
4534 #ifdef DSP_DIS_STORE15I
4536 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));
4538 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4540 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4541 pipeline[plPtrExec].value = PRN;
4542 pipeline[plPtrExec].type = TYPE_DWORD;
4546 static void DSP_store_r15_r(void)
4548 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4550 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4551 pipeline[plPtrExec].value = PRN;
4552 pipeline[plPtrExec].type = TYPE_DWORD;
4556 static void DSP_sub(void)
4560 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);
4562 uint32 res = PRN - PRM;
4563 SET_ZNC_SUB(PRN, PRM, res);
4567 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);
4571 static void DSP_subc(void)
4575 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);
4577 uint32 res = PRN - PRM - dsp_flag_c;
4578 uint32 borrow = dsp_flag_c;
4579 SET_ZNC_SUB(PRN - borrow, PRM, res);
4583 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);
4587 static void DSP_subq(void)
4591 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);
4593 uint32 r1 = dsp_convert_zero[PIMM1];
4594 uint32 res = PRN - r1;
4595 SET_ZNC_SUB(PRN, r1, res);
4599 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4603 static void DSP_subqmod(void)
4605 uint32 r1 = dsp_convert_zero[PIMM1];
4607 uint32 res = r2 - r1;
4608 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4610 SET_ZNC_SUB(r2, r1, res);
4613 static void DSP_subqt(void)
4615 #ifdef DSP_DIS_SUBQT
4617 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);
4619 PRES = PRN - dsp_convert_zero[PIMM1];
4620 #ifdef DSP_DIS_SUBQT
4622 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4626 static void DSP_xor(void)
4630 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);
4636 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);