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...
28 #include "m68000/m68kinterface.h"
32 // Seems alignment in loads & stores was off...
33 #define DSP_CORRECT_ALIGNMENT
34 //#define DSP_CORRECT_ALIGNMENT_STORE
37 //#define DSP_DEBUG_IRQ
38 //#define DSP_DEBUG_PL2
39 //#define DSP_DEBUG_STALL
40 //#define DSP_DEBUG_CC
41 #define NEW_SCOREBOARD
43 // Disassembly definitions
50 #define DSP_DIS_ADDQMOD
60 #define DSP_DIS_IMULTN
61 #define DSP_DIS_ILLEGAL
65 #define DSP_DIS_LOAD14I
66 #define DSP_DIS_LOAD14R
67 #define DSP_DIS_LOAD15I
68 #define DSP_DIS_LOAD15R
74 #define DSP_DIS_MOVEFA
75 #define DSP_DIS_MOVEPC // Pipeline only!
76 #define DSP_DIS_MOVETA
82 #define DSP_DIS_RESMAC
89 #define DSP_DIS_STORE14I
90 #define DSP_DIS_STORE15I
91 #define DSP_DIS_STOREB
92 #define DSP_DIS_STOREW
99 bool doDSPDis = false;
100 //bool doDSPDis = true;
135 + load_r15_indexed 284500
137 + store_r15_indexed 47416
141 + load_r14_ri 1229448
144 // Pipeline structures
146 const bool affectsScoreboard[64] =
148 true, true, true, true,
149 true, true, true, true,
150 true, true, true, true,
151 true, false, true, true,
153 true, true, false, true,
154 false, true, true, true,
155 true, true, true, true,
156 true, true, false, false,
158 true, true, true, true,
159 false, true, true, true,
160 true, true, true, true,
161 true, false, false, false,
163 true, false, false, true,
164 false, false, true, true,
165 true, false, true, true,
166 false, false, false, true
172 uint8 opcode, operand1, operand2;
173 uint32 reg1, reg2, areg1, areg2;
175 uint8 writebackRegister;
176 // General memory store...
185 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
186 #ifndef NEW_SCOREBOARD
189 uint8 scoreboard[32];
191 uint8 plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
192 PipelineStage pipeline[4];
193 bool IMASKCleared = false;
195 // DSP flags (old--have to get rid of this crap)
197 #define CINT0FLAG 0x00200
198 #define CINT1FLAG 0x00400
199 #define CINT2FLAG 0x00800
200 #define CINT3FLAG 0x01000
201 #define CINT4FLAG 0x02000
202 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
203 #define CINT5FLAG 0x20000 /* DSP only */
207 #define ZERO_FLAG 0x00001
208 #define CARRY_FLAG 0x00002
209 #define NEGA_FLAG 0x00004
210 #define IMASK 0x00008
211 #define INT_ENA0 0x00010
212 #define INT_ENA1 0x00020
213 #define INT_ENA2 0x00040
214 #define INT_ENA3 0x00080
215 #define INT_ENA4 0x00100
216 #define INT_CLR0 0x00200
217 #define INT_CLR1 0x00400
218 #define INT_CLR2 0x00800
219 #define INT_CLR3 0x01000
220 #define INT_CLR4 0x02000
221 #define REGPAGE 0x04000
222 #define DMAEN 0x08000
223 #define INT_ENA5 0x10000
224 #define INT_CLR5 0x20000
228 #define DSPGO 0x00001
229 #define CPUINT 0x00002
230 #define DSPINT0 0x00004
231 #define SINGLE_STEP 0x00008
232 #define SINGLE_GO 0x00010
234 #define INT_LAT0 0x00040
235 #define INT_LAT1 0x00080
236 #define INT_LAT2 0x00100
237 #define INT_LAT3 0x00200
238 #define INT_LAT4 0x00400
239 #define BUS_HOG 0x00800
240 #define VERSION 0x0F000
241 #define INT_LAT5 0x10000
243 extern uint32 jaguar_mainRom_crc32;
245 // Is opcode 62 *really* a NOP? Seems like it...
246 static void dsp_opcode_abs(void);
247 static void dsp_opcode_add(void);
248 static void dsp_opcode_addc(void);
249 static void dsp_opcode_addq(void);
250 static void dsp_opcode_addqmod(void);
251 static void dsp_opcode_addqt(void);
252 static void dsp_opcode_and(void);
253 static void dsp_opcode_bclr(void);
254 static void dsp_opcode_bset(void);
255 static void dsp_opcode_btst(void);
256 static void dsp_opcode_cmp(void);
257 static void dsp_opcode_cmpq(void);
258 static void dsp_opcode_div(void);
259 static void dsp_opcode_imacn(void);
260 static void dsp_opcode_imult(void);
261 static void dsp_opcode_imultn(void);
262 static void dsp_opcode_jr(void);
263 static void dsp_opcode_jump(void);
264 static void dsp_opcode_load(void);
265 static void dsp_opcode_loadb(void);
266 static void dsp_opcode_loadw(void);
267 static void dsp_opcode_load_r14_indexed(void);
268 static void dsp_opcode_load_r14_ri(void);
269 static void dsp_opcode_load_r15_indexed(void);
270 static void dsp_opcode_load_r15_ri(void);
271 static void dsp_opcode_mirror(void);
272 static void dsp_opcode_mmult(void);
273 static void dsp_opcode_move(void);
274 static void dsp_opcode_movei(void);
275 static void dsp_opcode_movefa(void);
276 static void dsp_opcode_move_pc(void);
277 static void dsp_opcode_moveq(void);
278 static void dsp_opcode_moveta(void);
279 static void dsp_opcode_mtoi(void);
280 static void dsp_opcode_mult(void);
281 static void dsp_opcode_neg(void);
282 static void dsp_opcode_nop(void);
283 static void dsp_opcode_normi(void);
284 static void dsp_opcode_not(void);
285 static void dsp_opcode_or(void);
286 static void dsp_opcode_resmac(void);
287 static void dsp_opcode_ror(void);
288 static void dsp_opcode_rorq(void);
289 static void dsp_opcode_xor(void);
290 static void dsp_opcode_sat16s(void);
291 static void dsp_opcode_sat32s(void);
292 static void dsp_opcode_sh(void);
293 static void dsp_opcode_sha(void);
294 static void dsp_opcode_sharq(void);
295 static void dsp_opcode_shlq(void);
296 static void dsp_opcode_shrq(void);
297 static void dsp_opcode_store(void);
298 static void dsp_opcode_storeb(void);
299 static void dsp_opcode_storew(void);
300 static void dsp_opcode_store_r14_indexed(void);
301 static void dsp_opcode_store_r14_ri(void);
302 static void dsp_opcode_store_r15_indexed(void);
303 static void dsp_opcode_store_r15_ri(void);
304 static void dsp_opcode_sub(void);
305 static void dsp_opcode_subc(void);
306 static void dsp_opcode_subq(void);
307 static void dsp_opcode_subqmod(void);
308 static void dsp_opcode_subqt(void);
310 uint8 dsp_opcode_cycles[64] =
312 3, 3, 3, 3, 3, 3, 3, 3,
313 3, 3, 3, 3, 3, 3, 3, 3,
314 3, 3, 1, 3, 1, 18, 3, 3,
315 3, 3, 3, 3, 3, 3, 3, 3,
316 3, 3, 2, 2, 2, 2, 3, 4,
317 5, 4, 5, 6, 6, 1, 1, 1,
318 1, 2, 2, 2, 1, 1, 9, 3,
319 3, 1, 6, 6, 2, 2, 3, 3
321 //Here's a QnD kludge...
322 //This is wrong, wrong, WRONG, but it seems to work for the time being...
323 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
324 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
325 /*uint8 dsp_opcode_cycles[64] =
327 1, 1, 1, 1, 1, 1, 1, 1,
328 1, 1, 1, 1, 1, 1, 1, 1,
329 1, 1, 1, 1, 1, 9, 1, 1,
330 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 2,
332 2, 2, 2, 3, 3, 1, 1, 1,
333 1, 1, 1, 1, 1, 1, 4, 1,
334 1, 1, 3, 3, 1, 1, 1, 1
337 void (* dsp_opcode[64])() =
339 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
340 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
341 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
342 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
343 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
344 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
345 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
346 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
347 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
348 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
349 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
350 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
351 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
352 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
353 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
354 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod,
357 uint32 dsp_opcode_use[65];
359 const char * dsp_opcode_str[65]=
361 "add", "addc", "addq", "addqt",
362 "sub", "subc", "subq", "subqt",
363 "neg", "and", "or", "xor",
364 "not", "btst", "bset", "bclr",
365 "mult", "imult", "imultn", "resmac",
366 "imacn", "div", "abs", "sh",
367 "shlq", "shrq", "sha", "sharq",
368 "ror", "rorq", "cmp", "cmpq",
369 "subqmod", "sat16s", "move", "moveq",
370 "moveta", "movefa", "movei", "loadb",
371 "loadw", "load", "sat32s", "load_r14_indexed",
372 "load_r15_indexed", "storeb", "storew", "store",
373 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
374 "jump", "jr", "mmult", "mtoi",
375 "normi", "nop", "load_r14_ri", "load_r15_ri",
376 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
381 static uint64 dsp_acc; // 40 bit register, NOT 32!
382 static uint32 dsp_remain;
383 static uint32 dsp_modulo;
384 static uint32 dsp_flags;
385 static uint32 dsp_matrix_control;
386 static uint32 dsp_pointer_to_matrix;
387 static uint32 dsp_data_organization;
389 static uint32 dsp_div_control;
390 static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c;
391 static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL;
392 static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32];
394 static uint32 dsp_opcode_first_parameter;
395 static uint32 dsp_opcode_second_parameter;
397 #define DSP_RUNNING (dsp_control & 0x01)
399 #define RM dsp_reg[dsp_opcode_first_parameter]
400 #define RN dsp_reg[dsp_opcode_second_parameter]
401 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
402 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
403 #define IMM_1 dsp_opcode_first_parameter
404 #define IMM_2 dsp_opcode_second_parameter
406 #define CLR_Z (dsp_flag_z = 0)
407 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
408 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
409 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
410 #define SET_N(r) (dsp_flag_n = (((uint32)(r) >> 31) & 0x01))
411 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(~(a))))
412 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32)(b) > (uint32)(a)))
413 #define SET_ZN(r) SET_N(r); SET_Z(r)
414 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
415 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
417 uint32 dsp_convert_zero[32] = {
418 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
419 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
421 uint8 dsp_branch_condition_table[32 * 8];
422 static uint16 mirror_table[65536];
423 static uint8 dsp_ram_8[0x2000];
425 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
427 static uint32 dsp_in_exec = 0;
428 static uint32 dsp_releaseTimeSlice_flag = 0;
433 // Comparison core vars (used only for core comparison! :-)
434 static uint64 count = 0;
435 static uint8 ram1[0x2000], ram2[0x2000];
436 static uint32 regs1[64], regs2[64];
437 static uint32 ctrl1[14], ctrl2[14];
440 // Private function prototypes
442 void DSPDumpRegisters(void);
443 void DSPDumpDisassembly(void);
444 void FlushDSPPipeline(void);
447 void dsp_reset_stats(void)
449 for(int i=0; i<65; i++)
450 dsp_opcode_use[i] = 0;
453 void DSPReleaseTimeslice(void)
455 //This does absolutely nothing!!! !!! FIX !!!
456 dsp_releaseTimeSlice_flag = 1;
459 void dsp_build_branch_condition_table(void)
461 // Fill in the mirror table
462 for(int i=0; i<65536; i++)
464 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
465 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
466 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
467 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
468 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
469 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
470 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
471 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
474 // Fill in the condition table
475 for(int i=0; i<8; i++)
477 for(int j=0; j<32; j++)
481 if ((j & 1) && (i & ZERO_FLAG))
484 if ((j & 2) && (!(i & ZERO_FLAG)))
487 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
490 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
493 dsp_branch_condition_table[i * 32 + j] = result;
498 uint8 DSPReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
500 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
501 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
503 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
506 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
508 if (offset==0xF1CFE0)
511 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
512 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
514 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
516 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
518 if ((offset&0x03)==0)
521 if ((offset&0x03)==1)
522 return((data>>16)&0xff);
524 if ((offset&0x03)==2)
525 return((data>>8)&0xff);
527 if ((offset&0x03)==3)
531 return JaguarReadByte(offset, who);
534 uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
536 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
537 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
539 offset &= 0xFFFFFFFE;
541 /* if (jaguar_mainRom_crc32==0xa74a97cd)
543 if (offset==0xF1A114) return(0x0000);
544 if (offset==0xF1A116) return(0x0000);
545 if (offset==0xF1B000) return(0x1234);
546 if (offset==0xF1B002) return(0x5678);
549 if (jaguar_mainRom_crc32==0x7ae20823)
551 if (offset==0xF1B9D8) return(0x0000);
552 if (offset==0xF1B9Da) return(0x0000);
553 if (offset==0xF1B2C0) return(0x0000);
554 if (offset==0xF1B2C2) return(0x0000);
557 // pour permettre � wolfenstein 3d de tourner sans le dsp
558 /* if ((offset==0xF1B0D0)||(offset==0xF1B0D2))
562 // pour permettre � nba jam de tourner sans le dsp
563 /* if (jaguar_mainRom_crc32==0x4faddb18)
565 if (offset==0xf1b2c0) return(0);
566 if (offset==0xf1b2c2) return(0);
567 if (offset==0xf1b240) return(0);
568 if (offset==0xf1b242) return(0);
569 if (offset==0xF1B340) return(0);
570 if (offset==0xF1B342) return(0);
571 if (offset==0xF1BAD8) return(0);
572 if (offset==0xF1BADA) return(0);
573 if (offset==0xF1B040) return(0);
574 if (offset==0xF1B042) return(0);
575 if (offset==0xF1B0C0) return(0);
576 if (offset==0xF1B0C2) return(0);
577 if (offset==0xF1B140) return(0);
578 if (offset==0xF1B142) return(0);
579 if (offset==0xF1B1C0) return(0);
580 if (offset==0xF1B1C2) return(0);
583 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
585 offset -= DSP_WORK_RAM_BASE;
586 /* uint16 data = (((uint16)dsp_ram_8[offset])<<8)|((uint16)dsp_ram_8[offset+1]);
588 return GET16(dsp_ram_8, offset);
590 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
592 uint32 data = DSPReadLong(offset & 0xFFFFFFFC, who);
595 return data & 0xFFFF;
600 return JaguarReadWord(offset, who);
603 uint32 DSPReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
605 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
606 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
609 offset &= 0xFFFFFFFC;
610 /*if (offset == 0xF1BCF4)
612 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));
613 DSPDumpDisassembly();
615 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
617 offset -= DSP_WORK_RAM_BASE;
618 return GET32(dsp_ram_8, offset);
620 //NOTE: Didn't return DSP_ACCUM!!!
621 //Mebbe it's not 'spose to! Yes, it is!
622 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
627 case 0x00: /*dsp_flag_c?(dsp_flag_c=1):(dsp_flag_c=0);
628 dsp_flag_z?(dsp_flag_z=1):(dsp_flag_z=0);
629 dsp_flag_n?(dsp_flag_n=1):(dsp_flag_n=0);*/
631 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
632 return dsp_flags & 0xFFFFC1FF;
633 case 0x04: return dsp_matrix_control;
634 case 0x08: return dsp_pointer_to_matrix;
635 case 0x0C: return dsp_data_organization;
636 case 0x10: return dsp_pc;
637 case 0x14: return dsp_control;
638 case 0x18: return dsp_modulo;
639 case 0x1C: return dsp_remain;
641 return (int32)((int8)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
643 // unaligned long read-- !!! FIX !!!
647 return JaguarReadLong(offset, who);
650 void DSPWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
652 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
653 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
655 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
657 offset -= DSP_WORK_RAM_BASE;
658 dsp_ram_8[offset] = data;
659 //This is rather stupid! !!! FIX !!!
660 /* if (dsp_in_exec == 0)
662 m68k_end_timeslice();
663 dsp_releaseTimeslice();
667 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
669 uint32 reg = offset & 0x1C;
670 int bytenum = offset & 0x03;
672 if ((reg >= 0x1C) && (reg <= 0x1F))
673 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
676 //This looks funky. !!! FIX !!!
677 uint32 old_data = DSPReadLong(offset&0xFFFFFFC, who);
678 bytenum = 3 - bytenum; // convention motorola !!!
679 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
680 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
684 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
685 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
686 JaguarWriteByte(offset, data, who);
689 void DSPWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
691 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
692 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
693 offset &= 0xFFFFFFFE;
694 /*if (offset == 0xF1BCF4)
696 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
698 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
699 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
701 /*if (offset == 0xF1B2F4)
703 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
705 offset -= DSP_WORK_RAM_BASE;
706 dsp_ram_8[offset] = data >> 8;
707 dsp_ram_8[offset+1] = data & 0xFF;
708 //This is rather stupid! !!! FIX !!!
709 /* if (dsp_in_exec == 0)
711 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
712 m68k_end_timeslice();
713 dsp_releaseTimeslice();
717 SET16(ram1, offset, data),
718 SET16(ram2, offset, data);
723 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
725 if ((offset & 0x1C) == 0x1C)
728 dsp_div_control = (dsp_div_control&0xffff0000)|(data&0xffff);
730 dsp_div_control = (dsp_div_control&0xffff)|((data&0xffff)<<16);
734 uint32 old_data = DSPReadLong(offset & 0xffffffc, who);
736 old_data = (old_data&0xffff0000)|(data&0xffff);
738 old_data = (old_data&0xffff)|((data&0xffff)<<16);
739 DSPWriteLong(offset & 0xffffffc, old_data, who);
744 JaguarWriteWord(offset, data, who);
747 //bool badWrite = false;
748 void DSPWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
750 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
751 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
753 offset &= 0xFFFFFFFC;
754 /*if (offset == 0xF1BCF4)
756 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
758 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
759 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
761 /*if (offset == 0xF1BE2C)
763 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
765 offset -= DSP_WORK_RAM_BASE;
766 SET32(dsp_ram_8, offset, data);
769 SET32(ram1, offset, data),
770 SET32(ram2, offset, data);
775 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
783 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
785 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
786 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
788 dsp_flag_z = dsp_flags & 0x01;
789 dsp_flag_c = (dsp_flags >> 1) & 0x01;
790 dsp_flag_n = (dsp_flags >> 2) & 0x01;
791 DSPUpdateRegisterBanks();
792 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
793 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
795 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
796 // It can be timed to anything really, anything that writes to L/RTXD at a regular
797 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
798 // interrupt, so that's what we check for here. Just know that this approach
799 // can be easily fooled!
800 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
803 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
804 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
805 // So, while this works, it's a by-product of the lame way in which audio is currently
806 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
807 // go away of its own accord. :-P
808 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
809 // weird is going on here...
810 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
811 // So subsequent interrupts come into the chip, but they're never serviced but the
812 // I2S subsystem keeps going.
813 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
814 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
815 // It seems that it's only stable for values of SCLK <= 9.
817 // All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
818 // that we don't actually need this stuff anymore. :-D
820 if (data & INT_ENA1) // I2S interrupt
822 int freq = GetCalculatedFrequency();
823 //This happens too often to be useful...
824 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
825 DACSetNewFrequency(freq);
827 else if (data & INT_ENA2) // TIMER 0 interrupt
829 int freq = JERRYGetPIT1Frequency();
830 //This happens too often to be useful...
831 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
832 DACSetNewFrequency(freq);
836 /* if (IMASKCleared) // If IMASK was cleared,
839 WriteLog("DSP: Finished interrupt.\n");
841 DSPHandleIRQs(); // see if any other interrupts need servicing!
846 if (/*4-8, 16*/data & 0x101F0)
847 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
848 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
849 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
850 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
851 /*if (data & 0x00020) // CD BIOS DSP code...
853 //001AC1BA: movea.l #$1AC200, A0
854 //001AC1C0: move.l #$1AC68C, D0
857 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
858 uint32 j = 0xF1B97C;//0x1AC200;
859 while (j <= 0xF1BE08)//0x1AC68C)
862 j += dasmjag(JAGUAR_DSP, buffer, j);
863 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
864 WriteLog("\t%08X: %s\n", oldj, buffer);
871 dsp_matrix_control = data;
874 // According to JTRM, only lines 2-11 are addressable, the rest being
875 // hardwired to $F1Bxxx.
876 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
879 dsp_data_organization = data;
884 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
889 ctrl1[0] = ctrl2[0] = data;
896 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
898 bool wasRunning = DSP_RUNNING;
899 // uint32 dsp_was_running = DSP_RUNNING;
900 // Check for DSP -> CPU interrupt
904 WriteLog("DSP: DSP -> CPU interrupt\n");
907 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
908 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
909 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
911 JERRYSetPendingIRQ(IRQ2_DSP);
912 DSPReleaseTimeslice();
913 m68k_set_irq(2); // Set 68000 IPL 2...
917 // Check for CPU -> DSP interrupt
921 WriteLog("DSP: CPU -> DSP interrupt\n");
923 m68k_end_timeslice();
924 DSPReleaseTimeslice();
925 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
929 if (data & SINGLE_STEP)
931 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
934 // Protect writes to VERSION and the interrupt latches...
935 uint32 mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
936 dsp_control = (dsp_control & mask) | (data & ~mask);
940 ctrl1[8] = ctrl2[8] = dsp_control;
944 // if dsp wasn't running but is now running
945 // execute a few cycles
946 //This is just plain wrong, wrong, WRONG!
947 #ifndef DSP_SINGLE_STEPPING
948 /* if (!dsp_was_running && DSP_RUNNING)
953 //This is WRONG! !!! FIX !!!
954 if (dsp_control & 0x18)
959 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
961 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
964 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
965 // !!! FIX !!! [DONE]
969 m68k_end_timeslice();
971 DSPReleaseTimeslice();
975 //DSPDumpDisassembly();
983 dsp_div_control = data;
985 // default: // unaligned long read
991 //We don't have to break this up like this! We CAN do 32 bit writes!
992 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
993 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
994 //if (offset > 0xF1FFFF)
996 JaguarWriteLong(offset, data, who);
1000 // Update the DSP register file pointers depending on REGPAGE bit
1002 void DSPUpdateRegisterBanks(void)
1004 int bank = (dsp_flags & REGPAGE);
1006 if (dsp_flags & IMASK)
1007 bank = 0; // IMASK forces main bank to be bank 0
1010 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
1012 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
1016 // Check for and handle any asserted DSP IRQs
1018 void DSPHandleIRQs(void)
1020 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1023 // Get the active interrupt bits (latches) & interrupt mask (enables)
1024 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1025 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1027 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1030 if (!bits) // Bail if nothing is enabled
1033 int which = 0; // Determine which interrupt
1047 #ifdef DSP_DEBUG_IRQ
1048 WriteLog("DSP: Generating interrupt #%i...", which);
1051 //if (which == 0) doDSPDis = true;
1053 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1054 // directly into the pipeline, it has the side effect of ensuring that the
1055 // instruction interrupted also gets to do its writeback. We simulate that
1057 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1059 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1060 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1062 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1063 scoreboard[pipeline[plPtrWrite].operand2] = false;
1065 //This should be execute (or should it?--not sure now!)
1066 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1067 //and what just executed is now in the Write position...). So why didn't it do the
1068 //writeback into register 0?
1069 #ifdef DSP_DEBUG_IRQ
1070 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1071 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]);
1072 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]);
1073 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]);
1075 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1077 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1079 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1080 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1083 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1084 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1085 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1086 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1088 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1092 #ifndef NEW_SCOREBOARD
1093 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1094 scoreboard[pipeline[plPtrWrite].operand2] = false;
1096 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1097 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1098 if (scoreboard[pipeline[plPtrWrite].operand2])
1099 scoreboard[pipeline[plPtrWrite].operand2]--;
1106 ctrl2[4] = dsp_flags;
1109 DSPUpdateRegisterBanks();
1110 #ifdef DSP_DEBUG_IRQ
1111 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1112 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]);
1115 // subqt #4,r31 ; pre-decrement stack pointer
1116 // move pc,r30 ; address of interrupted code
1117 // store r30,(r31) ; store return address
1124 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1125 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1126 //It missed the place that it was supposed to come back to, so this is WRONG!
1128 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1130 // R -> baz (<- PC points here)
1131 // E -> bar (when it should point here!)
1134 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1135 // which means (assuming they're all 2 bytes long) that the code below will come back on
1136 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1137 // instruction stream...
1139 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1140 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1143 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1147 // movei #service_address,r30 ; pointer to ISR entry
1148 // jump (r30) ; jump to ISR
1150 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1153 ctrl2[0] = regs2[30] = dsp_pc;
1160 // Non-pipelined version...
1162 void DSPHandleIRQsNP(void)
1166 memcpy(dsp_ram_8, ram1, 0x2000);
1167 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1168 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1171 dsp_remain = ctrl1[2];
1172 dsp_modulo = ctrl1[3];
1173 dsp_flags = ctrl1[4];
1174 dsp_matrix_control = ctrl1[5];
1175 dsp_pointer_to_matrix = ctrl1[6];
1176 dsp_data_organization = ctrl1[7];
1177 dsp_control = ctrl1[8];
1178 dsp_div_control = ctrl1[9];
1179 IMASKCleared = ctrl1[10];
1180 dsp_flag_z = ctrl1[11];
1181 dsp_flag_n = ctrl1[12];
1182 dsp_flag_c = ctrl1[13];
1183 DSPUpdateRegisterBanks();
1186 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1189 // Get the active interrupt bits (latches) & interrupt mask (enables)
1190 uint32 bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1191 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1193 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1196 if (!bits) // Bail if nothing is enabled
1199 int which = 0; // Determine which interrupt
1213 #ifdef DSP_DEBUG_IRQ
1214 WriteLog("DSP: Generating interrupt #%i...", which);
1220 ctrl1[4] = dsp_flags;
1223 DSPUpdateRegisterBanks();
1224 #ifdef DSP_DEBUG_IRQ
1225 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1228 // subqt #4,r31 ; pre-decrement stack pointer
1229 // move pc,r30 ; address of interrupted code
1230 // store r30,(r31) ; store return address
1237 DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1240 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1244 // movei #service_address,r30 ; pointer to ISR entry
1245 // jump (r30) ; jump to ISR
1247 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1250 ctrl1[0] = regs1[30] = dsp_pc;
1256 // Set the specified DSP IRQ line to a given state
1258 void DSPSetIRQLine(int irqline, int state)
1260 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1261 uint32 mask = INT_LAT0 << irqline;
1262 dsp_control &= ~mask; // Clear the latch bit
1265 ctrl1[8] = ctrl2[8] = dsp_control;
1271 dsp_control |= mask; // Set the latch bit
1275 ctrl1[8] = ctrl2[8] = dsp_control;
1281 // Not sure if this is correct behavior, but according to JTRM,
1282 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1283 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1284 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1287 bool DSPIsRunning(void)
1289 return (DSP_RUNNING ? true : false);
1294 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1295 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32), "DSP bank 0 regs");
1296 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32), "DSP bank 1 regs");
1298 dsp_build_branch_condition_table();
1300 srand(time(NULL)); // For randomizing local RAM
1305 dsp_pc = 0x00F1B000;
1306 dsp_acc = 0x00000000;
1307 dsp_remain = 0x00000000;
1308 dsp_modulo = 0xFFFFFFFF;
1309 dsp_flags = 0x00040000;
1310 dsp_matrix_control = 0x00000000;
1311 dsp_pointer_to_matrix = 0x00000000;
1312 dsp_data_organization = 0xFFFFFFFF;
1313 dsp_control = 0x00002000; // Report DSP version 2
1314 dsp_div_control = 0x00000000;
1317 dsp_reg = dsp_reg_bank_0;
1318 dsp_alternate_reg = dsp_reg_bank_1;
1320 for(int i=0; i<32; i++)
1321 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1324 IMASKCleared = false;
1327 // memset(dsp_ram_8, 0xFF, 0x2000);
1328 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1329 for(uint32 i=0; i<8192; i+=4)
1331 *((uint32 *)(&dsp_ram_8[i])) = rand();
1335 void DSPDumpDisassembly(void)
1339 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1340 uint32 j = 0xF1B000;
1342 while (j <= 0xF1CFFF)
1345 j += dasmjag(JAGUAR_DSP, buffer, j);
1346 WriteLog("\t%08X: %s\n", oldj, buffer);
1350 void DSPDumpRegisters(void)
1352 //Shoud add modulus, etc to dump here...
1353 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1354 WriteLog("\nRegisters bank 0\n");
1356 for(int j=0; j<8; j++)
1358 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1359 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1360 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1361 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1362 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1365 WriteLog("Registers bank 1\n");
1367 for(int j=0; j<8; j++)
1369 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1370 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1371 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1372 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1373 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1380 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1381 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1383 // get the active interrupt bits
1384 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1385 // get the interrupt mask
1386 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1388 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1389 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1390 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1391 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1392 WriteLog("\nRegisters bank 0\n");
1394 for(int j=0; j<8; j++)
1396 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1397 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1398 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1399 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1400 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1403 WriteLog("\nRegisters bank 1\n");
1407 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1408 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1409 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1410 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1411 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1416 static char buffer[512];
1417 j = DSP_WORK_RAM_BASE;
1419 while (j <= 0xF1CFFF)
1422 j += dasmjag(JAGUAR_DSP, buffer, j);
1423 WriteLog("\t%08X: %s\n", oldj, buffer);
1426 WriteLog("DSP opcodes use:\n");
1430 if (dsp_opcode_use[i])
1431 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1434 // memory_free(dsp_ram_8);
1435 // memory_free(dsp_reg_bank_0);
1436 // memory_free(dsp_reg_bank_1);
1437 // if (dsp_branch_condition_table)
1438 // free(dsp_branch_condition_table);
1440 // if (mirror_table)
1441 // free(mirror_table);
1447 // DSP comparison core...
1450 static uint16 lastExec;
1451 void DSPExecComp(int32 cycles)
1453 while (cycles > 0 && DSP_RUNNING)
1455 // Load up vars for non-pipelined core
1456 memcpy(dsp_ram_8, ram1, 0x2000);
1457 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1458 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1461 dsp_remain = ctrl1[2];
1462 dsp_modulo = ctrl1[3];
1463 dsp_flags = ctrl1[4];
1464 dsp_matrix_control = ctrl1[5];
1465 dsp_pointer_to_matrix = ctrl1[6];
1466 dsp_data_organization = ctrl1[7];
1467 dsp_control = ctrl1[8];
1468 dsp_div_control = ctrl1[9];
1469 IMASKCleared = ctrl1[10];
1470 dsp_flag_z = ctrl1[11];
1471 dsp_flag_n = ctrl1[12];
1472 dsp_flag_c = ctrl1[13];
1473 DSPUpdateRegisterBanks();
1475 // Decrement cycles based on non-pipelined core...
1476 uint16 instr1 = DSPReadWord(dsp_pc, DSP);
1477 cycles -= dsp_opcode_cycles[instr1 >> 10];
1479 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1480 DSPExec(1); // Do *one* instruction
1483 memcpy(ram1, dsp_ram_8, 0x2000);
1484 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1485 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1488 ctrl1[2] = dsp_remain;
1489 ctrl1[3] = dsp_modulo;
1490 ctrl1[4] = dsp_flags;
1491 ctrl1[5] = dsp_matrix_control;
1492 ctrl1[6] = dsp_pointer_to_matrix;
1493 ctrl1[7] = dsp_data_organization;
1494 ctrl1[8] = dsp_control;
1495 ctrl1[9] = dsp_div_control;
1496 ctrl1[10] = IMASKCleared;
1497 ctrl1[11] = dsp_flag_z;
1498 ctrl1[12] = dsp_flag_n;
1499 ctrl1[13] = dsp_flag_c;
1501 // Load up vars for pipelined core
1502 memcpy(dsp_ram_8, ram2, 0x2000);
1503 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1504 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1507 dsp_remain = ctrl2[2];
1508 dsp_modulo = ctrl2[3];
1509 dsp_flags = ctrl2[4];
1510 dsp_matrix_control = ctrl2[5];
1511 dsp_pointer_to_matrix = ctrl2[6];
1512 dsp_data_organization = ctrl2[7];
1513 dsp_control = ctrl2[8];
1514 dsp_div_control = ctrl2[9];
1515 IMASKCleared = ctrl2[10];
1516 dsp_flag_z = ctrl2[11];
1517 dsp_flag_n = ctrl2[12];
1518 dsp_flag_c = ctrl2[13];
1519 DSPUpdateRegisterBanks();
1521 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1522 DSPExecP2(1); // Do *one* instruction
1525 memcpy(ram2, dsp_ram_8, 0x2000);
1526 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1527 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1530 ctrl2[2] = dsp_remain;
1531 ctrl2[3] = dsp_modulo;
1532 ctrl2[4] = dsp_flags;
1533 ctrl2[5] = dsp_matrix_control;
1534 ctrl2[6] = dsp_pointer_to_matrix;
1535 ctrl2[7] = dsp_data_organization;
1536 ctrl2[8] = dsp_control;
1537 ctrl2[9] = dsp_div_control;
1538 ctrl2[10] = IMASKCleared;
1539 ctrl2[11] = dsp_flag_z;
1540 ctrl2[12] = dsp_flag_n;
1541 ctrl2[13] = dsp_flag_c;
1543 if (instr1 != lastExec)
1545 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1547 // 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));
1548 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1549 // if (ctrl1[0] < ppc) // P ran ahead of NP
1550 //How to test this crap???
1553 DSPExecP2(1); // Do one more instruction
1556 memcpy(ram2, dsp_ram_8, 0x2000);
1557 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1558 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1561 ctrl2[2] = dsp_remain;
1562 ctrl2[3] = dsp_modulo;
1563 ctrl2[4] = dsp_flags;
1564 ctrl2[5] = dsp_matrix_control;
1565 ctrl2[6] = dsp_pointer_to_matrix;
1566 ctrl2[7] = dsp_data_organization;
1567 ctrl2[8] = dsp_control;
1568 ctrl2[9] = dsp_div_control;
1569 ctrl2[10] = IMASKCleared;
1570 ctrl2[11] = dsp_flag_z;
1571 ctrl2[12] = dsp_flag_n;
1572 ctrl2[13] = dsp_flag_c;
1574 // else // NP ran ahead of P
1575 if (instr1 != lastExec) // Must be the other way...
1578 // Load up vars for non-pipelined core
1579 memcpy(dsp_ram_8, ram1, 0x2000);
1580 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1581 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1584 dsp_remain = ctrl1[2];
1585 dsp_modulo = ctrl1[3];
1586 dsp_flags = ctrl1[4];
1587 dsp_matrix_control = ctrl1[5];
1588 dsp_pointer_to_matrix = ctrl1[6];
1589 dsp_data_organization = ctrl1[7];
1590 dsp_control = ctrl1[8];
1591 dsp_div_control = ctrl1[9];
1592 IMASKCleared = ctrl1[10];
1593 dsp_flag_z = ctrl1[11];
1594 dsp_flag_n = ctrl1[12];
1595 dsp_flag_c = ctrl1[13];
1596 DSPUpdateRegisterBanks();
1598 for(int k=0; k<2; k++)
1600 // Decrement cycles based on non-pipelined core...
1601 instr1 = DSPReadWord(dsp_pc, DSP);
1602 cycles -= dsp_opcode_cycles[instr1 >> 10];
1604 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32)count, dsp_pc);
1605 DSPExec(1); // Do *one* instruction
1609 memcpy(ram1, dsp_ram_8, 0x2000);
1610 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1611 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1614 ctrl1[2] = dsp_remain;
1615 ctrl1[3] = dsp_modulo;
1616 ctrl1[4] = dsp_flags;
1617 ctrl1[5] = dsp_matrix_control;
1618 ctrl1[6] = dsp_pointer_to_matrix;
1619 ctrl1[7] = dsp_data_organization;
1620 ctrl1[8] = dsp_control;
1621 ctrl1[9] = dsp_div_control;
1622 ctrl1[10] = IMASKCleared;
1623 ctrl1[11] = dsp_flag_z;
1624 ctrl1[12] = dsp_flag_n;
1625 ctrl1[13] = dsp_flag_c;
1629 if (instr1 != lastExec)
1631 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1633 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1634 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1647 // DSP execution core
1649 //static bool R20Set = false, tripwire = false;
1650 //static uint32 pcQueue[32], ptrPCQ = 0;
1651 void DSPExec(int32 cycles)
1653 /*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed)
1654 dsp_check_if_i2s_interrupt_needed();*/
1656 #ifdef DSP_SINGLE_STEPPING
1657 if (dsp_control & 0x18)
1660 dsp_control &= ~0x10;
1663 //There is *no* good reason to do this here!
1665 dsp_releaseTimeSlice_flag = 0;
1668 while (cycles > 0 && DSP_RUNNING)
1670 /*extern uint32 totalFrames;
1671 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1672 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1673 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1675 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1678 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1680 if (dsp_pc == 0xF1B092)
1681 doDSPDis = false;//*/
1682 /*if (dsp_pc == 0xF1B140)
1683 doDSPDis = true;//*/
1685 if (IMASKCleared) // If IMASK was cleared,
1687 #ifdef DSP_DEBUG_IRQ
1688 WriteLog("DSP: Finished interrupt.\n");
1690 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1691 IMASKCleared = false;
1696 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1697 for(int i=0; i<80; i+=4)
1698 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1701 /*if (dsp_pc == 0xF1B55E)
1703 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1705 /*if (dsp_pc == 0xF1B7D2) // Start here???
1707 pcQueue[ptrPCQ++] = dsp_pc;
1709 uint16 opcode = DSPReadWord(dsp_pc, DSP);
1710 uint32 index = opcode >> 10;
1711 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1712 dsp_opcode_second_parameter = opcode & 0x1F;
1714 dsp_opcode[index]();
1715 dsp_opcode_use[index]++;
1716 cycles -= dsp_opcode_cycles[index];
1717 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1719 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1722 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1724 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1726 DSPDumpDisassembly();
1729 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1732 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1735 WriteLog("\nBacktrace:\n");
1736 for(int i=0; i<32; i++)
1738 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1739 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1749 // DSP opcode handlers
1752 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1753 // can cause trouble because an interrupt can occur *before* the instruction following the
1754 // jump can execute... !!! FIX !!!
1755 static void dsp_opcode_jump(void)
1758 const char * condition[32] =
1759 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1760 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1761 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1762 "???", "???", "???", "F" };
1764 WriteLog("%06X: 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);
1767 /* dsp_flag_c=dsp_flag_c?1:0;
1768 dsp_flag_z=dsp_flag_z?1:0;
1769 dsp_flag_n=dsp_flag_n?1:0;*/
1770 // KLUDGE: Used by BRANCH_CONDITION
1771 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1773 if (BRANCH_CONDITION(IMM_2))
1777 WriteLog("Branched!\n");
1779 uint32 delayed_pc = RM;
1781 dsp_pc = delayed_pc;
1786 WriteLog("Branch NOT taken.\n");
1790 static void dsp_opcode_jr(void)
1793 const char * condition[32] =
1794 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1795 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1796 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1797 "???", "???", "???", "F" };
1799 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);
1802 /* dsp_flag_c=dsp_flag_c?1:0;
1803 dsp_flag_z=dsp_flag_z?1:0;
1804 dsp_flag_n=dsp_flag_n?1:0;*/
1805 // KLUDGE: Used by BRANCH_CONDITION
1806 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1808 if (BRANCH_CONDITION(IMM_2))
1812 WriteLog("Branched!\n");
1814 int32 offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1815 int32 delayed_pc = dsp_pc + (offset * 2);
1817 dsp_pc = delayed_pc;
1822 WriteLog("Branch NOT taken.\n");
1826 static void dsp_opcode_add(void)
1830 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);
1832 uint32 res = RN + RM;
1833 SET_ZNC_ADD(RN, RM, res);
1837 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);
1841 static void dsp_opcode_addc(void)
1845 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);
1847 uint32 res = RN + RM + dsp_flag_c;
1848 uint32 carry = dsp_flag_c;
1849 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1850 SET_ZNC_ADD(RN + carry, RM, res);
1851 // SET_ZNC_ADD(RN, RM + carry, res);
1855 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);
1859 static void dsp_opcode_addq(void)
1863 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);
1865 uint32 r1 = dsp_convert_zero[IMM_1];
1866 uint32 res = RN + r1;
1867 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1871 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1875 static void dsp_opcode_sub(void)
1879 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);
1881 uint32 res = RN - RM;
1882 SET_ZNC_SUB(RN, RM, res);
1886 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);
1890 static void dsp_opcode_subc(void)
1894 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);
1896 uint32 res = RN - RM - dsp_flag_c;
1897 uint32 borrow = dsp_flag_c;
1898 SET_ZNC_SUB(RN - borrow, RM, res);
1902 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);
1906 static void dsp_opcode_subq(void)
1910 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);
1912 uint32 r1 = dsp_convert_zero[IMM_1];
1913 uint32 res = RN - r1;
1914 SET_ZNC_SUB(RN, r1, res);
1918 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1922 static void dsp_opcode_cmp(void)
1926 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);
1928 uint32 res = RN - RM;
1929 SET_ZNC_SUB(RN, RM, res);
1932 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1936 static void dsp_opcode_cmpq(void)
1938 static int32 sqtable[32] =
1939 { 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 };
1942 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);
1944 uint32 r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1945 uint32 res = RN - r1;
1946 SET_ZNC_SUB(RN, r1, res);
1949 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1953 static void dsp_opcode_and(void)
1957 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);
1963 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);
1967 static void dsp_opcode_or(void)
1971 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);
1977 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);
1981 static void dsp_opcode_xor(void)
1985 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);
1991 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);
1995 static void dsp_opcode_not(void)
1999 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);
2005 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2009 static void dsp_opcode_move_pc(void)
2014 static void dsp_opcode_store_r14_indexed(void)
2016 #ifdef DSP_DIS_STORE14I
2018 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));
2020 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2021 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2023 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2027 static void dsp_opcode_store_r15_indexed(void)
2029 #ifdef DSP_DIS_STORE15I
2031 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));
2033 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2034 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2036 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2040 static void dsp_opcode_load_r14_ri(void)
2042 #ifdef DSP_DIS_LOAD14R
2044 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);
2046 #ifdef DSP_CORRECT_ALIGNMENT
2047 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2049 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2051 #ifdef DSP_DIS_LOAD14R
2053 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2057 static void dsp_opcode_load_r15_ri(void)
2059 #ifdef DSP_DIS_LOAD15R
2061 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);
2063 #ifdef DSP_CORRECT_ALIGNMENT
2064 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2066 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2068 #ifdef DSP_DIS_LOAD15R
2070 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2074 static void dsp_opcode_store_r14_ri(void)
2076 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2079 static void dsp_opcode_store_r15_ri(void)
2081 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2084 static void dsp_opcode_nop(void)
2088 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2092 static void dsp_opcode_storeb(void)
2094 #ifdef DSP_DIS_STOREB
2096 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);
2098 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2099 DSPWriteLong(RM, RN & 0xFF, DSP);
2101 JaguarWriteByte(RM, RN, DSP);
2104 static void dsp_opcode_storew(void)
2106 #ifdef DSP_DIS_STOREW
2108 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);
2110 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2111 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2112 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2114 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2116 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2117 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2119 JaguarWriteWord(RM, RN, DSP);
2123 static void dsp_opcode_store(void)
2125 #ifdef DSP_DIS_STORE
2127 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);
2129 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2130 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2132 DSPWriteLong(RM, RN, DSP);
2136 static void dsp_opcode_loadb(void)
2138 #ifdef DSP_DIS_LOADB
2140 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);
2142 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2143 RN = DSPReadLong(RM, DSP) & 0xFF;
2145 RN = JaguarReadByte(RM, DSP);
2146 #ifdef DSP_DIS_LOADB
2148 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2152 static void dsp_opcode_loadw(void)
2154 #ifdef DSP_DIS_LOADW
2156 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);
2158 #ifdef DSP_CORRECT_ALIGNMENT
2159 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2160 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2162 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2164 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2165 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2167 RN = JaguarReadWord(RM, DSP);
2169 #ifdef DSP_DIS_LOADW
2171 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2175 static void dsp_opcode_load(void)
2179 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);
2181 #ifdef DSP_CORRECT_ALIGNMENT
2182 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2184 RN = DSPReadLong(RM, DSP);
2188 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2192 static void dsp_opcode_load_r14_indexed(void)
2194 #ifdef DSP_DIS_LOAD14I
2196 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);
2198 #ifdef DSP_CORRECT_ALIGNMENT
2199 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2201 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2203 #ifdef DSP_DIS_LOAD14I
2205 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2209 static void dsp_opcode_load_r15_indexed(void)
2211 #ifdef DSP_DIS_LOAD15I
2213 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);
2215 #ifdef DSP_CORRECT_ALIGNMENT
2216 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2218 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2220 #ifdef DSP_DIS_LOAD15I
2222 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2226 static void dsp_opcode_movei(void)
2228 #ifdef DSP_DIS_MOVEI
2230 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);
2232 // This instruction is followed by 32-bit value in LSW / MSW format...
2233 RN = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
2235 #ifdef DSP_DIS_MOVEI
2237 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2241 static void dsp_opcode_moveta(void)
2243 #ifdef DSP_DIS_MOVETA
2245 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);
2248 #ifdef DSP_DIS_MOVETA
2250 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);
2254 static void dsp_opcode_movefa(void)
2256 #ifdef DSP_DIS_MOVEFA
2258 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);
2261 #ifdef DSP_DIS_MOVEFA
2263 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);
2267 static void dsp_opcode_move(void)
2271 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);
2276 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);
2280 static void dsp_opcode_moveq(void)
2282 #ifdef DSP_DIS_MOVEQ
2284 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);
2287 #ifdef DSP_DIS_MOVEQ
2289 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2293 static void dsp_opcode_resmac(void)
2295 #ifdef DSP_DIS_RESMAC
2297 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));
2299 RN = (uint32)dsp_acc;
2300 #ifdef DSP_DIS_RESMAC
2302 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2306 static void dsp_opcode_imult(void)
2308 #ifdef DSP_DIS_IMULT
2310 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);
2312 RN = (int16)RN * (int16)RM;
2314 #ifdef DSP_DIS_IMULT
2316 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);
2320 static void dsp_opcode_mult(void)
2324 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);
2326 RN = (uint16)RM * (uint16)RN;
2330 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);
2334 static void dsp_opcode_bclr(void)
2338 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);
2340 uint32 res = RN & ~(1 << IMM_1);
2345 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2349 static void dsp_opcode_btst(void)
2353 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);
2355 dsp_flag_z = (~RN >> IMM_1) & 1;
2358 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2362 static void dsp_opcode_bset(void)
2366 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);
2368 uint32 res = RN | (1 << IMM_1);
2373 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2377 static void dsp_opcode_subqt(void)
2379 #ifdef DSP_DIS_SUBQT
2381 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);
2383 RN -= dsp_convert_zero[IMM_1];
2384 #ifdef DSP_DIS_SUBQT
2386 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2390 static void dsp_opcode_addqt(void)
2392 #ifdef DSP_DIS_ADDQT
2394 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);
2396 RN += dsp_convert_zero[IMM_1];
2397 #ifdef DSP_DIS_ADDQT
2399 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2403 static void dsp_opcode_imacn(void)
2405 #ifdef DSP_DIS_IMACN
2407 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);
2409 int32 res = (int16)RM * (int16)RN;
2410 dsp_acc += (int64)res;
2411 //Should we AND the result to fit into 40 bits here???
2412 #ifdef DSP_DIS_IMACN
2414 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));
2418 static void dsp_opcode_mtoi(void)
2420 RN = (((int32)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2424 static void dsp_opcode_normi(void)
2431 while ((_Rm & 0xffc00000) == 0)
2436 while ((_Rm & 0xff800000) != 0)
2446 static void dsp_opcode_mmult(void)
2448 int count = dsp_matrix_control&0x0f;
2449 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
2453 if (!(dsp_matrix_control & 0x10))
2455 for (int i = 0; i < count; i++)
2459 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2461 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2462 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2469 for (int i = 0; i < count; i++)
2473 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2475 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2476 int16 b=((int16)DSPReadWord(addr + 2, DSP));
2481 RN = res = (int32)accum;
2483 //NOTE: The flags are set based upon the last add/multiply done...
2487 static void dsp_opcode_abs(void)
2491 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);
2496 if (_Rn == 0x80000000)
2500 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2501 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2506 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2510 static void dsp_opcode_div(void)
2517 if (dsp_div_control & 1)
2519 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
2520 if (dsp_remain&0x80000000)
2522 RN = (((uint64)_Rn) << 16) / _Rm;
2526 dsp_remain = _Rn % _Rm;
2527 if (dsp_remain&0x80000000)
2536 static void dsp_opcode_imultn(void)
2538 #ifdef DSP_DIS_IMULTN
2540 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);
2542 // This is OK, since this multiply won't overflow 32 bits...
2543 int32 res = (int32)((int16)RN * (int16)RM);
2544 dsp_acc = (int64)res;
2546 #ifdef DSP_DIS_IMULTN
2548 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));
2552 static void dsp_opcode_neg(void)
2556 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);
2559 SET_ZNC_SUB(0, RN, res);
2563 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2567 static void dsp_opcode_shlq(void)
2571 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);
2573 int32 r1 = 32 - IMM_1;
2574 uint32 res = RN << r1;
2575 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2579 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2583 static void dsp_opcode_shrq(void)
2587 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);
2589 int32 r1 = dsp_convert_zero[IMM_1];
2590 uint32 res = RN >> r1;
2591 SET_ZN(res); dsp_flag_c = RN & 1;
2595 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2599 static void dsp_opcode_ror(void)
2603 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);
2605 uint32 r1 = RM & 0x1F;
2606 uint32 res = (RN >> r1) | (RN << (32 - r1));
2607 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2611 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);
2615 static void dsp_opcode_rorq(void)
2619 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);
2621 uint32 r1 = dsp_convert_zero[IMM_1 & 0x1F];
2623 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
2625 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2628 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2632 static void dsp_opcode_sha(void)
2634 int32 sRm=(int32)RM;
2640 if (shift>=32) shift=32;
2641 dsp_flag_c=(_Rn&0x80000000)>>31;
2651 if (shift>=32) shift=32;
2655 _Rn=((int32)_Rn)>>1;
2663 static void dsp_opcode_sharq(void)
2665 #ifdef DSP_DIS_SHARQ
2667 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);
2669 uint32 res = (int32)RN >> dsp_convert_zero[IMM_1];
2670 SET_ZN(res); dsp_flag_c = RN & 0x01;
2672 #ifdef DSP_DIS_SHARQ
2674 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2678 static void dsp_opcode_sh(void)
2680 int32 sRm=(int32)RM;
2685 uint32 shift=(-sRm);
2686 if (shift>=32) shift=32;
2687 dsp_flag_c=(_Rn&0x80000000)>>31;
2697 if (shift>=32) shift=32;
2709 void dsp_opcode_addqmod(void)
2711 #ifdef DSP_DIS_ADDQMOD
2713 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);
2715 uint32 r1 = dsp_convert_zero[IMM_1];
2717 uint32 res = r2 + r1;
2718 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2720 SET_ZNC_ADD(r2, r1, res);
2721 #ifdef DSP_DIS_ADDQMOD
2723 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2727 void dsp_opcode_subqmod(void)
2729 uint32 r1 = dsp_convert_zero[IMM_1];
2731 uint32 res = r2 - r1;
2732 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2735 SET_ZNC_SUB(r2, r1, res);
2738 void dsp_opcode_mirror(void)
2741 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2745 void dsp_opcode_sat32s(void)
2747 int32 r2 = (uint32)RN;
2748 int32 temp = dsp_acc >> 32;
2749 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
2754 void dsp_opcode_sat16s(void)
2757 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2763 // New pipelined DSP core
2766 static void DSP_abs(void);
2767 static void DSP_add(void);
2768 static void DSP_addc(void);
2769 static void DSP_addq(void);
2770 static void DSP_addqmod(void);
2771 static void DSP_addqt(void);
2772 static void DSP_and(void);
2773 static void DSP_bclr(void);
2774 static void DSP_bset(void);
2775 static void DSP_btst(void);
2776 static void DSP_cmp(void);
2777 static void DSP_cmpq(void);
2778 static void DSP_div(void);
2779 static void DSP_imacn(void);
2780 static void DSP_imult(void);
2781 static void DSP_imultn(void);
2782 static void DSP_illegal(void);
2783 static void DSP_jr(void);
2784 static void DSP_jump(void);
2785 static void DSP_load(void);
2786 static void DSP_loadb(void);
2787 static void DSP_loadw(void);
2788 static void DSP_load_r14_i(void);
2789 static void DSP_load_r14_r(void);
2790 static void DSP_load_r15_i(void);
2791 static void DSP_load_r15_r(void);
2792 static void DSP_mirror(void);
2793 static void DSP_mmult(void);
2794 static void DSP_move(void);
2795 static void DSP_movefa(void);
2796 static void DSP_movei(void);
2797 static void DSP_movepc(void);
2798 static void DSP_moveq(void);
2799 static void DSP_moveta(void);
2800 static void DSP_mtoi(void);
2801 static void DSP_mult(void);
2802 static void DSP_neg(void);
2803 static void DSP_nop(void);
2804 static void DSP_normi(void);
2805 static void DSP_not(void);
2806 static void DSP_or(void);
2807 static void DSP_resmac(void);
2808 static void DSP_ror(void);
2809 static void DSP_rorq(void);
2810 static void DSP_sat16s(void);
2811 static void DSP_sat32s(void);
2812 static void DSP_sh(void);
2813 static void DSP_sha(void);
2814 static void DSP_sharq(void);
2815 static void DSP_shlq(void);
2816 static void DSP_shrq(void);
2817 static void DSP_store(void);
2818 static void DSP_storeb(void);
2819 static void DSP_storew(void);
2820 static void DSP_store_r14_i(void);
2821 static void DSP_store_r14_r(void);
2822 static void DSP_store_r15_i(void);
2823 static void DSP_store_r15_r(void);
2824 static void DSP_sub(void);
2825 static void DSP_subc(void);
2826 static void DSP_subq(void);
2827 static void DSP_subqmod(void);
2828 static void DSP_subqt(void);
2829 static void DSP_xor(void);
2831 void (* DSPOpcode[64])() =
2833 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2834 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2835 DSP_neg, DSP_and, DSP_or, DSP_xor,
2836 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2838 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2839 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2840 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2841 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2843 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2844 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2845 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2846 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2848 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2849 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2850 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2851 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2854 bool readAffected[64][2] =
2856 { true, true}, { true, true}, {false, true}, {false, true},
2857 { true, true}, { true, true}, {false, true}, {false, true},
2858 {false, true}, { true, true}, { true, true}, { true, true},
2859 {false, true}, {false, true}, {false, true}, {false, true},
2861 { true, true}, { true, true}, { true, true}, {false, true},
2862 { true, true}, { true, true}, {false, true}, { true, true},
2863 {false, true}, {false, true}, { true, true}, {false, true},
2864 { true, true}, {false, true}, { true, true}, {false, true},
2866 {false, true}, {false, true}, { true, false}, {false, false},
2867 { true, false}, {false, false}, {false, false}, { true, false},
2868 { true, false}, { true, false}, {false, true}, { true, false},
2869 { true, false}, { true, true}, { true, true}, { true, true},
2871 {false, true}, { true, true}, { true, true}, {false, true},
2872 { true, false}, { true, false}, { true, true}, { true, false},
2873 { true, false}, {false, false}, { true, false}, { true, false},
2874 { true, true}, { true, true}, {false, false}, {false, true}
2877 bool isLoadStore[65] =
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, false,
2883 false, false, false, false, false, false, false, false,
2885 false, false, false, false, false, false, false, true,
2886 true, true, false, true, true, true, true, true,
2888 false, true, true, false, false, false, false, false,
2889 false, false, true, true, true, true, false, false, false
2892 void FlushDSPPipeline(void)
2894 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2896 for(int i=0; i<4; i++)
2897 pipeline[i].opcode = PIPELINE_STALL;
2899 for(int i=0; i<32; i++)
2904 // New pipelined DSP execution core
2906 /*void DSPExecP(int32 cycles)
2908 // bool inhibitFetch = false;
2910 dsp_releaseTimeSlice_flag = 0;
2913 while (cycles > 0 && DSP_RUNNING)
2915 WriteLog("DSPExecP: Pipeline status...\n");
2916 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);
2917 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);
2918 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);
2919 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);
2920 WriteLog(" --> Scoreboard: ");
2921 for(int i=0; i<32; i++)
2922 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2924 // Stage 1: Instruction fetch
2925 // if (!inhibitFetch)
2927 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2928 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2929 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2930 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2931 if (pipeline[plPtrFetch].opcode == 38)
2932 pipeline[plPtrFetch].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
2933 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
2936 // inhibitFetch = false;
2937 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2939 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2940 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);
2941 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);
2942 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);
2943 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2944 // Stage 2: Read registers
2945 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2946 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2947 if (scoreboard[pipeline[plPtrRead].operand2])
2948 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2949 // We have a hit in the scoreboard, so we have to stall the pipeline...
2951 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2952 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2953 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2954 pipeline[plPtrFetch] = pipeline[plPtrRead];
2955 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2959 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2960 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2961 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2963 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2964 // Shouldn't we be more selective with the register scoreboarding?
2965 // Yes, we should. !!! FIX !!!
2966 scoreboard[pipeline[plPtrRead].operand2] = true;
2967 //Advance PC here??? Yes.
2968 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2969 //This is a mangling of the pipeline stages, but what else to do???
2970 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2973 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2974 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);
2975 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);
2976 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);
2977 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);
2979 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2981 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2982 DSPOpcode[pipeline[plPtrExec].opcode]();
2983 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2984 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2989 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2990 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);
2991 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);
2992 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);
2993 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);
2994 // Stage 4: Write back register
2995 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2997 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2998 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3000 scoreboard[pipeline[plPtrWrite].operand1]
3001 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3004 // Push instructions through the pipeline...
3005 plPtrFetch = (++plPtrFetch) & 0x03;
3006 plPtrRead = (++plPtrRead) & 0x03;
3007 plPtrExec = (++plPtrExec) & 0x03;
3008 plPtrWrite = (++plPtrWrite) & 0x03;
3015 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3017 // Should be fixed now. Another problem is figuring how to do the sequence following
3018 // a branch followed with the JR & JUMP instructions...
3020 // There are two conflicting problems:
3023 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3024 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3025 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3026 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3027 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3028 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3029 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3030 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3031 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3032 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3033 DSP: Finished interrupt.
3034 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3035 ; bank 0 (where is was prepared)!
3036 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3037 F1B252: NOP [NCZ:001]
3040 // The other is when you see this at the end of an IRQ:
3043 JUMP T, (R29) ; R29 = Previous stack + 2
3044 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3046 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3047 ; 1) The STORE goes through the pipeline and is executed/written back
3048 ; 2) The pipeline is flushed
3049 ; 3) The DSP_PC is set to the new address
3050 ; 4) Execution resumes
3052 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3053 ; bank 0 instead of the current bank 1 and so goes astray!
3056 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3057 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3061 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3062 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3063 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3064 If it were done properly, the STORE write back would occur *after* (well, technically,
3065 during) the execution of the the JUMP that follows it.
3069 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3070 F1B08A: NOP [NCZ:001]
3072 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3075 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3078 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3079 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3080 F1B08A: NOP [NCZ:001]
3082 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3085 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3086 DSP: CPU -> DSP interrupt
3087 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3088 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3090 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3093 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3094 F1B006: NOP [NCZ:001]
3096 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3099 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3100 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3103 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3104 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3107 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3108 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3111 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3112 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3115 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3118 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3121 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3122 F1B0FE: NOP [NCZ:000]
3124 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3127 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3130 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3131 F1B138: NOP [NCZ:000]
3133 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3136 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3137 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3138 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3141 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3142 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3145 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3146 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3147 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3149 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3150 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3153 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3154 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3155 DSP: Finished interrupt.
3156 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3158 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3161 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3162 F1B016: NOP [NCZ:001]
3164 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3167 uint32 pcQueue1[0x400];
3169 static uint32 prevR1;
3170 //Let's try a 3 stage pipeline....
3171 //Looks like 3 stage is correct, otherwise bad things happen...
3172 void DSPExecP2(int32 cycles)
3174 dsp_releaseTimeSlice_flag = 0;
3177 while (cycles > 0 && DSP_RUNNING)
3179 /*extern uint32 totalFrames;
3180 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3181 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3182 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3184 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3187 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3189 if (dsp_pc == 0xF1B092)
3190 doDSPDis = false;//*/
3191 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3192 doDSPDis = true;//*/
3193 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3194 doDSPDis = true;//*/
3195 /*if (dsp_pc == 0xF1B0A0)
3196 doDSPDis = true;//*/
3197 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3198 doDSPDis = true;//*/
3199 //Two parter... (not sure how to write this)
3200 //if (dsp_pc == 0xF1B0D2)
3201 // prevR1 = dsp_reg[1];
3203 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3204 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3207 pcQueue1[pcQPtr1++] = dsp_pc;
3210 #ifdef DSP_DEBUG_PL2
3211 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3213 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3218 for(int i=0; i<0x400; i++)
3220 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3221 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3227 if (IMASKCleared) // If IMASK was cleared,
3229 #ifdef DSP_DEBUG_IRQ
3230 WriteLog("DSP: Finished interrupt.\n");
3232 DSPHandleIRQs(); // See if any other interrupts are pending!
3233 IMASKCleared = false;
3236 //if (dsp_flags & REGPAGE)
3237 // WriteLog(" --> REGPAGE has just been set!\n");
3238 #ifdef DSP_DEBUG_PL2
3241 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3242 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]);
3243 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]);
3244 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]);
3245 WriteLog(" --> Scoreboard: ");
3246 for(int i=0; i<32; i++)
3247 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3251 // Stage 1a: Instruction fetch
3252 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3253 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3254 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3255 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3256 if (pipeline[plPtrRead].opcode == 38)
3257 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3258 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3259 #ifdef DSP_DEBUG_PL2
3262 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3263 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3264 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]);
3265 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]);
3266 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]);
3269 // Stage 1b: Read registers
3270 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3271 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3273 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3274 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3275 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3276 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3277 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3278 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3279 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3281 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3282 // We have a hit in the scoreboard, so we have to stall the pipeline...
3283 #ifdef DSP_DEBUG_PL2
3287 WriteLog(" --> Stalling pipeline: ");
3288 if (readAffected[pipeline[plPtrRead].opcode][0])
3289 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3290 if (readAffected[pipeline[plPtrRead].opcode][1])
3291 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3295 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3296 #ifdef DSP_DEBUG_PL2
3301 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3302 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3303 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3305 // Shouldn't we be more selective with the register scoreboarding?
3306 // Yes, we should. !!! FIX !!! Kinda [DONE]
3307 #ifndef NEW_SCOREBOARD
3308 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3310 //Hopefully this will fix the dual MOVEQ # problem...
3311 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3314 //Advance PC here??? Yes.
3315 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3318 #ifdef DSP_DEBUG_PL2
3321 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3322 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]);
3323 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]);
3324 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]);
3328 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3330 #ifdef DSP_DEBUG_PL2
3332 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"));
3336 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3341 lastExec = pipeline[plPtrExec].instruction;
3342 //WriteLog("[lastExec = %04X]\n", lastExec);
3344 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3345 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3346 DSPOpcode[pipeline[plPtrExec].opcode]();
3347 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3351 //Let's not, until we do the stalling correctly...
3352 //But, we gotta while we're doing the comparison core...!
3353 //Or do we? cycles--;
3354 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3355 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3356 //to model this clock cycle behavior correctly...
3357 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3358 //don't affect the reads at stage 1...
3359 #ifdef DSP_DEBUG_STALL
3361 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3365 #ifdef DSP_DEBUG_PL2
3368 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3369 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]);
3370 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]);
3371 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]);
3375 // Stage 3: Write back register/memory address
3376 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3378 /*if (pipeline[plPtrWrite].writebackRegister == 3
3379 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3382 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3385 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3387 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3388 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3391 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3392 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3393 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3394 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3396 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3400 #ifndef NEW_SCOREBOARD
3401 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3402 scoreboard[pipeline[plPtrWrite].operand2] = false;
3404 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3405 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3406 if (scoreboard[pipeline[plPtrWrite].operand2])
3407 scoreboard[pipeline[plPtrWrite].operand2]--;
3411 // Push instructions through the pipeline...
3412 plPtrRead = (++plPtrRead) & 0x03;
3413 plPtrExec = (++plPtrExec) & 0x03;
3414 plPtrWrite = (++plPtrWrite) & 0x03;
3423 //#define DSP_DEBUG_PL3
3424 //Let's try a 2 stage pipeline....
3425 void DSPExecP3(int32 cycles)
3427 dsp_releaseTimeSlice_flag = 0;
3430 while (cycles > 0 && DSP_RUNNING)
3432 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3434 #ifdef DSP_DEBUG_PL3
3435 WriteLog("DSPExecP: Pipeline status...\n");
3436 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]);
3437 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]);
3438 WriteLog(" --> Scoreboard: ");
3439 for(int i=0; i<32; i++)
3440 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3443 // Stage 1a: Instruction fetch
3444 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3445 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3446 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3447 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3448 if (pipeline[plPtrRead].opcode == 38)
3449 pipeline[plPtrRead].result = (uint32)DSPReadWord(dsp_pc + 2, DSP)
3450 | ((uint32)DSPReadWord(dsp_pc + 4, DSP) << 16);
3451 #ifdef DSP_DEBUG_PL3
3452 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3453 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3454 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]);
3455 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]);
3457 // Stage 1b: Read registers
3458 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3459 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3460 // We have a hit in the scoreboard, so we have to stall the pipeline...
3461 #ifdef DSP_DEBUG_PL3
3463 WriteLog(" --> Stalling pipeline: ");
3464 if (readAffected[pipeline[plPtrRead].opcode][0])
3465 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3466 if (readAffected[pipeline[plPtrRead].opcode][1])
3467 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3470 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3471 #ifdef DSP_DEBUG_PL3
3476 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3477 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3478 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3480 // Shouldn't we be more selective with the register scoreboarding?
3481 // Yes, we should. !!! FIX !!! [Kinda DONE]
3482 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3484 //Advance PC here??? Yes.
3485 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3488 #ifdef DSP_DEBUG_PL3
3489 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3490 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]);
3491 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]);
3493 // Stage 2a: Execute
3494 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3496 #ifdef DSP_DEBUG_PL3
3497 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3499 DSPOpcode[pipeline[plPtrExec].opcode]();
3500 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3501 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3506 #ifdef DSP_DEBUG_PL3
3507 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3508 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]);
3509 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]);
3512 // Stage 2b: Write back register
3513 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3515 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3516 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3518 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3519 scoreboard[pipeline[plPtrExec].operand2] = false;
3522 // Push instructions through the pipeline...
3523 plPtrRead = (++plPtrRead) & 0x03;
3524 plPtrExec = (++plPtrExec) & 0x03;
3531 // DSP pipelined opcode handlers
3534 #define PRM pipeline[plPtrExec].reg1
3535 #define PRN pipeline[plPtrExec].reg2
3536 #define PIMM1 pipeline[plPtrExec].operand1
3537 #define PIMM2 pipeline[plPtrExec].operand2
3538 #define PRES pipeline[plPtrExec].result
3539 #define PWBR pipeline[plPtrExec].writebackRegister
3540 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3541 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3542 #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))
3543 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3545 static void DSP_abs(void)
3549 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);
3553 if (_Rn == 0x80000000)
3557 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3558 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3559 CLR_ZN; SET_Z(PRES);
3563 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3567 static void DSP_add(void)
3571 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);
3573 uint32 res = PRN + PRM;
3574 SET_ZNC_ADD(PRN, PRM, res);
3578 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);
3582 static void DSP_addc(void)
3586 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);
3588 uint32 res = PRN + PRM + dsp_flag_c;
3589 uint32 carry = dsp_flag_c;
3590 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3591 SET_ZNC_ADD(PRN + carry, PRM, res);
3592 // SET_ZNC_ADD(PRN, PRM + carry, res);
3596 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);
3600 static void DSP_addq(void)
3604 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);
3606 uint32 r1 = dsp_convert_zero[PIMM1];
3607 uint32 res = PRN + r1;
3608 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3612 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3616 static void DSP_addqmod(void)
3618 #ifdef DSP_DIS_ADDQMOD
3620 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);
3622 uint32 r1 = dsp_convert_zero[PIMM1];
3624 uint32 res = r2 + r1;
3625 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3627 SET_ZNC_ADD(r2, r1, res);
3628 #ifdef DSP_DIS_ADDQMOD
3630 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3634 static void DSP_addqt(void)
3636 #ifdef DSP_DIS_ADDQT
3638 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);
3640 PRES = PRN + dsp_convert_zero[PIMM1];
3641 #ifdef DSP_DIS_ADDQT
3643 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3647 static void DSP_and(void)
3651 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);
3657 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);
3661 static void DSP_bclr(void)
3665 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);
3667 PRES = PRN & ~(1 << PIMM1);
3671 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3675 static void DSP_bset(void)
3679 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);
3681 PRES = PRN | (1 << PIMM1);
3685 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3689 static void DSP_btst(void)
3693 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);
3695 dsp_flag_z = (~PRN >> PIMM1) & 1;
3699 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3703 static void DSP_cmp(void)
3707 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);
3709 uint32 res = PRN - PRM;
3710 SET_ZNC_SUB(PRN, PRM, res);
3714 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3718 static void DSP_cmpq(void)
3720 static int32 sqtable[32] =
3721 { 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 };
3724 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);
3726 uint32 r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3727 uint32 res = PRN - r1;
3728 SET_ZNC_SUB(PRN, r1, res);
3732 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3736 static void DSP_div(void)
3738 uint32 _Rm = PRM, _Rn = PRN;
3742 if (dsp_div_control & 1)
3744 dsp_remain = (((uint64)_Rn) << 16) % _Rm;
3745 if (dsp_remain & 0x80000000)
3747 PRES = (((uint64)_Rn) << 16) / _Rm;
3751 dsp_remain = _Rn % _Rm;
3752 if (dsp_remain & 0x80000000)
3761 static void DSP_imacn(void)
3763 #ifdef DSP_DIS_IMACN
3765 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);
3767 int32 res = (int16)PRM * (int16)PRN;
3768 dsp_acc += (int64)res;
3769 //Should we AND the result to fit into 40 bits here???
3771 #ifdef DSP_DIS_IMACN
3773 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));
3777 static void DSP_imult(void)
3779 #ifdef DSP_DIS_IMULT
3781 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);
3783 PRES = (int16)PRN * (int16)PRM;
3785 #ifdef DSP_DIS_IMULT
3787 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);
3791 static void DSP_imultn(void)
3793 #ifdef DSP_DIS_IMULTN
3795 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);
3797 // This is OK, since this multiply won't overflow 32 bits...
3798 int32 res = (int32)((int16)PRN * (int16)PRM);
3799 dsp_acc = (int64)res;
3802 #ifdef DSP_DIS_IMULTN
3804 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));
3808 static void DSP_illegal(void)
3810 #ifdef DSP_DIS_ILLEGAL
3812 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3817 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3818 // can cause trouble because an interrupt can occur *before* the instruction following the
3819 // jump can execute... !!! FIX !!!
3820 // This can probably be solved by judicious coding in the pipeline execution core...
3821 // And should be fixed now...
3822 static void DSP_jr(void)
3825 const char * condition[32] =
3826 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3827 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3828 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3829 "???", "???", "???", "F" };
3831 //How come this is always off by 2???
3832 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);
3834 // KLUDGE: Used by BRANCH_CONDITION macro
3835 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3837 if (BRANCH_CONDITION(PIMM2))
3841 WriteLog("Branched!\n");
3843 int32 offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3844 //Account for pipeline effects...
3845 uint32 newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3846 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3848 // Now that we've branched, we have to make sure that the following instruction
3849 // is executed atomically with this one and then flush the pipeline before setting
3852 // Step 1: Handle writebacks at stage 3 of pipeline
3853 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3855 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3856 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3858 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3859 scoreboard[pipeline[plPtrWrite].operand2] = false;
3861 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3863 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3865 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3866 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3869 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3870 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3871 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3872 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3874 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3878 #ifndef NEW_SCOREBOARD
3879 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3880 scoreboard[pipeline[plPtrWrite].operand2] = false;
3882 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3883 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3884 if (scoreboard[pipeline[plPtrWrite].operand2])
3885 scoreboard[pipeline[plPtrWrite].operand2]--;
3889 // Step 2: Push instruction through pipeline & execute following instruction
3890 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3891 // we effectively handle the final push of the instruction through the
3892 // pipeline when the new PC takes effect (since when we return, the
3893 // pipeline code will be executing the writeback stage. If we reverse
3894 // the execution order of the pipeline stages, this will no longer be
3896 pipeline[plPtrExec] = pipeline[plPtrRead];
3897 //This is BAD. We need to get that next opcode and execute it!
3898 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3899 // remove this crap.
3900 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3902 uint16 instruction = DSPReadWord(dsp_pc, DSP);
3903 pipeline[plPtrExec].opcode = instruction >> 10;
3904 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3905 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3906 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3907 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3908 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3910 dsp_pc += 2; // For DSP_DIS_* accuracy
3911 DSPOpcode[pipeline[plPtrExec].opcode]();
3912 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3913 pipeline[plPtrWrite] = pipeline[plPtrExec];
3915 // Step 3: Flush pipeline & set new PC
3916 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3923 WriteLog("Branch NOT taken.\n");
3929 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3932 static void DSP_jump(void)
3935 const char * condition[32] =
3936 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3937 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3938 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3939 "???", "???", "???", "F" };
3941 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);
3943 // KLUDGE: Used by BRANCH_CONDITION macro
3944 uint32 jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3946 if (BRANCH_CONDITION(PIMM2))
3950 WriteLog("Branched!\n");
3952 uint32 PCSave = PRM;
3953 // Now that we've branched, we have to make sure that the following instruction
3954 // is executed atomically with this one and then flush the pipeline before setting
3957 // Step 1: Handle writebacks at stage 3 of pipeline
3958 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3960 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3961 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3963 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3964 scoreboard[pipeline[plPtrWrite].operand2] = false;
3966 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3968 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3970 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3971 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3974 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3975 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3976 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3977 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3979 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3983 #ifndef NEW_SCOREBOARD
3984 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3985 scoreboard[pipeline[plPtrWrite].operand2] = false;
3987 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3988 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3989 if (scoreboard[pipeline[plPtrWrite].operand2])
3990 scoreboard[pipeline[plPtrWrite].operand2]--;
3994 // Step 2: Push instruction through pipeline & execute following instruction
3995 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3996 // we effectively handle the final push of the instruction through the
3997 // pipeline when the new PC takes effect (since when we return, the
3998 // pipeline code will be executing the writeback stage. If we reverse
3999 // the execution order of the pipeline stages, this will no longer be
4001 pipeline[plPtrExec] = pipeline[plPtrRead];
4002 //This is BAD. We need to get that next opcode and execute it!
4003 //Also, same problem in JR!
4004 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4005 // remove this crap.
4006 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
4008 uint16 instruction = DSPReadWord(dsp_pc, DSP);
4009 pipeline[plPtrExec].opcode = instruction >> 10;
4010 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4011 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4012 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4013 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4014 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4016 dsp_pc += 2; // For DSP_DIS_* accuracy
4017 DSPOpcode[pipeline[plPtrExec].opcode]();
4018 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4019 pipeline[plPtrWrite] = pipeline[plPtrExec];
4021 // Step 3: Flush pipeline & set new PC
4022 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4029 WriteLog("Branch NOT taken.\n");
4037 static void DSP_load(void)
4041 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);
4043 #ifdef DSP_CORRECT_ALIGNMENT
4044 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4046 PRES = DSPReadLong(PRM, DSP);
4050 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4054 static void DSP_loadb(void)
4056 #ifdef DSP_DIS_LOADB
4058 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);
4060 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4061 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4063 PRES = JaguarReadByte(PRM, DSP);
4064 #ifdef DSP_DIS_LOADB
4066 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4070 static void DSP_loadw(void)
4072 #ifdef DSP_DIS_LOADW
4074 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);
4076 #ifdef DSP_CORRECT_ALIGNMENT
4077 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4078 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4080 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4082 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4083 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4085 PRES = JaguarReadWord(PRM, DSP);
4087 #ifdef DSP_DIS_LOADW
4089 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4093 static void DSP_load_r14_i(void)
4095 #ifdef DSP_DIS_LOAD14I
4097 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);
4099 #ifdef DSP_CORRECT_ALIGNMENT
4100 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4102 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4104 #ifdef DSP_DIS_LOAD14I
4106 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4110 static void DSP_load_r14_r(void)
4112 #ifdef DSP_DIS_LOAD14R
4114 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);
4116 #ifdef DSP_CORRECT_ALIGNMENT
4117 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4119 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4121 #ifdef DSP_DIS_LOAD14R
4123 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4127 static void DSP_load_r15_i(void)
4129 #ifdef DSP_DIS_LOAD15I
4131 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);
4133 #ifdef DSP_CORRECT_ALIGNMENT
4134 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4136 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4138 #ifdef DSP_DIS_LOAD15I
4140 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4144 static void DSP_load_r15_r(void)
4146 #ifdef DSP_DIS_LOAD15R
4148 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);
4150 #ifdef DSP_CORRECT_ALIGNMENT
4151 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4153 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4155 #ifdef DSP_DIS_LOAD15R
4157 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4161 static void DSP_mirror(void)
4164 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4168 static void DSP_mmult(void)
4170 int count = dsp_matrix_control&0x0f;
4171 uint32 addr = dsp_pointer_to_matrix; // in the dsp ram
4175 if (!(dsp_matrix_control & 0x10))
4177 for (int i = 0; i < count; i++)
4181 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4183 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4184 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4191 for (int i = 0; i < count; i++)
4195 a=(int16)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4197 a=(int16)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4198 int16 b=((int16)DSPReadWord(addr + 2, DSP));
4204 PRES = res = (int32)accum;
4206 //NOTE: The flags are set based upon the last add/multiply done...
4210 static void DSP_move(void)
4214 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);
4219 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);
4223 static void DSP_movefa(void)
4225 #ifdef DSP_DIS_MOVEFA
4227 // 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);
4228 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);
4230 // PRES = ALTERNATE_RM;
4231 PRES = dsp_alternate_reg[PIMM1];
4232 #ifdef DSP_DIS_MOVEFA
4234 // 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);
4235 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);
4239 static void DSP_movei(void)
4241 #ifdef DSP_DIS_MOVEI
4243 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);
4245 // // This instruction is followed by 32-bit value in LSW / MSW format...
4246 // PRES = (uint32)DSPReadWord(dsp_pc, DSP) | ((uint32)DSPReadWord(dsp_pc + 2, DSP) << 16);
4248 #ifdef DSP_DIS_MOVEI
4250 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4254 static void DSP_movepc(void)
4256 #ifdef DSP_DIS_MOVEPC
4258 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);
4260 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4261 // PRES = dsp_pc - 2;
4262 //Account for pipeline effects...
4263 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4264 #ifdef DSP_DIS_MOVEPC
4266 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4270 static void DSP_moveq(void)
4272 #ifdef DSP_DIS_MOVEQ
4274 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);
4277 #ifdef DSP_DIS_MOVEQ
4279 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4283 static void DSP_moveta(void)
4285 #ifdef DSP_DIS_MOVETA
4287 // 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);
4288 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]);
4290 // ALTERNATE_RN = PRM;
4291 dsp_alternate_reg[PIMM2] = PRM;
4293 #ifdef DSP_DIS_MOVETA
4295 // 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);
4296 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]);
4300 static void DSP_mtoi(void)
4302 PRES = (((int32)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4306 static void DSP_mult(void)
4310 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);
4312 PRES = (uint16)PRM * (uint16)PRN;
4316 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);
4320 static void DSP_neg(void)
4324 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);
4327 SET_ZNC_SUB(0, PRN, res);
4331 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4335 static void DSP_nop(void)
4339 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4344 static void DSP_normi(void)
4351 while ((_Rm & 0xffc00000) == 0)
4356 while ((_Rm & 0xff800000) != 0)
4366 static void DSP_not(void)
4370 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);
4376 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4380 static void DSP_or(void)
4384 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);
4390 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);
4394 static void DSP_resmac(void)
4396 #ifdef DSP_DIS_RESMAC
4398 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));
4400 PRES = (uint32)dsp_acc;
4401 #ifdef DSP_DIS_RESMAC
4403 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4407 static void DSP_ror(void)
4411 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);
4413 uint32 r1 = PRM & 0x1F;
4414 uint32 res = (PRN >> r1) | (PRN << (32 - r1));
4415 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4419 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);
4423 static void DSP_rorq(void)
4427 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);
4429 uint32 r1 = dsp_convert_zero[PIMM1 & 0x1F];
4431 uint32 res = (r2 >> r1) | (r2 << (32 - r1));
4433 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4436 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4440 static void DSP_sat16s(void)
4443 uint32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4448 static void DSP_sat32s(void)
4450 int32 r2 = (uint32)PRN;
4451 int32 temp = dsp_acc >> 32;
4452 uint32 res = (temp < -1) ? (int32)0x80000000 : (temp > 0) ? (int32)0x7FFFFFFF : r2;
4457 static void DSP_sh(void)
4459 int32 sRm = (int32)PRM;
4464 uint32 shift = -sRm;
4469 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4484 dsp_flag_c = _Rn & 0x1;
4497 static void DSP_sha(void)
4499 int32 sRm = (int32)PRM;
4504 uint32 shift = -sRm;
4509 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4524 dsp_flag_c = _Rn & 0x1;
4528 _Rn = ((int32)_Rn) >> 1;
4537 static void DSP_sharq(void)
4539 #ifdef DSP_DIS_SHARQ
4541 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);
4543 uint32 res = (int32)PRN >> dsp_convert_zero[PIMM1];
4544 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4546 #ifdef DSP_DIS_SHARQ
4548 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4552 static void DSP_shlq(void)
4556 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);
4558 int32 r1 = 32 - PIMM1;
4559 uint32 res = PRN << r1;
4560 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4564 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4568 static void DSP_shrq(void)
4572 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);
4574 int32 r1 = dsp_convert_zero[PIMM1];
4575 uint32 res = PRN >> r1;
4576 SET_ZN(res); dsp_flag_c = PRN & 1;
4580 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4584 static void DSP_store(void)
4586 #ifdef DSP_DIS_STORE
4588 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);
4590 // DSPWriteLong(PRM, PRN, DSP);
4592 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4593 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4595 pipeline[plPtrExec].address = PRM;
4597 pipeline[plPtrExec].value = PRN;
4598 pipeline[plPtrExec].type = TYPE_DWORD;
4602 static void DSP_storeb(void)
4604 #ifdef DSP_DIS_STOREB
4606 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);
4608 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4609 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4611 // JaguarWriteByte(PRM, PRN, DSP);
4614 pipeline[plPtrExec].address = PRM;
4616 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4618 pipeline[plPtrExec].value = PRN & 0xFF;
4619 pipeline[plPtrExec].type = TYPE_DWORD;
4623 pipeline[plPtrExec].value = PRN;
4624 pipeline[plPtrExec].type = TYPE_BYTE;
4630 static void DSP_storew(void)
4632 #ifdef DSP_DIS_STOREW
4634 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);
4636 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4637 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4639 // JaguarWriteWord(PRM, PRN, DSP);
4642 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4643 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4645 pipeline[plPtrExec].address = PRM;
4648 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4650 pipeline[plPtrExec].value = PRN & 0xFFFF;
4651 pipeline[plPtrExec].type = TYPE_DWORD;
4655 pipeline[plPtrExec].value = PRN;
4656 pipeline[plPtrExec].type = TYPE_WORD;
4661 static void DSP_store_r14_i(void)
4663 #ifdef DSP_DIS_STORE14I
4665 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));
4667 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4669 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4670 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4672 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4674 pipeline[plPtrExec].value = PRN;
4675 pipeline[plPtrExec].type = TYPE_DWORD;
4679 static void DSP_store_r14_r(void)
4681 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4683 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4684 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4686 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4688 pipeline[plPtrExec].value = PRN;
4689 pipeline[plPtrExec].type = TYPE_DWORD;
4693 static void DSP_store_r15_i(void)
4695 #ifdef DSP_DIS_STORE15I
4697 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));
4699 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4701 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4702 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4704 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4706 pipeline[plPtrExec].value = PRN;
4707 pipeline[plPtrExec].type = TYPE_DWORD;
4711 static void DSP_store_r15_r(void)
4713 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4715 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4716 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4718 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4720 pipeline[plPtrExec].value = PRN;
4721 pipeline[plPtrExec].type = TYPE_DWORD;
4725 static void DSP_sub(void)
4729 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);
4731 uint32 res = PRN - PRM;
4732 SET_ZNC_SUB(PRN, PRM, res);
4736 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);
4740 static void DSP_subc(void)
4744 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);
4746 uint32 res = PRN - PRM - dsp_flag_c;
4747 uint32 borrow = dsp_flag_c;
4748 SET_ZNC_SUB(PRN - borrow, PRM, res);
4752 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);
4756 static void DSP_subq(void)
4760 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);
4762 uint32 r1 = dsp_convert_zero[PIMM1];
4763 uint32 res = PRN - r1;
4764 SET_ZNC_SUB(PRN, r1, res);
4768 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4772 static void DSP_subqmod(void)
4774 uint32 r1 = dsp_convert_zero[PIMM1];
4776 uint32 res = r2 - r1;
4777 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4779 SET_ZNC_SUB(r2, r1, res);
4782 static void DSP_subqt(void)
4784 #ifdef DSP_DIS_SUBQT
4786 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);
4788 PRES = PRN - dsp_convert_zero[PIMM1];
4789 #ifdef DSP_DIS_SUBQT
4791 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4795 static void DSP_xor(void)
4799 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);
4805 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);