4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 11/26/2011 Added fixes for LOAD/STORE alignment issues
19 #include <SDL.h> // Used only for SDL_GetTicks...
33 // Apparently on win32, they left of the last little bits of these. So let's do this:
38 // Seems alignment in loads & stores was off...
39 #define DSP_CORRECT_ALIGNMENT
40 //#define DSP_CORRECT_ALIGNMENT_STORE
43 //#define DSP_DEBUG_IRQ
44 //#define DSP_DEBUG_PL2
45 //#define DSP_DEBUG_STALL
46 //#define DSP_DEBUG_CC
47 #define NEW_SCOREBOARD
49 // Disassembly definitions
56 #define DSP_DIS_ADDQMOD
66 #define DSP_DIS_IMULTN
67 #define DSP_DIS_ILLEGAL
71 #define DSP_DIS_LOAD14I
72 #define DSP_DIS_LOAD14R
73 #define DSP_DIS_LOAD15I
74 #define DSP_DIS_LOAD15R
80 #define DSP_DIS_MOVEFA
81 #define DSP_DIS_MOVEPC // Pipeline only!
82 #define DSP_DIS_MOVETA
88 #define DSP_DIS_RESMAC
95 #define DSP_DIS_STORE14I
96 #define DSP_DIS_STORE15I
97 #define DSP_DIS_STOREB
98 #define DSP_DIS_STOREW
102 #define DSP_DIS_SUBQT
105 bool doDSPDis = false;
106 //bool doDSPDis = true;
141 + load_r15_indexed 284500
143 + store_r15_indexed 47416
147 + load_r14_ri 1229448
150 // Pipeline structures
152 const bool affectsScoreboard[64] =
154 true, true, true, true,
155 true, true, true, true,
156 true, true, true, true,
157 true, false, true, true,
159 true, true, false, true,
160 false, true, true, true,
161 true, true, true, true,
162 true, true, false, false,
164 true, true, true, true,
165 false, true, true, true,
166 true, true, true, true,
167 true, false, false, false,
169 true, false, false, true,
170 false, false, true, true,
171 true, false, true, true,
172 false, false, false, true
178 uint8 opcode, operand1, operand2;
179 uint32 reg1, reg2, areg1, areg2;
181 uint8 writebackRegister;
182 // General memory store...
191 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
192 #ifndef NEW_SCOREBOARD
195 uint8 scoreboard[32];
197 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
198 PipelineStage pipeline[4];
199 bool IMASKCleared = false;
201 // DSP flags (old--have to get rid of this crap)
203 #define CINT0FLAG 0x00200
204 #define CINT1FLAG 0x00400
205 #define CINT2FLAG 0x00800
206 #define CINT3FLAG 0x01000
207 #define CINT4FLAG 0x02000
208 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
209 #define CINT5FLAG 0x20000 /* DSP only */
213 #define ZERO_FLAG 0x00001
214 #define CARRY_FLAG 0x00002
215 #define NEGA_FLAG 0x00004
216 #define IMASK 0x00008
217 #define INT_ENA0 0x00010
218 #define INT_ENA1 0x00020
219 #define INT_ENA2 0x00040
220 #define INT_ENA3 0x00080
221 #define INT_ENA4 0x00100
222 #define INT_CLR0 0x00200
223 #define INT_CLR1 0x00400
224 #define INT_CLR2 0x00800
225 #define INT_CLR3 0x01000
226 #define INT_CLR4 0x02000
227 #define REGPAGE 0x04000
228 #define DMAEN 0x08000
229 #define INT_ENA5 0x10000
230 #define INT_CLR5 0x20000
234 #define DSPGO 0x00001
235 #define CPUINT 0x00002
236 #define DSPINT0 0x00004
237 #define SINGLE_STEP 0x00008
238 #define SINGLE_GO 0x00010
240 #define INT_LAT0 0x00040
241 #define INT_LAT1 0x00080
242 #define INT_LAT2 0x00100
243 #define INT_LAT3 0x00200
244 #define INT_LAT4 0x00400
245 #define BUS_HOG 0x00800
246 #define VERSION 0x0F000
247 #define INT_LAT5 0x10000
249 extern uint32 jaguar_mainRom_crc32;
251 // Is opcode 62 *really* a NOP? Seems like it...
252 static void dsp_opcode_abs(void);
253 static void dsp_opcode_add(void);
254 static void dsp_opcode_addc(void);
255 static void dsp_opcode_addq(void);
256 static void dsp_opcode_addqmod(void);
257 static void dsp_opcode_addqt(void);
258 static void dsp_opcode_and(void);
259 static void dsp_opcode_bclr(void);
260 static void dsp_opcode_bset(void);
261 static void dsp_opcode_btst(void);
262 static void dsp_opcode_cmp(void);
263 static void dsp_opcode_cmpq(void);
264 static void dsp_opcode_div(void);
265 static void dsp_opcode_imacn(void);
266 static void dsp_opcode_imult(void);
267 static void dsp_opcode_imultn(void);
268 static void dsp_opcode_jr(void);
269 static void dsp_opcode_jump(void);
270 static void dsp_opcode_load(void);
271 static void dsp_opcode_loadb(void);
272 static void dsp_opcode_loadw(void);
273 static void dsp_opcode_load_r14_indexed(void);
274 static void dsp_opcode_load_r14_ri(void);
275 static void dsp_opcode_load_r15_indexed(void);
276 static void dsp_opcode_load_r15_ri(void);
277 static void dsp_opcode_mirror(void);
278 static void dsp_opcode_mmult(void);
279 static void dsp_opcode_move(void);
280 static void dsp_opcode_movei(void);
281 static void dsp_opcode_movefa(void);
282 static void dsp_opcode_move_pc(void);
283 static void dsp_opcode_moveq(void);
284 static void dsp_opcode_moveta(void);
285 static void dsp_opcode_mtoi(void);
286 static void dsp_opcode_mult(void);
287 static void dsp_opcode_neg(void);
288 static void dsp_opcode_nop(void);
289 static void dsp_opcode_normi(void);
290 static void dsp_opcode_not(void);
291 static void dsp_opcode_or(void);
292 static void dsp_opcode_resmac(void);
293 static void dsp_opcode_ror(void);
294 static void dsp_opcode_rorq(void);
295 static void dsp_opcode_xor(void);
296 static void dsp_opcode_sat16s(void);
297 static void dsp_opcode_sat32s(void);
298 static void dsp_opcode_sh(void);
299 static void dsp_opcode_sha(void);
300 static void dsp_opcode_sharq(void);
301 static void dsp_opcode_shlq(void);
302 static void dsp_opcode_shrq(void);
303 static void dsp_opcode_store(void);
304 static void dsp_opcode_storeb(void);
305 static void dsp_opcode_storew(void);
306 static void dsp_opcode_store_r14_indexed(void);
307 static void dsp_opcode_store_r14_ri(void);
308 static void dsp_opcode_store_r15_indexed(void);
309 static void dsp_opcode_store_r15_ri(void);
310 static void dsp_opcode_sub(void);
311 static void dsp_opcode_subc(void);
312 static void dsp_opcode_subq(void);
313 static void dsp_opcode_subqmod(void);
314 static void dsp_opcode_subqt(void);
316 uint8 dsp_opcode_cycles[64] =
318 3, 3, 3, 3, 3, 3, 3, 3,
319 3, 3, 3, 3, 3, 3, 3, 3,
320 3, 3, 1, 3, 1, 18, 3, 3,
321 3, 3, 3, 3, 3, 3, 3, 3,
322 3, 3, 2, 2, 2, 2, 3, 4,
323 5, 4, 5, 6, 6, 1, 1, 1,
324 1, 2, 2, 2, 1, 1, 9, 3,
325 3, 1, 6, 6, 2, 2, 3, 3
327 //Here's a QnD kludge...
328 //This is wrong, wrong, WRONG, but it seems to work for the time being...
329 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
330 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
331 /*uint8 dsp_opcode_cycles[64] =
333 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 9, 1, 1,
336 1, 1, 1, 1, 1, 1, 1, 1,
337 1, 1, 1, 1, 1, 1, 1, 2,
338 2, 2, 2, 3, 3, 1, 1, 1,
339 1, 1, 1, 1, 1, 1, 4, 1,
340 1, 1, 3, 3, 1, 1, 1, 1
343 void (* dsp_opcode[64])() =
345 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
346 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
347 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
348 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
349 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
350 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
351 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
352 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
353 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
354 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
355 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
356 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
357 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
358 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
359 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
360 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
363 uint32 dsp_opcode_use[65];
365 const char * dsp_opcode_str[65]=
367 "add", "addc", "addq", "addqt",
368 "sub", "subc", "subq", "subqt",
369 "neg", "and", "or", "xor",
370 "not", "btst", "bset", "bclr",
371 "mult", "imult", "imultn", "resmac",
372 "imacn", "div", "abs", "sh",
373 "shlq", "shrq", "sha", "sharq",
374 "ror", "rorq", "cmp", "cmpq",
375 "subqmod", "sat16s", "move", "moveq",
376 "moveta", "movefa", "movei", "loadb",
377 "loadw", "load", "sat32s", "load_r14_indexed",
378 "load_r15_indexed", "storeb", "storew", "store",
379 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
380 "jump", "jr", "mmult", "mtoi",
381 "normi", "nop", "load_r14_ri", "load_r15_ri",
382 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
387 static uint64 dsp_acc; // 40 bit register, NOT 32!
388 static uint32 dsp_remain;
389 static uint32 dsp_modulo;
390 static uint32 dsp_flags;
391 static uint32 dsp_matrix_control;
392 static uint32 dsp_pointer_to_matrix;
393 static uint32 dsp_data_organization;
395 static uint32 dsp_div_control;
396 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
397 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
398 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
400 static uint32 dsp_opcode_first_parameter;
401 static uint32 dsp_opcode_second_parameter;
403 #define DSP_RUNNING (dsp_control & 0x01)
405 #define RM dsp_reg[dsp_opcode_first_parameter]
406 #define RN dsp_reg[dsp_opcode_second_parameter]
407 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
408 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
409 #define IMM_1 dsp_opcode_first_parameter
410 #define IMM_2 dsp_opcode_second_parameter
412 #define CLR_Z (dsp_flag_z = 0)
413 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
414 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
415 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
416 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
417 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
418 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
419 #define SET_ZN(r) SET_N(r); SET_Z(r)
420 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
421 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
423 uint32 dsp_convert_zero[32] = {
424 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
425 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
427 uint8 dsp_branch_condition_table[32 * 8];
428 static uint16 mirror_table[65536];
429 static uint8 dsp_ram_8[0x2000];
431 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
433 static uint32 dsp_in_exec = 0;
434 static uint32 dsp_releaseTimeSlice_flag = 0;
439 // Comparison core vars (used only for core comparison! :-)
440 static uint64 count = 0;
441 static uint8 ram1[0x2000], ram2[0x2000];
442 static uint32 regs1[64], regs2[64];
443 static uint32 ctrl1[14], ctrl2[14];
446 // Private function prototypes
448 void DSPDumpRegisters(void);
449 void DSPDumpDisassembly(void);
450 void FlushDSPPipeline(void);
453 void dsp_reset_stats(void)
455 for(int i=0; i<65; i++)
456 dsp_opcode_use[i] = 0;
459 void DSPReleaseTimeslice(void)
461 //This does absolutely nothing!!! !!! FIX !!!
462 dsp_releaseTimeSlice_flag = 1;
465 void dsp_build_branch_condition_table(void)
467 // Fill in the mirror table
468 for(int i=0; i<65536; i++)
470 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
471 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
472 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
473 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
474 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
475 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
476 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
477 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
480 // Fill in the condition table
481 for(int i=0; i<8; i++)
483 for(int j=0; j<32; j++)
487 if ((j & 1) && (i & ZERO_FLAG))
490 if ((j & 2) && (!(i & ZERO_FLAG)))
493 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
496 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
499 dsp_branch_condition_table[i * 32 + j] = result;
504 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
506 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
507 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
509 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
512 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
514 if (offset==0xF1CFE0)
517 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
518 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
520 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
522 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
524 if ((offset&0x03)==0)
527 if ((offset&0x03)==1)
528 return((data>>16)&0xff);
530 if ((offset&0x03)==2)
531 return((data>>8)&0xff);
533 if ((offset&0x03)==3)
537 return JaguarReadByte(offset, who);
540 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
542 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
543 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
545 offset &= 0xFFFFFFFE;
547 /* if (jaguar_mainRom_crc32==0xa74a97cd)
549 if (offset==0xF1A114) return(0x0000);
550 if (offset==0xF1A116) return(0x0000);
551 if (offset==0xF1B000) return(0x1234);
552 if (offset==0xF1B002) return(0x5678);
555 if (jaguar_mainRom_crc32==0x7ae20823)
557 if (offset==0xF1B9D8) return(0x0000);
558 if (offset==0xF1B9Da) return(0x0000);
559 if (offset==0xF1B2C0) return(0x0000);
560 if (offset==0xF1B2C2) return(0x0000);
563 // pour permettre � wolfenstein 3d de tourner sans le dsp
564 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
568 // pour permettre � nba jam de tourner sans le dsp
569 /* if (jaguar_mainRom_crc32==0x4faddb18)
571 if (offset==0xf1b2c0) return(0);
572 if (offset==0xf1b2c2) return(0);
573 if (offset==0xf1b240) return(0);
574 if (offset==0xf1b242) return(0);
575 if (offset==0xF1B340) return(0);
576 if (offset==0xF1B342) return(0);
577 if (offset==0xF1BAD8) return(0);
578 if (offset==0xF1BADA) return(0);
579 if (offset==0xF1B040) return(0);
580 if (offset==0xF1B042) return(0);
581 if (offset==0xF1B0C0) return(0);
582 if (offset==0xF1B0C2) return(0);
583 if (offset==0xF1B140) return(0);
584 if (offset==0xF1B142) return(0);
585 if (offset==0xF1B1C0) return(0);
586 if (offset==0xF1B1C2) return(0);
589 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
591 offset -= DSP_WORK_RAM_BASE;
592 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
594 return GET16(dsp_ram_8, offset);
596 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
598 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
601 return data & 0xFFFF;
606 return JaguarReadWord(offset, who);
609 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
611 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
612 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
615 offset &= 0xFFFFFFFC;
616 /*if (offset == 0xF1BCF4)
618 WriteLog("DSPReadLong: Reading from 0xF1BCF4... -> %08X [%02X %02X %02X %02X][%04X %04X]\n", GET32(dsp_ram_8, 0x0CF4), dsp_ram_8[0x0CF4], dsp_ram_8[0x0CF5], dsp_ram_8[0x0CF6], dsp_ram_8[0x0CF7], JaguarReadWord(0xF1BCF4, DSP), JaguarReadWord(0xF1BCF6, DSP));
619 DSPDumpDisassembly();
621 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
623 offset -= DSP_WORK_RAM_BASE;
624 return GET32(dsp_ram_8, offset);
626 //NOTE: Didn't return DSP_ACCUM!!!
627 //Mebbe it's not 'spose to! Yes, it is!
628 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
633 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
634 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
635 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
637 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
638 return dsp_flags & 0xFFFFC1FF;
639 case 0x04: return dsp_matrix_control;
640 case 0x08: return dsp_pointer_to_matrix;
641 case 0x0C: return dsp_data_organization;
642 case 0x10: return dsp_pc;
643 case 0x14: return dsp_control;
644 case 0x18: return dsp_modulo;
645 case 0x1C: return dsp_remain;
647 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
649 // unaligned long read-- !!! FIX !!!
653 return JaguarReadLong(offset, who);
656 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
658 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
659 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
661 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
663 offset -= DSP_WORK_RAM_BASE;
664 dsp_ram_8[offset] = data;
665 //This is rather stupid! !!! FIX !!!
666 /* if (dsp_in_exec == 0)
668 m68k_end_timeslice();
669 dsp_releaseTimeslice();
673 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
675 uint32 reg = offset & 0x1C;
676 int bytenum = offset & 0x03;
678 if ((reg >= 0x1C) && (reg <= 0x1F))
679 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
682 //This looks funky. !!! FIX !!!
683 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
684 bytenum = 3 - bytenum; // convention motorola !!!
685 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
686 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
690 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
691 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
692 JaguarWriteByte(offset, data, who);
695 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
697 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
698 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
699 offset &= 0xFFFFFFFE;
700 /*if (offset == 0xF1BCF4)
702 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
704 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
705 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
707 /*if (offset == 0xF1B2F4)
709 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
711 offset -= DSP_WORK_RAM_BASE;
712 dsp_ram_8[offset] = data >> 8;
713 dsp_ram_8[offset+1] = data & 0xFF;
714 //This is rather stupid! !!! FIX !!!
715 /* if (dsp_in_exec == 0)
717 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
718 m68k_end_timeslice();
719 dsp_releaseTimeslice();
723 SET16(ram1, offset, data),
724 SET16(ram2, offset, data);
729 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
731 if ((offset & 0x1C) == 0x1C)
734 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
736 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
740 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
742 old_data = (old_data&0xffff0000)|(data&0xffff);
744 old_data = (old_data&0xffff)|((data&0xffff)<<16);
745 DSPWriteLong(offset & 0xffffffc, old_data, who);
750 JaguarWriteWord(offset, data, who);
753 //bool badWrite = false;
754 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
756 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
757 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
759 offset &= 0xFFFFFFFC;
760 /*if (offset == 0xF1BCF4)
762 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
764 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
765 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
767 /*if (offset == 0xF1BE2C)
769 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
771 offset -= DSP_WORK_RAM_BASE;
772 SET32(dsp_ram_8, offset, data);
775 SET32(ram1, offset, data),
776 SET32(ram2, offset, data);
781 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
789 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
791 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
792 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
794 dsp_flag_z = dsp_flags & 0x01;
795 dsp_flag_c = (dsp_flags >> 1) & 0x01;
796 dsp_flag_n = (dsp_flags >> 2) & 0x01;
797 DSPUpdateRegisterBanks();
798 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
799 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
801 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
802 // It can be timed to anything really, anything that writes to L/RTXD at a regular
803 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
804 // interrupt, so that's what we check for here. Just know that this approach
805 // can be easily fooled!
806 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
809 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
810 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
811 // So, while this works, it's a by-product of the lame way in which audio is currently
812 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
813 // go away of its own accord. :-P
814 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
815 // weird is going on here...
816 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
817 // So subsequent interrupts come into the chip, but they're never serviced but the
818 // I2S subsystem keeps going.
819 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
820 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
821 // It seems that it's only stable for values of SCLK <= 9.
823 if (data & INT_ENA1) // I2S interrupt
825 int freq = GetCalculatedFrequency();
826 //This happens too often to be useful...
827 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
828 DACSetNewFrequency(freq);
830 else if (data & INT_ENA2) // TIMER 0 interrupt
832 int freq = JERRYGetPIT1Frequency();
833 //This happens too often to be useful...
834 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
835 DACSetNewFrequency(freq);
838 /* if (IMASKCleared) // If IMASK was cleared,
841 WriteLog("DSP: Finished interrupt.\n");
843 DSPHandleIRQs(); // see if any other interrupts need servicing!
848 if (/*4-8, 16*/data & 0x101F0)
849 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
850 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
851 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
852 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
853 /*if (data & 0x00020) // CD BIOS DSP code...
855 //001AC1BA: movea.l #$1AC200, A0
856 //001AC1C0: move.l #$1AC68C, D0
859 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
860 uint32 j = 0xF1B97C;//0x1AC200;
861 while (j <= 0xF1BE08)//0x1AC68C)
864 j += dasmjag(JAGUAR_DSP, buffer, j);
865 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
866 WriteLog("\t%08X: %s\n", oldj, buffer);
873 dsp_matrix_control = data;
876 // According to JTRM, only lines 2-11 are addressable, the rest being
877 // hardwired to $F1Bxxx.
878 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
881 dsp_data_organization = data;
886 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
891 ctrl1[0] = ctrl2[0] = data;
898 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
900 bool wasRunning = DSP_RUNNING;
901 // uint32 dsp_was_running = DSP_RUNNING;
902 // Check for DSP -> CPU interrupt
906 WriteLog("DSP: DSP -> CPU interrupt\n");
909 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
910 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
911 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
913 JERRYSetPendingIRQ(IRQ2_DSP);
914 DSPReleaseTimeslice();
915 m68k_set_irq(2); // Set 68000 IPL 2...
919 // Check for CPU -> DSP interrupt
923 WriteLog("DSP: CPU -> DSP interrupt\n");
925 m68k_end_timeslice();
926 DSPReleaseTimeslice();
927 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
931 if (data & SINGLE_STEP)
933 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
936 // Protect writes to VERSION and the interrupt latches...
937 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
938 dsp_control = (dsp_control & mask) | (data & ~mask);
942 ctrl1[8] = ctrl2[8] = dsp_control;
946 // if dsp wasn't running but is now running
947 // execute a few cycles
948 //This is just plain wrong, wrong, WRONG!
949 #ifndef DSP_SINGLE_STEPPING
950 /* if (!dsp_was_running && DSP_RUNNING)
955 //This is WRONG! !!! FIX !!!
956 if (dsp_control & 0x18)
961 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
963 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
966 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
967 // !!! FIX !!! [DONE]
971 m68k_end_timeslice();
973 DSPReleaseTimeslice();
977 //DSPDumpDisassembly();
985 dsp_div_control = data;
987 // default: // unaligned long read
993 //We don't have to break this up like this! We CAN do 32 bit writes!
994 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
995 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
996 //if (offset > 0xF1FFFF)
998 JaguarWriteLong(offset, data, who);
1002 // Update the DSP register file pointers depending on REGPAGE bit
1004 void DSPUpdateRegisterBanks(void)
1006 int bank = (dsp_flags & REGPAGE);
1008 if (dsp_flags & IMASK)
1009 bank = 0; // IMASK forces main bank to be bank 0
1012 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1014 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1018 // Check for and handle any asserted DSP IRQs
1020 void DSPHandleIRQs(void)
1022 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1025 // Get the active interrupt bits (latches) & interrupt mask (enables)
1026 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1027 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1029 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1032 if (!bits) // Bail if nothing is enabled
1035 int which = 0; // Determine which interrupt
1049 #ifdef DSP_DEBUG_IRQ
1050 WriteLog("DSP: Generating interrupt #%i...", which);
1053 //if (which == 0) doDSPDis = true;
1055 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1056 // directly into the pipeline, it has the side effect of ensuring that the
1057 // instruction interrupted also gets to do its writeback. We simulate that
1059 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1061 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1062 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1064 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1065 scoreboard[pipeline[plPtrWrite].operand2] = false;
1067 //This should be execute (or should it?--not sure now!)
1068 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1069 //and what just executed is now in the Write position...). So why didn't it do the
1070 //writeback into register 0?
1071 #ifdef DSP_DEBUG_IRQ
1072 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1073 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]);
1074 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]);
1075 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]);
1077 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1079 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1081 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1082 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1085 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1086 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1087 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1088 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1090 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1094 #ifndef NEW_SCOREBOARD
1095 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1096 scoreboard[pipeline[plPtrWrite].operand2] = false;
1098 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1099 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1100 if (scoreboard[pipeline[plPtrWrite].operand2])
1101 scoreboard[pipeline[plPtrWrite].operand2]--;
1108 ctrl2[4] = dsp_flags;
1111 DSPUpdateRegisterBanks();
1112 #ifdef DSP_DEBUG_IRQ
1113 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1114 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]);
1117 // subqt #4,r31 ; pre-decrement stack pointer
1118 // move pc,r30 ; address of interrupted code
1119 // store r30,(r31) ; store return address
1126 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1127 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1128 //It missed the place that it was supposed to come back to, so this is WRONG!
1130 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1132 // R -> baz (<- PC points here)
1133 // E -> bar (when it should point here!)
1136 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1137 // which means (assuming they're all 2 bytes long) that the code below will come back on
1138 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1139 // instruction stream...
1141 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1142 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1145 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1149 // movei #service_address,r30 ; pointer to ISR entry
1150 // jump (r30) ; jump to ISR
1152 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1155 ctrl2[0] = regs2[30] = dsp_pc;
1162 // Non-pipelined version...
1164 void DSPHandleIRQsNP(void)
1168 memcpy(dsp_ram_8, ram1, 0x2000);
1169 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1170 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1173 dsp_remain = ctrl1[2];
1174 dsp_modulo = ctrl1[3];
1175 dsp_flags = ctrl1[4];
1176 dsp_matrix_control = ctrl1[5];
1177 dsp_pointer_to_matrix = ctrl1[6];
1178 dsp_data_organization = ctrl1[7];
1179 dsp_control = ctrl1[8];
1180 dsp_div_control = ctrl1[9];
1181 IMASKCleared = ctrl1[10];
1182 dsp_flag_z = ctrl1[11];
1183 dsp_flag_n = ctrl1[12];
1184 dsp_flag_c = ctrl1[13];
1185 DSPUpdateRegisterBanks();
1188 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1191 // Get the active interrupt bits (latches) & interrupt mask (enables)
1192 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1193 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1195 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1198 if (!bits) // Bail if nothing is enabled
1201 int which = 0; // Determine which interrupt
1215 #ifdef DSP_DEBUG_IRQ
1216 WriteLog("DSP: Generating interrupt #%i...", which);
1222 ctrl1[4] = dsp_flags;
1225 DSPUpdateRegisterBanks();
1226 #ifdef DSP_DEBUG_IRQ
1227 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1230 // subqt #4,r31 ; pre-decrement stack pointer
1231 // move pc,r30 ; address of interrupted code
1232 // store r30,(r31) ; store return address
1239 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1242 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1246 // movei #service_address,r30 ; pointer to ISR entry
1247 // jump (r30) ; jump to ISR
1249 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1252 ctrl1[0] = regs1[30] = dsp_pc;
1258 // Set the specified DSP IRQ line to a given state
1260 void DSPSetIRQLine(int irqline, int state)
1262 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1263 uint32 mask = INT_LAT0 << irqline;
1264 dsp_control &= ~mask; // Clear the latch bit
1267 ctrl1[8] = ctrl2[8] = dsp_control;
1273 dsp_control |= mask; // Set the latch bit
1277 ctrl1[8] = ctrl2[8] = dsp_control;
1283 // Not sure if this is correct behavior, but according to JTRM,
1284 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1285 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1286 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1291 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1292 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1293 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1295 dsp_build_branch_condition_table();
1297 srandom(time(NULL)); // For randomizing local RAM
1302 dsp_pc = 0x00F1B000;
1303 dsp_acc = 0x00000000;
1304 dsp_remain = 0x00000000;
1305 dsp_modulo = 0xFFFFFFFF;
1306 dsp_flags = 0x00040000;
1307 dsp_matrix_control = 0x00000000;
1308 dsp_pointer_to_matrix = 0x00000000;
1309 dsp_data_organization = 0xFFFFFFFF;
1310 dsp_control = 0x00002000; // Report DSP version 2
1311 dsp_div_control = 0x00000000;
1314 dsp_reg = dsp_reg_bank_0;
1315 dsp_alternate_reg = dsp_reg_bank_1;
1317 for(int i=0; i<32; i++)
1318 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1321 IMASKCleared = false;
1324 // memset(dsp_ram_8, 0xFF, 0x2000);
1325 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1326 for(uint32 i=0; i<8192; i+=4)
1328 *((uint32 *)(&dsp_ram_8[i])) = random();
1332 void DSPDumpDisassembly(void)
1336 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1337 uint32 j = 0xF1B000;
1339 while (j <= 0xF1CFFF)
1342 j += dasmjag(JAGUAR_DSP, buffer, j);
1343 WriteLog("\t%08X: %s\n", oldj, buffer);
1347 void DSPDumpRegisters(void)
1349 //Shoud add modulus, etc to dump here...
1350 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1351 WriteLog("\nRegisters bank 0\n");
1353 for(int j=0; j<8; j++)
1355 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1356 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1357 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1358 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1359 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1362 WriteLog("Registers bank 1\n");
1364 for(int j=0; j<8; j++)
1366 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1367 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1368 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1369 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1370 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1377 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1378 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1380 // get the active interrupt bits
1381 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1382 // get the interrupt mask
1383 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1385 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1386 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1387 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1388 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1389 WriteLog("\nRegisters bank 0\n");
1391 for(int j=0; j<8; j++)
1393 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1394 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1395 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1396 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1397 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1400 WriteLog("\nRegisters bank 1\n");
1404 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1405 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1406 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1407 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1408 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1413 static char buffer[512];
1414 j = DSP_WORK_RAM_BASE;
1416 while (j <= 0xF1CFFF)
1419 j += dasmjag(JAGUAR_DSP, buffer, j);
1420 WriteLog("\t%08X: %s\n", oldj, buffer);
1423 WriteLog("DSP opcodes use:\n");
1427 if (dsp_opcode_use[i])
1428 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1431 // memory_free(dsp_ram_8);
1432 // memory_free(dsp_reg_bank_0);
1433 // memory_free(dsp_reg_bank_1);
1434 // if (dsp_branch_condition_table)
1435 // free(dsp_branch_condition_table);
1437 // if (mirror_table)
1438 // free(mirror_table);
1444 // DSP comparison core...
1447 static uint16 lastExec;
1448 void DSPExecComp(int32 cycles)
1450 while (cycles > 0 && DSP_RUNNING)
1452 // Load up vars for non-pipelined core
1453 memcpy(dsp_ram_8, ram1, 0x2000);
1454 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1455 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1458 dsp_remain = ctrl1[2];
1459 dsp_modulo = ctrl1[3];
1460 dsp_flags = ctrl1[4];
1461 dsp_matrix_control = ctrl1[5];
1462 dsp_pointer_to_matrix = ctrl1[6];
1463 dsp_data_organization = ctrl1[7];
1464 dsp_control = ctrl1[8];
1465 dsp_div_control = ctrl1[9];
1466 IMASKCleared = ctrl1[10];
1467 dsp_flag_z = ctrl1[11];
1468 dsp_flag_n = ctrl1[12];
1469 dsp_flag_c = ctrl1[13];
1470 DSPUpdateRegisterBanks();
1472 // Decrement cycles based on non-pipelined core...
1473 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1474 cycles -= dsp_opcode_cycles[instr1 >> 10];
1476 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1477 DSPExec(1); // Do *one* instruction
1480 memcpy(ram1, dsp_ram_8, 0x2000);
1481 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1482 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1485 ctrl1[2] = dsp_remain;
1486 ctrl1[3] = dsp_modulo;
1487 ctrl1[4] = dsp_flags;
1488 ctrl1[5] = dsp_matrix_control;
1489 ctrl1[6] = dsp_pointer_to_matrix;
1490 ctrl1[7] = dsp_data_organization;
1491 ctrl1[8] = dsp_control;
1492 ctrl1[9] = dsp_div_control;
1493 ctrl1[10] = IMASKCleared;
1494 ctrl1[11] = dsp_flag_z;
1495 ctrl1[12] = dsp_flag_n;
1496 ctrl1[13] = dsp_flag_c;
1498 // Load up vars for pipelined core
1499 memcpy(dsp_ram_8, ram2, 0x2000);
1500 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1501 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1504 dsp_remain = ctrl2[2];
1505 dsp_modulo = ctrl2[3];
1506 dsp_flags = ctrl2[4];
1507 dsp_matrix_control = ctrl2[5];
1508 dsp_pointer_to_matrix = ctrl2[6];
1509 dsp_data_organization = ctrl2[7];
1510 dsp_control = ctrl2[8];
1511 dsp_div_control = ctrl2[9];
1512 IMASKCleared = ctrl2[10];
1513 dsp_flag_z = ctrl2[11];
1514 dsp_flag_n = ctrl2[12];
1515 dsp_flag_c = ctrl2[13];
1516 DSPUpdateRegisterBanks();
1518 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1519 DSPExecP2(1); // Do *one* instruction
1522 memcpy(ram2, dsp_ram_8, 0x2000);
1523 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1524 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1527 ctrl2[2] = dsp_remain;
1528 ctrl2[3] = dsp_modulo;
1529 ctrl2[4] = dsp_flags;
1530 ctrl2[5] = dsp_matrix_control;
1531 ctrl2[6] = dsp_pointer_to_matrix;
1532 ctrl2[7] = dsp_data_organization;
1533 ctrl2[8] = dsp_control;
1534 ctrl2[9] = dsp_div_control;
1535 ctrl2[10] = IMASKCleared;
1536 ctrl2[11] = dsp_flag_z;
1537 ctrl2[12] = dsp_flag_n;
1538 ctrl2[13] = dsp_flag_c;
1540 if (instr1 != lastExec)
1542 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1544 // 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));
1545 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1546 // if (ctrl1[0] < ppc) // P ran ahead of NP
1547 //How to test this crap???
1550 DSPExecP2(1); // Do one more instruction
1553 memcpy(ram2, dsp_ram_8, 0x2000);
1554 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1555 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1558 ctrl2[2] = dsp_remain;
1559 ctrl2[3] = dsp_modulo;
1560 ctrl2[4] = dsp_flags;
1561 ctrl2[5] = dsp_matrix_control;
1562 ctrl2[6] = dsp_pointer_to_matrix;
1563 ctrl2[7] = dsp_data_organization;
1564 ctrl2[8] = dsp_control;
1565 ctrl2[9] = dsp_div_control;
1566 ctrl2[10] = IMASKCleared;
1567 ctrl2[11] = dsp_flag_z;
1568 ctrl2[12] = dsp_flag_n;
1569 ctrl2[13] = dsp_flag_c;
1571 // else // NP ran ahead of P
1572 if (instr1 != lastExec) // Must be the other way...
1575 // Load up vars for non-pipelined core
1576 memcpy(dsp_ram_8, ram1, 0x2000);
1577 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1578 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1581 dsp_remain = ctrl1[2];
1582 dsp_modulo = ctrl1[3];
1583 dsp_flags = ctrl1[4];
1584 dsp_matrix_control = ctrl1[5];
1585 dsp_pointer_to_matrix = ctrl1[6];
1586 dsp_data_organization = ctrl1[7];
1587 dsp_control = ctrl1[8];
1588 dsp_div_control = ctrl1[9];
1589 IMASKCleared = ctrl1[10];
1590 dsp_flag_z = ctrl1[11];
1591 dsp_flag_n = ctrl1[12];
1592 dsp_flag_c = ctrl1[13];
1593 DSPUpdateRegisterBanks();
1595 for(int k=0; k<2; k++)
1597 // Decrement cycles based on non-pipelined core...
1598 instr1 = DSPReadWord(dsp_pc, DSP);
1599 cycles -= dsp_opcode_cycles[instr1 >> 10];
1601 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1602 DSPExec(1); // Do *one* instruction
1606 memcpy(ram1, dsp_ram_8, 0x2000);
1607 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1608 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1611 ctrl1[2] = dsp_remain;
1612 ctrl1[3] = dsp_modulo;
1613 ctrl1[4] = dsp_flags;
1614 ctrl1[5] = dsp_matrix_control;
1615 ctrl1[6] = dsp_pointer_to_matrix;
1616 ctrl1[7] = dsp_data_organization;
1617 ctrl1[8] = dsp_control;
1618 ctrl1[9] = dsp_div_control;
1619 ctrl1[10] = IMASKCleared;
1620 ctrl1[11] = dsp_flag_z;
1621 ctrl1[12] = dsp_flag_n;
1622 ctrl1[13] = dsp_flag_c;
1626 if (instr1 != lastExec)
1628 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1630 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1631 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1644 // DSP execution core
1646 //static bool R20Set = false, tripwire = false;
1647 //static uint32 pcQueue[32], ptrPCQ = 0;
1648 void DSPExec(int32 cycles)
1650 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1651 dsp_check_if_i2s_interrupt_needed();*/
1653 #ifdef DSP_SINGLE_STEPPING
1654 if (dsp_control & 0x18)
1657 dsp_control &= ~0x10;
1660 //There is *no* good reason to do this here!
1662 dsp_releaseTimeSlice_flag = 0;
1665 while (cycles > 0 && DSP_RUNNING)
1667 /*extern uint32 totalFrames;
1668 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1669 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1670 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1672 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1675 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1677 if (dsp_pc == 0xF1B092)
1678 doDSPDis = false;//*/
1679 /*if (dsp_pc == 0xF1B140)
1680 doDSPDis = true;//*/
1682 if (IMASKCleared) // If IMASK was cleared,
1684 #ifdef DSP_DEBUG_IRQ
1685 WriteLog("DSP: Finished interrupt.\n");
1687 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1688 IMASKCleared = false;
1693 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1694 for(int i=0; i<80; i+=4)
1695 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1698 /*if (dsp_pc == 0xF1B55E)
1700 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1702 /*if (dsp_pc == 0xF1B7D2) // Start here???
1704 pcQueue[ptrPCQ++] = dsp_pc;
1706 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1707 uint32 index = opcode >> 10;
1708 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1709 dsp_opcode_second_parameter = opcode & 0x1F;
1711 dsp_opcode[index]();
1712 dsp_opcode_use[index]++;
1713 cycles -= dsp_opcode_cycles[index];
1714 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1716 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1719 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1721 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1723 DSPDumpDisassembly();
1726 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1729 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1732 WriteLog("\nBacktrace:\n");
1733 for(int i=0; i<32; i++)
1735 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1736 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1746 // DSP opcode handlers
1749 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1750 // can cause trouble because an interrupt can occur *before* the instruction following the
1751 // jump can execute... !!! FIX !!!
1752 static void dsp_opcode_jump(void)
1755 const char * condition[32] =
1756 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1757 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1758 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1759 "???", "???", "???", "F" };
1761 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);
1764 /* dsp_flag_c=dsp_flag_c?1:0;
1765 dsp_flag_z=dsp_flag_z?1:0;
1766 dsp_flag_n=dsp_flag_n?1:0;*/
1767 // KLUDGE: Used by BRANCH_CONDITION
1768 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1770 if (BRANCH_CONDITION(IMM_2))
1774 WriteLog("Branched!\n");
1776 uint32 delayed_pc = RM;
1778 dsp_pc = delayed_pc;
1783 WriteLog("Branch NOT taken.\n");
1787 static void dsp_opcode_jr(void)
1790 const char * condition[32] =
1791 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1792 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1793 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1794 "???", "???", "???", "F" };
1796 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);
1799 /* dsp_flag_c=dsp_flag_c?1:0;
1800 dsp_flag_z=dsp_flag_z?1:0;
1801 dsp_flag_n=dsp_flag_n?1:0;*/
1802 // KLUDGE: Used by BRANCH_CONDITION
1803 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1805 if (BRANCH_CONDITION(IMM_2))
1809 WriteLog("Branched!\n");
1811 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1812 int32 delayed_pc = dsp_pc + (offset * 2);
1814 dsp_pc = delayed_pc;
1819 WriteLog("Branch NOT taken.\n");
1823 static void dsp_opcode_add(void)
1827 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);
1829 uint32 res = RN + RM;
1830 SET_ZNC_ADD(RN, 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_addc(void)
1842 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);
1844 uint32 res = RN + RM + dsp_flag_c;
1845 uint32 carry = dsp_flag_c;
1846 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1847 SET_ZNC_ADD(RN + carry, RM, res);
1848 // SET_ZNC_ADD(RN, RM + carry, res);
1852 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);
1856 static void dsp_opcode_addq(void)
1860 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);
1862 uint32 r1 = dsp_convert_zero[IMM_1];
1863 uint32 res = RN + r1;
1864 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1868 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1872 static void dsp_opcode_sub(void)
1876 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);
1878 uint32 res = RN - RM;
1879 SET_ZNC_SUB(RN, RM, res);
1883 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);
1887 static void dsp_opcode_subc(void)
1891 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);
1893 uint32 res = RN - RM - dsp_flag_c;
1894 uint32 borrow = dsp_flag_c;
1895 SET_ZNC_SUB(RN - borrow, RM, res);
1899 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);
1903 static void dsp_opcode_subq(void)
1907 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);
1909 uint32 r1 = dsp_convert_zero[IMM_1];
1910 uint32 res = RN - r1;
1911 SET_ZNC_SUB(RN, r1, res);
1915 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1919 static void dsp_opcode_cmp(void)
1923 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);
1925 uint32 res = RN - RM;
1926 SET_ZNC_SUB(RN, RM, res);
1929 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1933 static void dsp_opcode_cmpq(void)
1935 static int32 sqtable[32] =
1936 { 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 };
1939 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);
1941 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1942 uint32 res = RN - r1;
1943 SET_ZNC_SUB(RN, r1, res);
1946 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1950 static void dsp_opcode_and(void)
1954 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);
1960 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);
1964 static void dsp_opcode_or(void)
1968 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);
1974 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);
1978 static void dsp_opcode_xor(void)
1982 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);
1988 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);
1992 static void dsp_opcode_not(void)
1996 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);
2002 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2006 static void dsp_opcode_move_pc(void)
2011 static void dsp_opcode_store_r14_indexed(void)
2013 #ifdef DSP_DIS_STORE14I
2015 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));
2017 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2018 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2020 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2024 static void dsp_opcode_store_r15_indexed(void)
2026 #ifdef DSP_DIS_STORE15I
2028 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));
2030 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2031 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2033 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2037 static void dsp_opcode_load_r14_ri(void)
2039 #ifdef DSP_DIS_LOAD14R
2041 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);
2043 #ifdef DSP_CORRECT_ALIGNMENT
2044 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2046 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2048 #ifdef DSP_DIS_LOAD14R
2050 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2054 static void dsp_opcode_load_r15_ri(void)
2056 #ifdef DSP_DIS_LOAD15R
2058 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);
2060 #ifdef DSP_CORRECT_ALIGNMENT
2061 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2063 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2065 #ifdef DSP_DIS_LOAD15R
2067 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2071 static void dsp_opcode_store_r14_ri(void)
2073 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2076 static void dsp_opcode_store_r15_ri(void)
2078 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2081 static void dsp_opcode_nop(void)
2085 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2089 static void dsp_opcode_storeb(void)
2091 #ifdef DSP_DIS_STOREB
2093 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);
2095 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2096 DSPWriteLong(RM, RN & 0xFF, DSP);
2098 JaguarWriteByte(RM, RN, DSP);
2101 static void dsp_opcode_storew(void)
2103 #ifdef DSP_DIS_STOREW
2105 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);
2107 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2108 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2109 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2111 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2113 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2114 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2116 JaguarWriteWord(RM, RN, DSP);
2120 static void dsp_opcode_store(void)
2122 #ifdef DSP_DIS_STORE
2124 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);
2126 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2127 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2129 DSPWriteLong(RM, RN, DSP);
2133 static void dsp_opcode_loadb(void)
2135 #ifdef DSP_DIS_LOADB
2137 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);
2139 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2140 RN = DSPReadLong(RM, DSP) & 0xFF;
2142 RN = JaguarReadByte(RM, DSP);
2143 #ifdef DSP_DIS_LOADB
2145 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2149 static void dsp_opcode_loadw(void)
2151 #ifdef DSP_DIS_LOADW
2153 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);
2155 #ifdef DSP_CORRECT_ALIGNMENT
2156 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2157 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2159 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2161 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2162 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2164 RN = JaguarReadWord(RM, DSP);
2166 #ifdef DSP_DIS_LOADW
2168 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2172 static void dsp_opcode_load(void)
2176 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);
2178 #ifdef DSP_CORRECT_ALIGNMENT
2179 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2181 RN = DSPReadLong(RM, DSP);
2185 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2189 static void dsp_opcode_load_r14_indexed(void)
2191 #ifdef DSP_DIS_LOAD14I
2193 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);
2195 #ifdef DSP_CORRECT_ALIGNMENT
2196 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2198 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2200 #ifdef DSP_DIS_LOAD14I
2202 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2206 static void dsp_opcode_load_r15_indexed(void)
2208 #ifdef DSP_DIS_LOAD15I
2210 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);
2212 #ifdef DSP_CORRECT_ALIGNMENT
2213 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2215 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2217 #ifdef DSP_DIS_LOAD15I
2219 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2223 static void dsp_opcode_movei(void)
2225 #ifdef DSP_DIS_MOVEI
2227 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);
2229 // This instruction is followed by 32-bit value in LSW / MSW format...
2230 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2232 #ifdef DSP_DIS_MOVEI
2234 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2238 static void dsp_opcode_moveta(void)
2240 #ifdef DSP_DIS_MOVETA
2242 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);
2245 #ifdef DSP_DIS_MOVETA
2247 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);
2251 static void dsp_opcode_movefa(void)
2253 #ifdef DSP_DIS_MOVEFA
2255 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);
2258 #ifdef DSP_DIS_MOVEFA
2260 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);
2264 static void dsp_opcode_move(void)
2268 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);
2273 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);
2277 static void dsp_opcode_moveq(void)
2279 #ifdef DSP_DIS_MOVEQ
2281 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);
2284 #ifdef DSP_DIS_MOVEQ
2286 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2290 static void dsp_opcode_resmac(void)
2292 #ifdef DSP_DIS_RESMAC
2294 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));
2296 RN = (uint32)dsp_acc;
2297 #ifdef DSP_DIS_RESMAC
2299 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2303 static void dsp_opcode_imult(void)
2305 #ifdef DSP_DIS_IMULT
2307 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);
2309 RN = (int16)RN * (int16)RM;
2311 #ifdef DSP_DIS_IMULT
2313 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);
2317 static void dsp_opcode_mult(void)
2321 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);
2323 RN = (uint16)RM * (uint16)RN;
2327 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);
2331 static void dsp_opcode_bclr(void)
2335 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);
2337 uint32 res = RN & ~(1 << IMM_1);
2342 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2346 static void dsp_opcode_btst(void)
2350 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);
2352 dsp_flag_z = (~RN >> IMM_1) & 1;
2355 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2359 static void dsp_opcode_bset(void)
2363 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);
2365 uint32 res = RN | (1 << IMM_1);
2370 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2374 static void dsp_opcode_subqt(void)
2376 #ifdef DSP_DIS_SUBQT
2378 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);
2380 RN -= dsp_convert_zero[IMM_1];
2381 #ifdef DSP_DIS_SUBQT
2383 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2387 static void dsp_opcode_addqt(void)
2389 #ifdef DSP_DIS_ADDQT
2391 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);
2393 RN += dsp_convert_zero[IMM_1];
2394 #ifdef DSP_DIS_ADDQT
2396 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2400 static void dsp_opcode_imacn(void)
2402 #ifdef DSP_DIS_IMACN
2404 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);
2406 int32 res = (int16)RM * (int16)RN;
2407 dsp_acc += (int64)res;
2408 //Should we AND the result to fit into 40 bits here???
2409 #ifdef DSP_DIS_IMACN
2411 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));
2415 static void dsp_opcode_mtoi(void)
2417 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2421 static void dsp_opcode_normi(void)
2428 while ((_Rm & 0xffc00000) == 0)
2433 while ((_Rm & 0xff800000) != 0)
2443 static void dsp_opcode_mmult(void)
2445 int count = dsp_matrix_control&0x0f;
2446 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2450 if (!(dsp_matrix_control & 0x10))
2452 for (int i = 0; i < count; i++)
2456 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2458 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2459 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2466 for (int i = 0; i < count; i++)
2470 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2472 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2473 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2478 RN = res = (int32)accum;
2480 //NOTE: The flags are set based upon the last add/multiply done...
2484 static void dsp_opcode_abs(void)
2488 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);
2493 if (_Rn == 0x80000000)
2497 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2498 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2503 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2507 static void dsp_opcode_div(void)
2514 if (dsp_div_control & 1)
2516 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2517 if (dsp_remain&0x80000000)
2519 RN = (((uint64)_Rn) << 16) / _Rm;
2523 dsp_remain = _Rn % _Rm;
2524 if (dsp_remain&0x80000000)
2533 static void dsp_opcode_imultn(void)
2535 #ifdef DSP_DIS_IMULTN
2537 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);
2539 // This is OK, since this multiply won't overflow 32 bits...
2540 int32 res = (int32)((int16)RN * (int16)RM);
2541 dsp_acc = (int64)res;
2543 #ifdef DSP_DIS_IMULTN
2545 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));
2549 static void dsp_opcode_neg(void)
2553 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);
2556 SET_ZNC_SUB(0, RN, res);
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_shlq(void)
2568 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);
2570 int32 r1 = 32 - IMM_1;
2571 uint32 res = RN << r1;
2572 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2576 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2580 static void dsp_opcode_shrq(void)
2584 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);
2586 int32 r1 = dsp_convert_zero[IMM_1];
2587 uint32 res = RN >> r1;
2588 SET_ZN(res); dsp_flag_c = RN & 1;
2592 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2596 static void dsp_opcode_ror(void)
2600 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);
2602 uint32 r1 = RM & 0x1F;
2603 uint32 res = (RN >> r1) | (RN << (32 - r1));
2604 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2608 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);
2612 static void dsp_opcode_rorq(void)
2616 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);
2618 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2620 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2622 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2625 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2629 static void dsp_opcode_sha(void)
2631 int32 sRm=(int32)RM;
2637 if (shift>=32) shift=32;
2638 dsp_flag_c=(_Rn&0x80000000)>>31;
2648 if (shift>=32) shift=32;
2652 _Rn=((int32)_Rn)>>1;
2660 static void dsp_opcode_sharq(void)
2662 #ifdef DSP_DIS_SHARQ
2664 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);
2666 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2667 SET_ZN(res); dsp_flag_c = RN & 0x01;
2669 #ifdef DSP_DIS_SHARQ
2671 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2675 static void dsp_opcode_sh(void)
2677 int32 sRm=(int32)RM;
2682 uint32 shift=(-sRm);
2683 if (shift>=32) shift=32;
2684 dsp_flag_c=(_Rn&0x80000000)>>31;
2694 if (shift>=32) shift=32;
2706 void dsp_opcode_addqmod(void)
2708 #ifdef DSP_DIS_ADDQMOD
2710 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);
2712 uint32 r1 = dsp_convert_zero[IMM_1];
2714 uint32 res = r2 + r1;
2715 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2717 SET_ZNC_ADD(r2, r1, res);
2718 #ifdef DSP_DIS_ADDQMOD
2720 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2724 void dsp_opcode_subqmod(void)
2726 uint32 r1 = dsp_convert_zero[IMM_1];
2728 uint32 res = r2 - r1;
2729 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2732 SET_ZNC_SUB(r2, r1, res);
2735 void dsp_opcode_mirror(void)
2738 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2742 void dsp_opcode_sat32s(void)
2744 int32 r2 = (uint32)RN;
2745 int32 temp = dsp_acc >> 32;
2746 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2751 void dsp_opcode_sat16s(void)
2754 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2760 // New pipelined DSP core
2763 static void DSP_abs(void);
2764 static void DSP_add(void);
2765 static void DSP_addc(void);
2766 static void DSP_addq(void);
2767 static void DSP_addqmod(void);
2768 static void DSP_addqt(void);
2769 static void DSP_and(void);
2770 static void DSP_bclr(void);
2771 static void DSP_bset(void);
2772 static void DSP_btst(void);
2773 static void DSP_cmp(void);
2774 static void DSP_cmpq(void);
2775 static void DSP_div(void);
2776 static void DSP_imacn(void);
2777 static void DSP_imult(void);
2778 static void DSP_imultn(void);
2779 static void DSP_illegal(void);
2780 static void DSP_jr(void);
2781 static void DSP_jump(void);
2782 static void DSP_load(void);
2783 static void DSP_loadb(void);
2784 static void DSP_loadw(void);
2785 static void DSP_load_r14_i(void);
2786 static void DSP_load_r14_r(void);
2787 static void DSP_load_r15_i(void);
2788 static void DSP_load_r15_r(void);
2789 static void DSP_mirror(void);
2790 static void DSP_mmult(void);
2791 static void DSP_move(void);
2792 static void DSP_movefa(void);
2793 static void DSP_movei(void);
2794 static void DSP_movepc(void);
2795 static void DSP_moveq(void);
2796 static void DSP_moveta(void);
2797 static void DSP_mtoi(void);
2798 static void DSP_mult(void);
2799 static void DSP_neg(void);
2800 static void DSP_nop(void);
2801 static void DSP_normi(void);
2802 static void DSP_not(void);
2803 static void DSP_or(void);
2804 static void DSP_resmac(void);
2805 static void DSP_ror(void);
2806 static void DSP_rorq(void);
2807 static void DSP_sat16s(void);
2808 static void DSP_sat32s(void);
2809 static void DSP_sh(void);
2810 static void DSP_sha(void);
2811 static void DSP_sharq(void);
2812 static void DSP_shlq(void);
2813 static void DSP_shrq(void);
2814 static void DSP_store(void);
2815 static void DSP_storeb(void);
2816 static void DSP_storew(void);
2817 static void DSP_store_r14_i(void);
2818 static void DSP_store_r14_r(void);
2819 static void DSP_store_r15_i(void);
2820 static void DSP_store_r15_r(void);
2821 static void DSP_sub(void);
2822 static void DSP_subc(void);
2823 static void DSP_subq(void);
2824 static void DSP_subqmod(void);
2825 static void DSP_subqt(void);
2826 static void DSP_xor(void);
2828 void (* DSPOpcode[64])() =
2830 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2831 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2832 DSP_neg, DSP_and, DSP_or, DSP_xor,
2833 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2835 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2836 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2837 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2838 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2840 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2841 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2842 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2843 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2845 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2846 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2847 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2848 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2851 bool readAffected[64][2] =
2853 { true, true}, { true, true}, {false, true}, {false, true},
2854 { true, true}, { true, true}, {false, true}, {false, true},
2855 {false, true}, { true, true}, { true, true}, { true, true},
2856 {false, true}, {false, true}, {false, true}, {false, true},
2858 { true, true}, { true, true}, { true, true}, {false, true},
2859 { true, true}, { true, true}, {false, true}, { true, true},
2860 {false, true}, {false, true}, { true, true}, {false, true},
2861 { true, true}, {false, true}, { true, true}, {false, true},
2863 {false, true}, {false, true}, { true, false}, {false, false},
2864 { true, false}, {false, false}, {false, false}, { true, false},
2865 { true, false}, { true, false}, {false, true}, { true, false},
2866 { true, false}, { true, true}, { true, true}, { true, true},
2868 {false, true}, { true, true}, { true, true}, {false, true},
2869 { true, false}, { true, false}, { true, true}, { true, false},
2870 { true, false}, {false, false}, { true, false}, { true, false},
2871 { true, true}, { true, true}, {false, false}, {false, true}
2874 bool isLoadStore[65] =
2876 false, false, false, false, false, false, false, false,
2877 false, false, false, false, false, false, false, false,
2879 false, false, false, false, false, false, false, false,
2880 false, false, false, false, false, false, false, false,
2882 false, false, false, false, false, false, false, true,
2883 true, true, false, true, true, true, true, true,
2885 false, true, true, false, false, false, false, false,
2886 false, false, true, true, true, true, false, false, false
2889 void FlushDSPPipeline(void)
2891 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2893 for(int i=0; i<4; i++)
2894 pipeline[i].opcode = PIPELINE_STALL;
2896 for(int i=0; i<32; i++)
2901 // New pipelined DSP execution core
2903 /*void DSPExecP(int32 cycles)
2905 // bool inhibitFetch = false;
2907 dsp_releaseTimeSlice_flag = 0;
2910 while (cycles > 0 && DSP_RUNNING)
2912 WriteLog("DSPExecP: Pipeline status...\n");
2913 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);
2914 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);
2915 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);
2916 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);
2917 WriteLog(" --> Scoreboard: ");
2918 for(int i=0; i<32; i++)
2919 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2921 // Stage 1: Instruction fetch
2922 // if (!inhibitFetch)
2924 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2925 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2926 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2927 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2928 if (pipeline[plPtrFetch].opcode == 38)
2929 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2930 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2933 // inhibitFetch = false;
2934 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2936 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2937 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);
2938 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);
2939 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);
2940 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);
2941 // Stage 2: Read registers
2942 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2943 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2944 if (scoreboard[pipeline[plPtrRead].operand2])
2945 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2946 // We have a hit in the scoreboard, so we have to stall the pipeline...
2948 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2949 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2950 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2951 pipeline[plPtrFetch] = pipeline[plPtrRead];
2952 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2956 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2957 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2958 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2960 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2961 // Shouldn't we be more selective with the register scoreboarding?
2962 // Yes, we should. !!! FIX !!!
2963 scoreboard[pipeline[plPtrRead].operand2] = true;
2964 //Advance PC here??? Yes.
2965 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2966 //This is a mangling of the pipeline stages, but what else to do???
2967 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2970 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2971 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);
2972 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);
2973 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);
2974 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);
2976 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2978 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2979 DSPOpcode[pipeline[plPtrExec].opcode]();
2980 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2981 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2986 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2987 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);
2988 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);
2989 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);
2990 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);
2991 // Stage 4: Write back register
2992 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2994 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2995 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2997 scoreboard[pipeline[plPtrWrite].operand1]
2998 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3001 // Push instructions through the pipeline...
3002 plPtrFetch = (++plPtrFetch) & 0x03;
3003 plPtrRead = (++plPtrRead) & 0x03;
3004 plPtrExec = (++plPtrExec) & 0x03;
3005 plPtrWrite = (++plPtrWrite) & 0x03;
3012 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3014 // Should be fixed now. Another problem is figuring how to do the sequence following
3015 // a branch followed with the JR & JUMP instructions...
3017 // There are two conflicting problems:
3020 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3021 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3022 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3023 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3024 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3025 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3026 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3027 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3028 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3029 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3030 DSP: Finished interrupt.
3031 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3032 ; bank 0 (where is was prepared)!
3033 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3034 F1B252: NOP [NCZ:001]
3037 // The other is when you see this at the end of an IRQ:
3040 JUMP T, (R29) ; R29 = Previous stack + 2
3041 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3043 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3044 ; 1) The STORE goes through the pipeline and is executed/written back
3045 ; 2) The pipeline is flushed
3046 ; 3) The DSP_PC is set to the new address
3047 ; 4) Execution resumes
3049 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3050 ; bank 0 instead of the current bank 1 and so goes astray!
3053 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3054 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3058 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3059 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3060 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3061 If it were done properly, the STORE write back would occur *after* (well, technically,
3062 during) the execution of the the JUMP that follows it.
3066 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3067 F1B08A: NOP [NCZ:001]
3069 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3072 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3075 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3076 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3077 F1B08A: NOP [NCZ:001]
3079 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3082 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3083 DSP: CPU -> DSP interrupt
3084 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3085 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3087 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3090 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3091 F1B006: NOP [NCZ:001]
3093 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3096 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3097 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3100 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3101 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3104 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3105 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3108 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3109 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3112 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3115 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3118 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3119 F1B0FE: NOP [NCZ:000]
3121 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3124 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3127 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3128 F1B138: NOP [NCZ:000]
3130 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3133 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3134 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3135 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3138 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3139 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3142 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3143 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3144 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3146 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3147 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3150 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3151 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3152 DSP: Finished interrupt.
3153 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3155 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3158 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3159 F1B016: NOP [NCZ:001]
3161 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3164 uint32 pcQueue1[0x400];
3166 static uint32 prevR1;
3167 //Let's try a 3 stage pipeline....
3168 //Looks like 3 stage is correct, otherwise bad things happen...
3169 void DSPExecP2(int32 cycles)
3171 dsp_releaseTimeSlice_flag = 0;
3174 while (cycles > 0 && DSP_RUNNING)
3176 /*extern uint32 totalFrames;
3177 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3178 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3179 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3181 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3184 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3186 if (dsp_pc == 0xF1B092)
3187 doDSPDis = false;//*/
3188 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3189 doDSPDis = true;//*/
3190 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3191 doDSPDis = true;//*/
3192 /*if (dsp_pc == 0xF1B0A0)
3193 doDSPDis = true;//*/
3194 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3195 doDSPDis = true;//*/
3196 //Two parter... (not sure how to write this)
3197 //if (dsp_pc == 0xF1B0D2)
3198 // prevR1 = dsp_reg[1];
3200 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3201 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3204 pcQueue1[pcQPtr1++] = dsp_pc;
3207 #ifdef DSP_DEBUG_PL2
3208 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3210 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3215 for(int i=0; i<0x400; i++)
3217 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3218 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3224 if (IMASKCleared) // If IMASK was cleared,
3226 #ifdef DSP_DEBUG_IRQ
3227 WriteLog("DSP: Finished interrupt.\n");
3229 DSPHandleIRQs(); // See if any other interrupts are pending!
3230 IMASKCleared = false;
3233 //if (dsp_flags & REGPAGE)
3234 // WriteLog(" --> REGPAGE has just been set!\n");
3235 #ifdef DSP_DEBUG_PL2
3238 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3239 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]);
3240 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]);
3241 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]);
3242 WriteLog(" --> Scoreboard: ");
3243 for(int i=0; i<32; i++)
3244 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3248 // Stage 1a: Instruction fetch
3249 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3250 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3251 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3252 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3253 if (pipeline[plPtrRead].opcode == 38)
3254 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3255 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3256 #ifdef DSP_DEBUG_PL2
3259 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3260 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3261 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]);
3262 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]);
3263 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]);
3266 // Stage 1b: Read registers
3267 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3268 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3270 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3271 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3272 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3273 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3274 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3275 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3276 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3278 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3279 // We have a hit in the scoreboard, so we have to stall the pipeline...
3280 #ifdef DSP_DEBUG_PL2
3284 WriteLog(" --> Stalling pipeline: ");
3285 if (readAffected[pipeline[plPtrRead].opcode][0])
3286 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3287 if (readAffected[pipeline[plPtrRead].opcode][1])
3288 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3292 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3293 #ifdef DSP_DEBUG_PL2
3298 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3299 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3300 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3302 // Shouldn't we be more selective with the register scoreboarding?
3303 // Yes, we should. !!! FIX !!! Kinda [DONE]
3304 #ifndef NEW_SCOREBOARD
3305 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3307 //Hopefully this will fix the dual MOVEQ # problem...
3308 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3311 //Advance PC here??? Yes.
3312 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3315 #ifdef DSP_DEBUG_PL2
3318 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3319 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]);
3320 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]);
3321 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]);
3325 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3327 #ifdef DSP_DEBUG_PL2
3329 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"));
3333 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3338 lastExec = pipeline[plPtrExec].instruction;
3339 //WriteLog("[lastExec = %04X]\n", lastExec);
3341 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3342 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3343 DSPOpcode[pipeline[plPtrExec].opcode]();
3344 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3348 //Let's not, until we do the stalling correctly...
3349 //But, we gotta while we're doing the comparison core...!
3350 //Or do we? cycles--;
3351 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3352 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3353 //to model this clock cycle behavior correctly...
3354 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3355 //don't affect the reads at stage 1...
3356 #ifdef DSP_DEBUG_STALL
3358 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3362 #ifdef DSP_DEBUG_PL2
3365 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3366 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]);
3367 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]);
3368 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]);
3372 // Stage 3: Write back register/memory address
3373 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3375 /*if (pipeline[plPtrWrite].writebackRegister == 3
3376 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3379 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3382 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3384 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3385 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3388 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3389 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3390 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3391 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3393 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3397 #ifndef NEW_SCOREBOARD
3398 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3399 scoreboard[pipeline[plPtrWrite].operand2] = false;
3401 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3402 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3403 if (scoreboard[pipeline[plPtrWrite].operand2])
3404 scoreboard[pipeline[plPtrWrite].operand2]--;
3408 // Push instructions through the pipeline...
3409 plPtrRead = (++plPtrRead) & 0x03;
3410 plPtrExec = (++plPtrExec) & 0x03;
3411 plPtrWrite = (++plPtrWrite) & 0x03;
3420 //#define DSP_DEBUG_PL3
3421 //Let's try a 2 stage pipeline....
3422 void DSPExecP3(int32 cycles)
3424 dsp_releaseTimeSlice_flag = 0;
3427 while (cycles > 0 && DSP_RUNNING)
3429 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3431 #ifdef DSP_DEBUG_PL3
3432 WriteLog("DSPExecP: Pipeline status...\n");
3433 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]);
3434 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]);
3435 WriteLog(" --> Scoreboard: ");
3436 for(int i=0; i<32; i++)
3437 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3440 // Stage 1a: Instruction fetch
3441 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3442 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3443 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3444 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3445 if (pipeline[plPtrRead].opcode == 38)
3446 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3447 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3448 #ifdef DSP_DEBUG_PL3
3449 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3450 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3451 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]);
3452 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]);
3454 // Stage 1b: Read registers
3455 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3456 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3457 // We have a hit in the scoreboard, so we have to stall the pipeline...
3458 #ifdef DSP_DEBUG_PL3
3460 WriteLog(" --> Stalling pipeline: ");
3461 if (readAffected[pipeline[plPtrRead].opcode][0])
3462 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3463 if (readAffected[pipeline[plPtrRead].opcode][1])
3464 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3467 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3468 #ifdef DSP_DEBUG_PL3
3473 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3474 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3475 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3477 // Shouldn't we be more selective with the register scoreboarding?
3478 // Yes, we should. !!! FIX !!! [Kinda DONE]
3479 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3481 //Advance PC here??? Yes.
3482 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3485 #ifdef DSP_DEBUG_PL3
3486 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3487 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]);
3488 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]);
3490 // Stage 2a: Execute
3491 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3493 #ifdef DSP_DEBUG_PL3
3494 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3496 DSPOpcode[pipeline[plPtrExec].opcode]();
3497 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3498 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3503 #ifdef DSP_DEBUG_PL3
3504 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3505 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]);
3506 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]);
3509 // Stage 2b: Write back register
3510 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3512 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3513 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3515 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3516 scoreboard[pipeline[plPtrExec].operand2] = false;
3519 // Push instructions through the pipeline...
3520 plPtrRead = (++plPtrRead) & 0x03;
3521 plPtrExec = (++plPtrExec) & 0x03;
3528 // DSP pipelined opcode handlers
3531 #define PRM pipeline[plPtrExec].reg1
3532 #define PRN pipeline[plPtrExec].reg2
3533 #define PIMM1 pipeline[plPtrExec].operand1
3534 #define PIMM2 pipeline[plPtrExec].operand2
3535 #define PRES pipeline[plPtrExec].result
3536 #define PWBR pipeline[plPtrExec].writebackRegister
3537 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3538 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3539 #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))
3540 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3542 static void DSP_abs(void)
3546 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);
3550 if (_Rn == 0x80000000)
3554 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3555 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3556 CLR_ZN; SET_Z(PRES);
3560 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3564 static void DSP_add(void)
3568 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);
3570 uint32 res = PRN + PRM;
3571 SET_ZNC_ADD(PRN, PRM, res);
3575 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);
3579 static void DSP_addc(void)
3583 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);
3585 uint32 res = PRN + PRM + dsp_flag_c;
3586 uint32 carry = dsp_flag_c;
3587 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3588 SET_ZNC_ADD(PRN + carry, PRM, res);
3589 // SET_ZNC_ADD(PRN, PRM + carry, res);
3593 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);
3597 static void DSP_addq(void)
3601 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);
3603 uint32 r1 = dsp_convert_zero[PIMM1];
3604 uint32 res = PRN + r1;
3605 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3609 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3613 static void DSP_addqmod(void)
3615 #ifdef DSP_DIS_ADDQMOD
3617 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);
3619 uint32 r1 = dsp_convert_zero[PIMM1];
3621 uint32 res = r2 + r1;
3622 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3624 SET_ZNC_ADD(r2, r1, res);
3625 #ifdef DSP_DIS_ADDQMOD
3627 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3631 static void DSP_addqt(void)
3633 #ifdef DSP_DIS_ADDQT
3635 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);
3637 PRES = PRN + dsp_convert_zero[PIMM1];
3638 #ifdef DSP_DIS_ADDQT
3640 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3644 static void DSP_and(void)
3648 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);
3654 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);
3658 static void DSP_bclr(void)
3662 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);
3664 PRES = PRN & ~(1 << PIMM1);
3668 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3672 static void DSP_bset(void)
3676 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);
3678 PRES = PRN | (1 << PIMM1);
3682 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3686 static void DSP_btst(void)
3690 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);
3692 dsp_flag_z = (~PRN >> PIMM1) & 1;
3696 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3700 static void DSP_cmp(void)
3704 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);
3706 uint32 res = PRN - PRM;
3707 SET_ZNC_SUB(PRN, PRM, res);
3711 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3715 static void DSP_cmpq(void)
3717 static int32 sqtable[32] =
3718 { 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 };
3721 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);
3723 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3724 uint32 res = PRN - r1;
3725 SET_ZNC_SUB(PRN, r1, res);
3729 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3733 static void DSP_div(void)
3735 uint32 _Rm = PRM, _Rn = PRN;
3739 if (dsp_div_control & 1)
3741 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3742 if (dsp_remain & 0x80000000)
3744 PRES = (((uint64)_Rn) << 16) / _Rm;
3748 dsp_remain = _Rn % _Rm;
3749 if (dsp_remain & 0x80000000)
3758 static void DSP_imacn(void)
3760 #ifdef DSP_DIS_IMACN
3762 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);
3764 int32 res = (int16)PRM * (int16)PRN;
3765 dsp_acc += (int64)res;
3766 //Should we AND the result to fit into 40 bits here???
3768 #ifdef DSP_DIS_IMACN
3770 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));
3774 static void DSP_imult(void)
3776 #ifdef DSP_DIS_IMULT
3778 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);
3780 PRES = (int16)PRN * (int16)PRM;
3782 #ifdef DSP_DIS_IMULT
3784 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);
3788 static void DSP_imultn(void)
3790 #ifdef DSP_DIS_IMULTN
3792 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);
3794 // This is OK, since this multiply won't overflow 32 bits...
3795 int32 res = (int32)((int16)PRN * (int16)PRM);
3796 dsp_acc = (int64)res;
3799 #ifdef DSP_DIS_IMULTN
3801 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));
3805 static void DSP_illegal(void)
3807 #ifdef DSP_DIS_ILLEGAL
3809 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3814 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3815 // can cause trouble because an interrupt can occur *before* the instruction following the
3816 // jump can execute... !!! FIX !!!
3817 // This can probably be solved by judicious coding in the pipeline execution core...
3818 // And should be fixed now...
3819 static void DSP_jr(void)
3822 const char * condition[32] =
3823 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3824 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3825 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3826 "???", "???", "???", "F" };
3828 //How come this is always off by 2???
3829 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);
3831 // KLUDGE: Used by BRANCH_CONDITION macro
3832 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3834 if (BRANCH_CONDITION(PIMM2))
3838 WriteLog("Branched!\n");
3840 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3841 //Account for pipeline effects...
3842 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3843 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3845 // Now that we've branched, we have to make sure that the following instruction
3846 // is executed atomically with this one and then flush the pipeline before setting
3849 // Step 1: Handle writebacks at stage 3 of pipeline
3850 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3852 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3853 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3855 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3856 scoreboard[pipeline[plPtrWrite].operand2] = false;
3858 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3860 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3862 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3863 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3866 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3867 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3868 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3869 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3871 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3875 #ifndef NEW_SCOREBOARD
3876 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3877 scoreboard[pipeline[plPtrWrite].operand2] = false;
3879 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3880 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3881 if (scoreboard[pipeline[plPtrWrite].operand2])
3882 scoreboard[pipeline[plPtrWrite].operand2]--;
3886 // Step 2: Push instruction through pipeline & execute following instruction
3887 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3888 // we effectively handle the final push of the instruction through the
3889 // pipeline when the new PC takes effect (since when we return, the
3890 // pipeline code will be executing the writeback stage. If we reverse
3891 // the execution order of the pipeline stages, this will no longer be
3893 pipeline[plPtrExec] = pipeline[plPtrRead];
3894 //This is BAD. We need to get that next opcode and execute it!
3895 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3896 // remove this crap.
3897 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3899 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3900 pipeline[plPtrExec].opcode = instruction >> 10;
3901 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3902 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3903 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3904 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3905 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3907 dsp_pc += 2; // For DSP_DIS_* accuracy
3908 DSPOpcode[pipeline[plPtrExec].opcode]();
3909 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3910 pipeline[plPtrWrite] = pipeline[plPtrExec];
3912 // Step 3: Flush pipeline & set new PC
3913 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3920 WriteLog("Branch NOT taken.\n");
3926 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3929 static void DSP_jump(void)
3932 const char * condition[32] =
3933 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3934 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3935 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3936 "???", "???", "???", "F" };
3938 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);
3940 // KLUDGE: Used by BRANCH_CONDITION macro
3941 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3943 if (BRANCH_CONDITION(PIMM2))
3947 WriteLog("Branched!\n");
3949 uint32 PCSave = PRM;
3950 // Now that we've branched, we have to make sure that the following instruction
3951 // is executed atomically with this one and then flush the pipeline before setting
3954 // Step 1: Handle writebacks at stage 3 of pipeline
3955 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3957 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3958 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3960 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3961 scoreboard[pipeline[plPtrWrite].operand2] = false;
3963 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3965 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3967 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3968 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3971 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3972 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3973 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3974 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3976 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3980 #ifndef NEW_SCOREBOARD
3981 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3982 scoreboard[pipeline[plPtrWrite].operand2] = false;
3984 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3985 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3986 if (scoreboard[pipeline[plPtrWrite].operand2])
3987 scoreboard[pipeline[plPtrWrite].operand2]--;
3991 // Step 2: Push instruction through pipeline & execute following instruction
3992 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3993 // we effectively handle the final push of the instruction through the
3994 // pipeline when the new PC takes effect (since when we return, the
3995 // pipeline code will be executing the writeback stage. If we reverse
3996 // the execution order of the pipeline stages, this will no longer be
3998 pipeline[plPtrExec] = pipeline[plPtrRead];
3999 //This is BAD. We need to get that next opcode and execute it!
4000 //Also, same problem in JR!
4001 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4002 // remove this crap.
4003 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
4005 uint16 instruction = DSPReadWord(dsp_pc, DSP);
4006 pipeline[plPtrExec].opcode = instruction >> 10;
4007 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4008 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4009 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4010 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4011 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4013 dsp_pc += 2; // For DSP_DIS_* accuracy
4014 DSPOpcode[pipeline[plPtrExec].opcode]();
4015 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4016 pipeline[plPtrWrite] = pipeline[plPtrExec];
4018 // Step 3: Flush pipeline & set new PC
4019 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4026 WriteLog("Branch NOT taken.\n");
4034 static void DSP_load(void)
4038 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);
4040 #ifdef DSP_CORRECT_ALIGNMENT
4041 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4043 PRES = DSPReadLong(PRM, DSP);
4047 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4051 static void DSP_loadb(void)
4053 #ifdef DSP_DIS_LOADB
4055 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);
4057 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4058 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4060 PRES = JaguarReadByte(PRM, DSP);
4061 #ifdef DSP_DIS_LOADB
4063 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4067 static void DSP_loadw(void)
4069 #ifdef DSP_DIS_LOADW
4071 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);
4073 #ifdef DSP_CORRECT_ALIGNMENT
4074 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4075 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4077 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4079 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4080 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4082 PRES = JaguarReadWord(PRM, DSP);
4084 #ifdef DSP_DIS_LOADW
4086 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4090 static void DSP_load_r14_i(void)
4092 #ifdef DSP_DIS_LOAD14I
4094 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);
4096 #ifdef DSP_CORRECT_ALIGNMENT
4097 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4099 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4101 #ifdef DSP_DIS_LOAD14I
4103 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4107 static void DSP_load_r14_r(void)
4109 #ifdef DSP_DIS_LOAD14R
4111 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);
4113 #ifdef DSP_CORRECT_ALIGNMENT
4114 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4116 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4118 #ifdef DSP_DIS_LOAD14R
4120 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4124 static void DSP_load_r15_i(void)
4126 #ifdef DSP_DIS_LOAD15I
4128 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);
4130 #ifdef DSP_CORRECT_ALIGNMENT
4131 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4133 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4135 #ifdef DSP_DIS_LOAD15I
4137 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4141 static void DSP_load_r15_r(void)
4143 #ifdef DSP_DIS_LOAD15R
4145 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);
4147 #ifdef DSP_CORRECT_ALIGNMENT
4148 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4150 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4152 #ifdef DSP_DIS_LOAD15R
4154 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4158 static void DSP_mirror(void)
4161 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4165 static void DSP_mmult(void)
4167 int count = dsp_matrix_control&0x0f;
4168 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4172 if (!(dsp_matrix_control & 0x10))
4174 for (int i = 0; i < count; i++)
4178 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4180 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4181 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4188 for (int i = 0; i < count; i++)
4192 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4194 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4195 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4201 PRES = res = (int32)accum;
4203 //NOTE: The flags are set based upon the last add/multiply done...
4207 static void DSP_move(void)
4211 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);
4216 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);
4220 static void DSP_movefa(void)
4222 #ifdef DSP_DIS_MOVEFA
4224 // 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);
4225 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);
4227 // PRES = ALTERNATE_RM;
4228 PRES = dsp_alternate_reg[PIMM1];
4229 #ifdef DSP_DIS_MOVEFA
4231 // 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);
4232 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);
4236 static void DSP_movei(void)
4238 #ifdef DSP_DIS_MOVEI
4240 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);
4242 // // This instruction is followed by 32-bit value in LSW / MSW format...
4243 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4245 #ifdef DSP_DIS_MOVEI
4247 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4251 static void DSP_movepc(void)
4253 #ifdef DSP_DIS_MOVEPC
4255 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);
4257 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4258 // PRES = dsp_pc - 2;
4259 //Account for pipeline effects...
4260 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4261 #ifdef DSP_DIS_MOVEPC
4263 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4267 static void DSP_moveq(void)
4269 #ifdef DSP_DIS_MOVEQ
4271 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);
4274 #ifdef DSP_DIS_MOVEQ
4276 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4280 static void DSP_moveta(void)
4282 #ifdef DSP_DIS_MOVETA
4284 // 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);
4285 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]);
4287 // ALTERNATE_RN = PRM;
4288 dsp_alternate_reg[PIMM2] = PRM;
4290 #ifdef DSP_DIS_MOVETA
4292 // 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);
4293 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]);
4297 static void DSP_mtoi(void)
4299 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4303 static void DSP_mult(void)
4307 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);
4309 PRES = (uint16)PRM * (uint16)PRN;
4313 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);
4317 static void DSP_neg(void)
4321 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);
4324 SET_ZNC_SUB(0, PRN, res);
4328 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4332 static void DSP_nop(void)
4336 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4341 static void DSP_normi(void)
4348 while ((_Rm & 0xffc00000) == 0)
4353 while ((_Rm & 0xff800000) != 0)
4363 static void DSP_not(void)
4367 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);
4373 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4377 static void DSP_or(void)
4381 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);
4387 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);
4391 static void DSP_resmac(void)
4393 #ifdef DSP_DIS_RESMAC
4395 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));
4397 PRES = (uint32)dsp_acc;
4398 #ifdef DSP_DIS_RESMAC
4400 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4404 static void DSP_ror(void)
4408 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);
4410 uint32 r1 = PRM & 0x1F;
4411 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4412 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4416 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);
4420 static void DSP_rorq(void)
4424 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);
4426 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4428 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4430 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4433 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4437 static void DSP_sat16s(void)
4440 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4445 static void DSP_sat32s(void)
4447 int32 r2 = (uint32)PRN;
4448 int32 temp = dsp_acc >> 32;
4449 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4454 static void DSP_sh(void)
4456 int32 sRm = (int32)PRM;
4461 uint32 shift = -sRm;
4466 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4481 dsp_flag_c = _Rn & 0x1;
4494 static void DSP_sha(void)
4496 int32 sRm = (int32)PRM;
4501 uint32 shift = -sRm;
4506 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4521 dsp_flag_c = _Rn & 0x1;
4525 _Rn = ((int32)_Rn) >> 1;
4534 static void DSP_sharq(void)
4536 #ifdef DSP_DIS_SHARQ
4538 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);
4540 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4541 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4543 #ifdef DSP_DIS_SHARQ
4545 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4549 static void DSP_shlq(void)
4553 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);
4555 int32 r1 = 32 - PIMM1;
4556 uint32 res = PRN << r1;
4557 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4561 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4565 static void DSP_shrq(void)
4569 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);
4571 int32 r1 = dsp_convert_zero[PIMM1];
4572 uint32 res = PRN >> r1;
4573 SET_ZN(res); dsp_flag_c = PRN & 1;
4577 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4581 static void DSP_store(void)
4583 #ifdef DSP_DIS_STORE
4585 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);
4587 // DSPWriteLong(PRM, PRN, DSP);
4589 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4590 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4592 pipeline[plPtrExec].address = PRM;
4594 pipeline[plPtrExec].value = PRN;
4595 pipeline[plPtrExec].type = TYPE_DWORD;
4599 static void DSP_storeb(void)
4601 #ifdef DSP_DIS_STOREB
4603 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);
4605 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4606 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4608 // JaguarWriteByte(PRM, PRN, DSP);
4611 pipeline[plPtrExec].address = PRM;
4613 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4615 pipeline[plPtrExec].value = PRN & 0xFF;
4616 pipeline[plPtrExec].type = TYPE_DWORD;
4620 pipeline[plPtrExec].value = PRN;
4621 pipeline[plPtrExec].type = TYPE_BYTE;
4627 static void DSP_storew(void)
4629 #ifdef DSP_DIS_STOREW
4631 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);
4633 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4634 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4636 // JaguarWriteWord(PRM, PRN, DSP);
4639 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4640 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4642 pipeline[plPtrExec].address = PRM;
4645 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4647 pipeline[plPtrExec].value = PRN & 0xFFFF;
4648 pipeline[plPtrExec].type = TYPE_DWORD;
4652 pipeline[plPtrExec].value = PRN;
4653 pipeline[plPtrExec].type = TYPE_WORD;
4658 static void DSP_store_r14_i(void)
4660 #ifdef DSP_DIS_STORE14I
4662 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));
4664 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4666 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4667 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4669 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4671 pipeline[plPtrExec].value = PRN;
4672 pipeline[plPtrExec].type = TYPE_DWORD;
4676 static void DSP_store_r14_r(void)
4678 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4680 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4681 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4683 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4685 pipeline[plPtrExec].value = PRN;
4686 pipeline[plPtrExec].type = TYPE_DWORD;
4690 static void DSP_store_r15_i(void)
4692 #ifdef DSP_DIS_STORE15I
4694 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));
4696 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4698 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4699 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4701 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4703 pipeline[plPtrExec].value = PRN;
4704 pipeline[plPtrExec].type = TYPE_DWORD;
4708 static void DSP_store_r15_r(void)
4710 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4712 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4713 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4715 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4717 pipeline[plPtrExec].value = PRN;
4718 pipeline[plPtrExec].type = TYPE_DWORD;
4722 static void DSP_sub(void)
4726 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);
4728 uint32 res = PRN - PRM;
4729 SET_ZNC_SUB(PRN, PRM, res);
4733 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);
4737 static void DSP_subc(void)
4741 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);
4743 uint32 res = PRN - PRM - dsp_flag_c;
4744 uint32 borrow = dsp_flag_c;
4745 SET_ZNC_SUB(PRN - borrow, PRM, res);
4749 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);
4753 static void DSP_subq(void)
4757 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);
4759 uint32 r1 = dsp_convert_zero[PIMM1];
4760 uint32 res = PRN - r1;
4761 SET_ZNC_SUB(PRN, r1, res);
4765 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4769 static void DSP_subqmod(void)
4771 uint32 r1 = dsp_convert_zero[PIMM1];
4773 uint32 res = r2 - r1;
4774 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4776 SET_ZNC_SUB(r2, r1, res);
4779 static void DSP_subqt(void)
4781 #ifdef DSP_DIS_SUBQT
4783 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);
4785 PRES = PRN - dsp_convert_zero[PIMM1];
4786 #ifdef DSP_DIS_SUBQT
4788 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4792 static void DSP_xor(void)
4796 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);
4802 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);