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;
102 bool doDSPDis = false;
104 //#define DSP_DIS_JUMP
138 + load_r15_indexed 284500
140 + store_r15_indexed 47416
144 + load_r14_ri 1229448
147 // Pipeline structures
149 const bool affectsScoreboard[64] =
151 true, true, true, true,
152 true, true, true, true,
153 true, true, true, true,
154 true, false, true, true,
156 true, true, false, true,
157 false, true, true, true,
158 true, true, true, true,
159 true, true, false, false,
161 true, true, true, true,
162 false, true, true, true,
163 true, true, true, true,
164 true, false, false, false,
166 true, false, false, true,
167 false, false, true, true,
168 true, false, true, true,
169 false, false, false, true
174 uint16_t instruction;
175 uint8_t opcode, operand1, operand2;
176 uint32_t reg1, reg2, areg1, areg2;
178 uint8_t writebackRegister;
179 // General memory store...
188 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
189 #ifndef NEW_SCOREBOARD
192 uint8_t scoreboard[32];
194 uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
195 PipelineStage pipeline[4];
196 bool IMASKCleared = false;
198 // DSP flags (old--have to get rid of this crap)
200 #define CINT0FLAG 0x00200
201 #define CINT1FLAG 0x00400
202 #define CINT2FLAG 0x00800
203 #define CINT3FLAG 0x01000
204 #define CINT4FLAG 0x02000
205 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
206 #define CINT5FLAG 0x20000 /* DSP only */
210 #define ZERO_FLAG 0x00001
211 #define CARRY_FLAG 0x00002
212 #define NEGA_FLAG 0x00004
213 #define IMASK 0x00008
214 #define INT_ENA0 0x00010
215 #define INT_ENA1 0x00020
216 #define INT_ENA2 0x00040
217 #define INT_ENA3 0x00080
218 #define INT_ENA4 0x00100
219 #define INT_CLR0 0x00200
220 #define INT_CLR1 0x00400
221 #define INT_CLR2 0x00800
222 #define INT_CLR3 0x01000
223 #define INT_CLR4 0x02000
224 #define REGPAGE 0x04000
225 #define DMAEN 0x08000
226 #define INT_ENA5 0x10000
227 #define INT_CLR5 0x20000
231 #define DSPGO 0x00001
232 #define CPUINT 0x00002
233 #define DSPINT0 0x00004
234 #define SINGLE_STEP 0x00008
235 #define SINGLE_GO 0x00010
237 #define INT_LAT0 0x00040
238 #define INT_LAT1 0x00080
239 #define INT_LAT2 0x00100
240 #define INT_LAT3 0x00200
241 #define INT_LAT4 0x00400
242 #define BUS_HOG 0x00800
243 #define VERSION 0x0F000
244 #define INT_LAT5 0x10000
246 extern uint32_t jaguar_mainRom_crc32;
248 // Is opcode 62 *really* a NOP? Seems like it...
249 static void dsp_opcode_abs(void);
250 static void dsp_opcode_add(void);
251 static void dsp_opcode_addc(void);
252 static void dsp_opcode_addq(void);
253 static void dsp_opcode_addqmod(void);
254 static void dsp_opcode_addqt(void);
255 static void dsp_opcode_and(void);
256 static void dsp_opcode_bclr(void);
257 static void dsp_opcode_bset(void);
258 static void dsp_opcode_btst(void);
259 static void dsp_opcode_cmp(void);
260 static void dsp_opcode_cmpq(void);
261 static void dsp_opcode_div(void);
262 static void dsp_opcode_imacn(void);
263 static void dsp_opcode_imult(void);
264 static void dsp_opcode_imultn(void);
265 static void dsp_opcode_jr(void);
266 static void dsp_opcode_jump(void);
267 static void dsp_opcode_load(void);
268 static void dsp_opcode_loadb(void);
269 static void dsp_opcode_loadw(void);
270 static void dsp_opcode_load_r14_indexed(void);
271 static void dsp_opcode_load_r14_ri(void);
272 static void dsp_opcode_load_r15_indexed(void);
273 static void dsp_opcode_load_r15_ri(void);
274 static void dsp_opcode_mirror(void);
275 static void dsp_opcode_mmult(void);
276 static void dsp_opcode_move(void);
277 static void dsp_opcode_movei(void);
278 static void dsp_opcode_movefa(void);
279 static void dsp_opcode_move_pc(void);
280 static void dsp_opcode_moveq(void);
281 static void dsp_opcode_moveta(void);
282 static void dsp_opcode_mtoi(void);
283 static void dsp_opcode_mult(void);
284 static void dsp_opcode_neg(void);
285 static void dsp_opcode_nop(void);
286 static void dsp_opcode_normi(void);
287 static void dsp_opcode_not(void);
288 static void dsp_opcode_or(void);
289 static void dsp_opcode_resmac(void);
290 static void dsp_opcode_ror(void);
291 static void dsp_opcode_rorq(void);
292 static void dsp_opcode_xor(void);
293 static void dsp_opcode_sat16s(void);
294 static void dsp_opcode_sat32s(void);
295 static void dsp_opcode_sh(void);
296 static void dsp_opcode_sha(void);
297 static void dsp_opcode_sharq(void);
298 static void dsp_opcode_shlq(void);
299 static void dsp_opcode_shrq(void);
300 static void dsp_opcode_store(void);
301 static void dsp_opcode_storeb(void);
302 static void dsp_opcode_storew(void);
303 static void dsp_opcode_store_r14_indexed(void);
304 static void dsp_opcode_store_r14_ri(void);
305 static void dsp_opcode_store_r15_indexed(void);
306 static void dsp_opcode_store_r15_ri(void);
307 static void dsp_opcode_sub(void);
308 static void dsp_opcode_subc(void);
309 static void dsp_opcode_subq(void);
310 static void dsp_opcode_subqmod(void);
311 static void dsp_opcode_subqt(void);
312 static void dsp_opcode_illegal(void);
314 uint8_t dsp_opcode_cycles[64] =
316 3, 3, 3, 3, 3, 3, 3, 3,
317 3, 3, 3, 3, 3, 3, 3, 3,
318 3, 3, 1, 3, 1, 18, 3, 3,
319 3, 3, 3, 3, 3, 3, 3, 3,
320 3, 3, 2, 2, 2, 2, 3, 4,
321 5, 4, 5, 6, 6, 1, 1, 1,
322 1, 2, 2, 2, 1, 1, 9, 3,
323 3, 1, 6, 6, 2, 2, 3, 3
325 //Here's a QnD kludge...
326 //This is wrong, wrong, WRONG, but it seems to work for the time being...
327 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
328 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
329 /*uint8_t dsp_opcode_cycles[64] =
331 1, 1, 1, 1, 1, 1, 1, 1,
332 1, 1, 1, 1, 1, 1, 1, 1,
333 1, 1, 1, 1, 1, 9, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 1, 1, 2,
336 2, 2, 2, 3, 3, 1, 1, 1,
337 1, 1, 1, 1, 1, 1, 4, 1,
338 1, 1, 3, 3, 1, 1, 1, 1
341 void (* dsp_opcode[64])() =
343 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
344 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
345 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
346 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
347 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
348 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
349 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
350 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
351 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
352 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
353 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
354 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
355 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
356 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
357 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
358 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod,
361 uint32_t dsp_opcode_use[65];
363 const char * dsp_opcode_str[65]=
365 "add", "addc", "addq", "addqt",
366 "sub", "subc", "subq", "subqt",
367 "neg", "and", "or", "xor",
368 "not", "btst", "bset", "bclr",
369 "mult", "imult", "imultn", "resmac",
370 "imacn", "div", "abs", "sh",
371 "shlq", "shrq", "sha", "sharq",
372 "ror", "rorq", "cmp", "cmpq",
373 "subqmod", "sat16s", "move", "moveq",
374 "moveta", "movefa", "movei", "loadb",
375 "loadw", "load", "sat32s", "load_r14_indexed",
376 "load_r15_indexed", "storeb", "storew", "store",
377 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
378 "jump", "jr", "mmult", "mtoi",
379 "normi", "nop", "load_r14_ri", "load_r15_ri",
380 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
385 static uint64_t dsp_acc; // 40 bit register, NOT 32!
386 static uint32_t dsp_remain;
387 static uint32_t dsp_modulo;
388 static uint32_t dsp_flags;
389 static uint32_t dsp_matrix_control;
390 static uint32_t dsp_pointer_to_matrix;
391 static uint32_t dsp_data_organization;
392 uint32_t dsp_control;
393 static uint32_t dsp_div_control;
394 static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
395 static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
396 uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
398 static uint32_t dsp_opcode_first_parameter;
399 static uint32_t dsp_opcode_second_parameter;
401 #define DSP_RUNNING (dsp_control & 0x01)
403 #define RM dsp_reg[dsp_opcode_first_parameter]
404 #define RN dsp_reg[dsp_opcode_second_parameter]
405 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
406 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
407 #define IMM_1 dsp_opcode_first_parameter
408 #define IMM_2 dsp_opcode_second_parameter
410 #define CLR_Z (dsp_flag_z = 0)
411 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
412 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
413 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
414 #define SET_N(r) (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
415 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
416 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
417 #define SET_ZN(r) SET_N(r); SET_Z(r)
418 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
419 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
421 uint32_t dsp_convert_zero[32] = {
422 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
423 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
426 uint8_t dsp_branch_condition_table[32 * 8];
427 static uint16_t mirror_table[65536];
428 static uint8_t dsp_ram_8[0x2000];
430 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
432 static uint32_t dsp_in_exec = 0;
433 static uint32_t dsp_releaseTimeSlice_flag = 0;
438 // Comparison core vars (used only for core comparison! :-)
439 static uint64_t count = 0;
440 static uint8_t ram1[0x2000], ram2[0x2000];
441 static uint32_t regs1[64], regs2[64];
442 static uint32_t ctrl1[14], ctrl2[14];
445 // Private function prototypes
447 void DSPDumpRegisters(void);
448 void DSPDumpDisassembly(void);
449 void FlushDSPPipeline(void);
452 void dsp_reset_stats(void)
454 for(int i=0; i<65; i++)
455 dsp_opcode_use[i] = 0;
458 void DSPReleaseTimeslice(void)
460 //This does absolutely nothing!!! !!! FIX !!!
461 dsp_releaseTimeSlice_flag = 1;
464 void dsp_build_branch_condition_table(void)
466 // Fill in the mirror table
467 for(int i=0; i<65536; i++)
469 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
470 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
471 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
472 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
473 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
474 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
475 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
476 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
479 // Fill in the condition table
480 for(int i=0; i<8; i++)
482 for(int j=0; j<32; j++)
486 if ((j & 1) && (i & ZERO_FLAG))
489 if ((j & 2) && (!(i & ZERO_FLAG)))
492 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
495 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
498 dsp_branch_condition_table[i * 32 + j] = result;
503 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
505 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
506 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
508 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
511 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
513 if (offset==0xF1CFE0)
516 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
517 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
519 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
521 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
523 if ((offset&0x03)==0)
526 if ((offset&0x03)==1)
527 return((data>>16)&0xff);
529 if ((offset&0x03)==2)
530 return((data>>8)&0xff);
532 if ((offset&0x03)==3)
536 return JaguarReadByte(offset, who);
539 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
541 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
542 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
544 offset &= 0xFFFFFFFE;
546 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
548 offset -= DSP_WORK_RAM_BASE;
549 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
551 return GET16(dsp_ram_8, offset);
553 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
555 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
558 return data & 0xFFFF;
563 return JaguarReadWord(offset, who);
566 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
568 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
569 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
572 offset &= 0xFFFFFFFC;
573 /*if (offset == 0xF1BCF4)
575 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));
576 DSPDumpDisassembly();
578 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
580 offset -= DSP_WORK_RAM_BASE;
581 return GET32(dsp_ram_8, offset);
583 //NOTE: Didn't return DSP_ACCUM!!!
584 //Mebbe it's not 'spose to! Yes, it is!
585 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
591 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
592 return dsp_flags & 0xFFFFC1FF;
593 case 0x04: return dsp_matrix_control;
594 case 0x08: return dsp_pointer_to_matrix;
595 case 0x0C: return dsp_data_organization;
596 case 0x10: return dsp_pc;
597 case 0x14: return dsp_control;
598 case 0x18: return dsp_modulo;
599 case 0x1C: return dsp_remain;
601 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
603 // unaligned long read-- !!! FIX !!!
607 return JaguarReadLong(offset, who);
610 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
612 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
613 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
615 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
617 offset -= DSP_WORK_RAM_BASE;
618 dsp_ram_8[offset] = data;
619 //This is rather stupid! !!! FIX !!!
620 /* if (dsp_in_exec == 0)
622 m68k_end_timeslice();
623 dsp_releaseTimeslice();
627 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
629 uint32_t reg = offset & 0x1C;
630 int bytenum = offset & 0x03;
632 if ((reg >= 0x1C) && (reg <= 0x1F))
633 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
636 //This looks funky. !!! FIX !!!
637 uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
638 bytenum = 3 - bytenum; // convention motorola !!!
639 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
640 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
644 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
645 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
646 JaguarWriteByte(offset, data, who);
649 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
651 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
652 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
653 offset &= 0xFFFFFFFE;
654 /*if (offset == 0xF1BCF4)
656 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
658 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
659 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
661 /*if (offset == 0xF1B2F4)
663 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
665 offset -= DSP_WORK_RAM_BASE;
666 dsp_ram_8[offset] = data >> 8;
667 dsp_ram_8[offset+1] = data & 0xFF;
668 //This is rather stupid! !!! FIX !!!
669 /* if (dsp_in_exec == 0)
671 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
672 m68k_end_timeslice();
673 dsp_releaseTimeslice();
677 SET16(ram1, offset, data),
678 SET16(ram2, offset, data);
683 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
685 if ((offset & 0x1C) == 0x1C)
688 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
690 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
694 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
697 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
699 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
701 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
707 JaguarWriteWord(offset, data, who);
710 //bool badWrite = false;
711 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
713 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
714 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
716 offset &= 0xFFFFFFFC;
717 /*if (offset == 0xF1BCF4)
719 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
721 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
722 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
724 /*if (offset == 0xF1BE2C)
726 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
728 offset -= DSP_WORK_RAM_BASE;
729 SET32(dsp_ram_8, offset, data);
732 SET32(ram1, offset, data),
733 SET32(ram2, offset, data);
738 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
746 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
748 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
749 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
750 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
751 // IRQ logic can set it. So we mask it out here to prevent problems...
752 dsp_flags = data & (~IMASK);
753 dsp_flag_z = dsp_flags & 0x01;
754 dsp_flag_c = (dsp_flags >> 1) & 0x01;
755 dsp_flag_n = (dsp_flags >> 2) & 0x01;
756 DSPUpdateRegisterBanks();
757 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
758 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
760 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
761 // It can be timed to anything really, anything that writes to L/RTXD at a regular
762 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
763 // interrupt, so that's what we check for here. Just know that this approach
764 // can be easily fooled!
765 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
768 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
769 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
770 // So, while this works, it's a by-product of the lame way in which audio is currently
771 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
772 // go away of its own accord. :-P
773 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
774 // weird is going on here...
775 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
776 // So subsequent interrupts come into the chip, but they're never serviced but the
777 // I2S subsystem keeps going.
778 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
779 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
780 // It seems that it's only stable for values of SCLK <= 9.
782 // All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
783 // that we don't actually need this stuff anymore. :-D
785 if (data & INT_ENA1) // I2S interrupt
787 int freq = GetCalculatedFrequency();
788 //This happens too often to be useful...
789 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
790 DACSetNewFrequency(freq);
792 else if (data & INT_ENA2) // TIMER 0 interrupt
794 int freq = JERRYGetPIT1Frequency();
795 //This happens too often to be useful...
796 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
797 DACSetNewFrequency(freq);
801 /* if (IMASKCleared) // If IMASK was cleared,
804 WriteLog("DSP: Finished interrupt.\n");
806 DSPHandleIRQs(); // see if any other interrupts need servicing!
811 if (/*4-8, 16*/data & 0x101F0)
812 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
813 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
814 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
815 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
816 /*if (data & 0x00020) // CD BIOS DSP code...
818 //001AC1BA: movea.l #$1AC200, A0
819 //001AC1C0: move.l #$1AC68C, D0
822 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
823 uint32_t j = 0xF1B97C;//0x1AC200;
824 while (j <= 0xF1BE08)//0x1AC68C)
827 j += dasmjag(JAGUAR_DSP, buffer, j);
828 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
829 WriteLog("\t%08X: %s\n", oldj, buffer);
836 dsp_matrix_control = data;
839 // According to JTRM, only lines 2-11 are addressable, the rest being
840 // hardwired to $F1Bxxx.
841 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
844 dsp_data_organization = data;
849 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
854 ctrl1[0] = ctrl2[0] = data;
861 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
863 bool wasRunning = DSP_RUNNING;
864 // uint32_t dsp_was_running = DSP_RUNNING;
865 // Check for DSP -> CPU interrupt
869 WriteLog("DSP: DSP -> CPU interrupt\n");
872 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
873 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
874 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
876 JERRYSetPendingIRQ(IRQ2_DSP);
877 DSPReleaseTimeslice();
878 m68k_set_irq(2); // Set 68000 IPL 2...
882 // Check for CPU -> DSP interrupt
886 WriteLog("DSP: CPU -> DSP interrupt\n");
888 m68k_end_timeslice();
889 DSPReleaseTimeslice();
890 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
894 if (data & SINGLE_STEP)
896 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
899 // Protect writes to VERSION and the interrupt latches...
900 uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
901 dsp_control = (dsp_control & mask) | (data & ~mask);
905 ctrl1[8] = ctrl2[8] = dsp_control;
909 // if dsp wasn't running but is now running
910 // execute a few cycles
911 //This is just plain wrong, wrong, WRONG!
912 #ifndef DSP_SINGLE_STEPPING
913 /* if (!dsp_was_running && DSP_RUNNING)
918 //This is WRONG! !!! FIX !!!
919 if (dsp_control & 0x18)
924 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
926 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
929 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
930 // !!! FIX !!! [DONE]
934 m68k_end_timeslice();
936 DSPReleaseTimeslice();
940 //DSPDumpDisassembly();
945 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
949 dsp_div_control = data;
951 // default: // unaligned long read
957 //We don't have to break this up like this! We CAN do 32 bit writes!
958 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
959 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
960 //if (offset > 0xF1FFFF)
962 JaguarWriteLong(offset, data, who);
966 // Update the DSP register file pointers depending on REGPAGE bit
968 void DSPUpdateRegisterBanks(void)
970 int bank = (dsp_flags & REGPAGE);
972 if (dsp_flags & IMASK)
973 bank = 0; // IMASK forces main bank to be bank 0
976 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
978 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
981 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
986 // Check for and handle any asserted DSP IRQs
988 void DSPHandleIRQs(void)
990 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
993 // Get the active interrupt bits (latches) & interrupt mask (enables)
994 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
995 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
997 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1000 if (!bits) // Bail if nothing is enabled
1003 int which = 0; // Determine which interrupt
1018 #ifdef DSP_DEBUG_IRQ
1019 WriteLog("DSP: Generating interrupt #%i...", which);
1022 //if (which == 0) doDSPDis = true;
1024 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1025 // directly into the pipeline, it has the side effect of ensuring that the
1026 // instruction interrupted also gets to do its writeback. We simulate that
1028 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1030 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1031 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1033 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1034 scoreboard[pipeline[plPtrWrite].operand2] = false;
1036 //This should be execute (or should it?--not sure now!)
1037 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1038 //and what just executed is now in the Write position...). So why didn't it do the
1039 //writeback into register 0?
1040 #ifdef DSP_DEBUG_IRQ
1041 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1042 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]);
1043 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]);
1044 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]);
1046 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1048 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1050 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1051 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1054 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1055 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1056 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1057 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1059 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1063 #ifndef NEW_SCOREBOARD
1064 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1065 scoreboard[pipeline[plPtrWrite].operand2] = false;
1067 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1068 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1069 if (scoreboard[pipeline[plPtrWrite].operand2])
1070 scoreboard[pipeline[plPtrWrite].operand2]--;
1077 ctrl2[4] = dsp_flags;
1080 DSPUpdateRegisterBanks();
1081 #ifdef DSP_DEBUG_IRQ
1082 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1083 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]);
1086 // subqt #4,r31 ; pre-decrement stack pointer
1087 // move pc,r30 ; address of interrupted code
1088 // store r30,(r31) ; store return address
1095 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1096 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1097 //It missed the place that it was supposed to come back to, so this is WRONG!
1099 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1101 // R -> baz (<- PC points here)
1102 // E -> bar (when it should point here!)
1105 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1106 // which means (assuming they're all 2 bytes long) that the code below will come back on
1107 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1108 // instruction stream...
1110 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1111 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1114 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1118 // movei #service_address,r30 ; pointer to ISR entry
1119 // jump (r30) ; jump to ISR
1121 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1124 ctrl2[0] = regs2[30] = dsp_pc;
1131 // Non-pipelined version...
1133 void DSPHandleIRQsNP(void)
1137 memcpy(dsp_ram_8, ram1, 0x2000);
1138 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1139 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1142 dsp_remain = ctrl1[2];
1143 dsp_modulo = ctrl1[3];
1144 dsp_flags = ctrl1[4];
1145 dsp_matrix_control = ctrl1[5];
1146 dsp_pointer_to_matrix = ctrl1[6];
1147 dsp_data_organization = ctrl1[7];
1148 dsp_control = ctrl1[8];
1149 dsp_div_control = ctrl1[9];
1150 IMASKCleared = ctrl1[10];
1151 dsp_flag_z = ctrl1[11];
1152 dsp_flag_n = ctrl1[12];
1153 dsp_flag_c = ctrl1[13];
1154 DSPUpdateRegisterBanks();
1157 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1160 // Get the active interrupt bits (latches) & interrupt mask (enables)
1161 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1162 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1164 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1167 if (!bits) // Bail if nothing is enabled
1170 int which = 0; // Determine which interrupt
1184 dsp_flags |= IMASK; // Force Bank #0
1187 ctrl1[4] = dsp_flags;
1190 #ifdef DSP_DEBUG_IRQ
1191 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1192 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1194 DSPUpdateRegisterBanks();
1195 #ifdef DSP_DEBUG_IRQ
1196 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1197 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1200 #ifdef DSP_DEBUG_IRQ
1201 WriteLog("DSP: Generating interrupt #%i...", which);
1202 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1205 // subqt #4,r31 ; pre-decrement stack pointer
1206 // move pc,r30 ; address of interrupted code
1207 // store r30,(r31) ; store return address
1209 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1216 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1217 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1220 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1224 // movei #service_address,r30 ; pointer to ISR entry
1225 // jump (r30) ; jump to ISR
1227 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1230 ctrl1[0] = regs1[30] = dsp_pc;
1236 // Set the specified DSP IRQ line to a given state
1238 void DSPSetIRQLine(int irqline, int state)
1240 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1241 uint32_t mask = INT_LAT0 << irqline;
1242 dsp_control &= ~mask; // Clear the latch bit
1245 ctrl1[8] = ctrl2[8] = dsp_control;
1251 dsp_control |= mask; // Set the latch bit
1252 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1257 ctrl1[8] = ctrl2[8] = dsp_control;
1263 // Not sure if this is correct behavior, but according to JTRM,
1264 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1265 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1266 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1269 bool DSPIsRunning(void)
1271 return (DSP_RUNNING ? true : false);
1276 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1277 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1278 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1280 dsp_build_branch_condition_table();
1282 srand(time(NULL)); // For randomizing local RAM
1287 dsp_pc = 0x00F1B000;
1288 dsp_acc = 0x00000000;
1289 dsp_remain = 0x00000000;
1290 dsp_modulo = 0xFFFFFFFF;
1291 dsp_flags = 0x00040000;
1292 dsp_matrix_control = 0x00000000;
1293 dsp_pointer_to_matrix = 0x00000000;
1294 dsp_data_organization = 0xFFFFFFFF;
1295 dsp_control = 0x00002000; // Report DSP version 2
1296 dsp_div_control = 0x00000000;
1299 dsp_reg = dsp_reg_bank_0;
1300 dsp_alternate_reg = dsp_reg_bank_1;
1302 for(int i=0; i<32; i++)
1303 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1306 IMASKCleared = false;
1309 // memset(dsp_ram_8, 0xFF, 0x2000);
1310 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1311 for(uint32_t i=0; i<8192; i+=4)
1313 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1317 void DSPDumpDisassembly(void)
1321 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1322 uint32_t j = 0xF1B000;
1324 while (j <= 0xF1CFFF)
1327 j += dasmjag(JAGUAR_DSP, buffer, j);
1328 WriteLog("\t%08X: %s\n", oldj, buffer);
1332 void DSPDumpRegisters(void)
1334 //Shoud add modulus, etc to dump here...
1335 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1336 WriteLog("\nRegisters bank 0\n");
1338 for(int j=0; j<8; j++)
1340 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1341 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1342 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1343 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1344 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1347 WriteLog("Registers bank 1\n");
1349 for(int j=0; j<8; j++)
1351 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1352 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1353 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1354 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1355 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1362 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1363 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1365 // get the active interrupt bits
1366 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1367 // get the interrupt mask
1368 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1370 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1371 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1372 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1373 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1374 WriteLog("\nRegisters bank 0\n");
1376 for(int j=0; j<8; j++)
1378 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1379 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1380 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1381 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1382 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1385 WriteLog("\nRegisters bank 1\n");
1389 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1390 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1391 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1392 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1393 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1398 static char buffer[512];
1399 j = DSP_WORK_RAM_BASE;
1401 while (j <= 0xF1CFFF)
1404 j += dasmjag(JAGUAR_DSP, buffer, j);
1405 WriteLog("\t%08X: %s\n", oldj, buffer);
1408 WriteLog("DSP opcodes use:\n");
1412 if (dsp_opcode_use[i])
1413 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1420 // DSP comparison core...
1423 static uint16_t lastExec;
1424 void DSPExecComp(int32_t cycles)
1426 while (cycles > 0 && DSP_RUNNING)
1428 // Load up vars for non-pipelined core
1429 memcpy(dsp_ram_8, ram1, 0x2000);
1430 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1431 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1434 dsp_remain = ctrl1[2];
1435 dsp_modulo = ctrl1[3];
1436 dsp_flags = ctrl1[4];
1437 dsp_matrix_control = ctrl1[5];
1438 dsp_pointer_to_matrix = ctrl1[6];
1439 dsp_data_organization = ctrl1[7];
1440 dsp_control = ctrl1[8];
1441 dsp_div_control = ctrl1[9];
1442 IMASKCleared = ctrl1[10];
1443 dsp_flag_z = ctrl1[11];
1444 dsp_flag_n = ctrl1[12];
1445 dsp_flag_c = ctrl1[13];
1446 DSPUpdateRegisterBanks();
1448 // Decrement cycles based on non-pipelined core...
1449 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1450 cycles -= dsp_opcode_cycles[instr1 >> 10];
1452 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1453 DSPExec(1); // Do *one* instruction
1456 memcpy(ram1, dsp_ram_8, 0x2000);
1457 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1458 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1461 ctrl1[2] = dsp_remain;
1462 ctrl1[3] = dsp_modulo;
1463 ctrl1[4] = dsp_flags;
1464 ctrl1[5] = dsp_matrix_control;
1465 ctrl1[6] = dsp_pointer_to_matrix;
1466 ctrl1[7] = dsp_data_organization;
1467 ctrl1[8] = dsp_control;
1468 ctrl1[9] = dsp_div_control;
1469 ctrl1[10] = IMASKCleared;
1470 ctrl1[11] = dsp_flag_z;
1471 ctrl1[12] = dsp_flag_n;
1472 ctrl1[13] = dsp_flag_c;
1474 // Load up vars for pipelined core
1475 memcpy(dsp_ram_8, ram2, 0x2000);
1476 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1477 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1480 dsp_remain = ctrl2[2];
1481 dsp_modulo = ctrl2[3];
1482 dsp_flags = ctrl2[4];
1483 dsp_matrix_control = ctrl2[5];
1484 dsp_pointer_to_matrix = ctrl2[6];
1485 dsp_data_organization = ctrl2[7];
1486 dsp_control = ctrl2[8];
1487 dsp_div_control = ctrl2[9];
1488 IMASKCleared = ctrl2[10];
1489 dsp_flag_z = ctrl2[11];
1490 dsp_flag_n = ctrl2[12];
1491 dsp_flag_c = ctrl2[13];
1492 DSPUpdateRegisterBanks();
1494 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1495 DSPExecP2(1); // Do *one* instruction
1498 memcpy(ram2, dsp_ram_8, 0x2000);
1499 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1500 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1503 ctrl2[2] = dsp_remain;
1504 ctrl2[3] = dsp_modulo;
1505 ctrl2[4] = dsp_flags;
1506 ctrl2[5] = dsp_matrix_control;
1507 ctrl2[6] = dsp_pointer_to_matrix;
1508 ctrl2[7] = dsp_data_organization;
1509 ctrl2[8] = dsp_control;
1510 ctrl2[9] = dsp_div_control;
1511 ctrl2[10] = IMASKCleared;
1512 ctrl2[11] = dsp_flag_z;
1513 ctrl2[12] = dsp_flag_n;
1514 ctrl2[13] = dsp_flag_c;
1516 if (instr1 != lastExec)
1518 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1520 // uint32_t 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));
1521 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1522 // if (ctrl1[0] < ppc) // P ran ahead of NP
1523 //How to test this crap???
1526 DSPExecP2(1); // Do one more instruction
1529 memcpy(ram2, dsp_ram_8, 0x2000);
1530 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1531 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1534 ctrl2[2] = dsp_remain;
1535 ctrl2[3] = dsp_modulo;
1536 ctrl2[4] = dsp_flags;
1537 ctrl2[5] = dsp_matrix_control;
1538 ctrl2[6] = dsp_pointer_to_matrix;
1539 ctrl2[7] = dsp_data_organization;
1540 ctrl2[8] = dsp_control;
1541 ctrl2[9] = dsp_div_control;
1542 ctrl2[10] = IMASKCleared;
1543 ctrl2[11] = dsp_flag_z;
1544 ctrl2[12] = dsp_flag_n;
1545 ctrl2[13] = dsp_flag_c;
1547 // else // NP ran ahead of P
1548 if (instr1 != lastExec) // Must be the other way...
1551 // Load up vars for non-pipelined core
1552 memcpy(dsp_ram_8, ram1, 0x2000);
1553 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1554 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1557 dsp_remain = ctrl1[2];
1558 dsp_modulo = ctrl1[3];
1559 dsp_flags = ctrl1[4];
1560 dsp_matrix_control = ctrl1[5];
1561 dsp_pointer_to_matrix = ctrl1[6];
1562 dsp_data_organization = ctrl1[7];
1563 dsp_control = ctrl1[8];
1564 dsp_div_control = ctrl1[9];
1565 IMASKCleared = ctrl1[10];
1566 dsp_flag_z = ctrl1[11];
1567 dsp_flag_n = ctrl1[12];
1568 dsp_flag_c = ctrl1[13];
1569 DSPUpdateRegisterBanks();
1571 for(int k=0; k<2; k++)
1573 // Decrement cycles based on non-pipelined core...
1574 instr1 = DSPReadWord(dsp_pc, DSP);
1575 cycles -= dsp_opcode_cycles[instr1 >> 10];
1577 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1578 DSPExec(1); // Do *one* instruction
1582 memcpy(ram1, dsp_ram_8, 0x2000);
1583 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1584 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1587 ctrl1[2] = dsp_remain;
1588 ctrl1[3] = dsp_modulo;
1589 ctrl1[4] = dsp_flags;
1590 ctrl1[5] = dsp_matrix_control;
1591 ctrl1[6] = dsp_pointer_to_matrix;
1592 ctrl1[7] = dsp_data_organization;
1593 ctrl1[8] = dsp_control;
1594 ctrl1[9] = dsp_div_control;
1595 ctrl1[10] = IMASKCleared;
1596 ctrl1[11] = dsp_flag_z;
1597 ctrl1[12] = dsp_flag_n;
1598 ctrl1[13] = dsp_flag_c;
1602 if (instr1 != lastExec)
1604 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1606 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1607 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1620 // DSP execution core
1622 //static bool R20Set = false, tripwire = false;
1623 //static uint32_t pcQueue[32], ptrPCQ = 0;
1624 void DSPExec(int32_t cycles)
1626 #ifdef DSP_SINGLE_STEPPING
1627 if (dsp_control & 0x18)
1630 dsp_control &= ~0x10;
1633 //There is *no* good reason to do this here!
1635 dsp_releaseTimeSlice_flag = 0;
1638 while (cycles > 0 && DSP_RUNNING)
1640 /*extern uint32_t totalFrames;
1641 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1642 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1643 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1645 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1648 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1650 if (dsp_pc == 0xF1B092)
1651 doDSPDis = false;//*/
1652 /*if (dsp_pc == 0xF1B140)
1653 doDSPDis = true;//*/
1655 if (IMASKCleared) // If IMASK was cleared,
1657 #ifdef DSP_DEBUG_IRQ
1658 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1660 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1661 IMASKCleared = false;
1666 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1667 for(int i=0; i<80; i+=4)
1668 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1671 /*if (dsp_pc == 0xF1B55E)
1673 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1675 /*if (dsp_pc == 0xF1B7D2) // Start here???
1677 pcQueue[ptrPCQ++] = dsp_pc;
1679 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1680 uint32_t index = opcode >> 10;
1681 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1682 dsp_opcode_second_parameter = opcode & 0x1F;
1684 dsp_opcode[index]();
1685 dsp_opcode_use[index]++;
1686 cycles -= dsp_opcode_cycles[index];
1687 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1689 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1692 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1694 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1696 DSPDumpDisassembly();
1699 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1702 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1705 WriteLog("\nBacktrace:\n");
1706 for(int i=0; i<32; i++)
1708 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1709 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1719 // DSP opcode handlers
1722 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1723 // can cause trouble because an interrupt can occur *before* the instruction following the
1724 // jump can execute... !!! FIX !!!
1725 static void dsp_opcode_jump(void)
1728 const char * condition[32] =
1729 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1730 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1731 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1732 "???", "???", "???", "F" };
1734 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);
1737 /* dsp_flag_c=dsp_flag_c?1:0;
1738 dsp_flag_z=dsp_flag_z?1:0;
1739 dsp_flag_n=dsp_flag_n?1:0;*/
1740 // KLUDGE: Used by BRANCH_CONDITION
1741 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1743 if (BRANCH_CONDITION(IMM_2))
1747 WriteLog("Branched!\n");
1749 uint32_t delayed_pc = RM;
1751 dsp_pc = delayed_pc;
1756 WriteLog("Branch NOT taken.\n");
1760 static void dsp_opcode_jr(void)
1763 const char * condition[32] =
1764 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1765 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1766 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1767 "???", "???", "???", "F" };
1769 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);
1772 /* dsp_flag_c=dsp_flag_c?1:0;
1773 dsp_flag_z=dsp_flag_z?1:0;
1774 dsp_flag_n=dsp_flag_n?1:0;*/
1775 // KLUDGE: Used by BRANCH_CONDITION
1776 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1778 if (BRANCH_CONDITION(IMM_2))
1782 WriteLog("Branched!\n");
1784 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1785 int32_t delayed_pc = dsp_pc + (offset * 2);
1787 dsp_pc = delayed_pc;
1792 WriteLog("Branch NOT taken.\n");
1796 static void dsp_opcode_add(void)
1800 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);
1802 uint32_t res = RN + RM;
1803 SET_ZNC_ADD(RN, RM, res);
1807 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);
1811 static void dsp_opcode_addc(void)
1815 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);
1817 uint32_t res = RN + RM + dsp_flag_c;
1818 uint32_t carry = dsp_flag_c;
1819 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1820 SET_ZNC_ADD(RN + carry, RM, res);
1821 // SET_ZNC_ADD(RN, RM + carry, res);
1825 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);
1829 static void dsp_opcode_addq(void)
1833 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);
1835 uint32_t r1 = dsp_convert_zero[IMM_1];
1836 uint32_t res = RN + r1;
1837 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1841 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1845 static void dsp_opcode_sub(void)
1849 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);
1851 uint32_t res = RN - RM;
1852 SET_ZNC_SUB(RN, RM, res);
1856 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);
1860 static void dsp_opcode_subc(void)
1864 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);
1866 uint32_t res = RN - RM - dsp_flag_c;
1867 uint32_t borrow = dsp_flag_c;
1868 SET_ZNC_SUB(RN - borrow, RM, res);
1872 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);
1876 static void dsp_opcode_subq(void)
1880 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);
1882 uint32_t r1 = dsp_convert_zero[IMM_1];
1883 uint32_t res = RN - r1;
1884 SET_ZNC_SUB(RN, r1, res);
1888 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1892 static void dsp_opcode_cmp(void)
1896 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);
1898 uint32_t res = RN - RM;
1899 SET_ZNC_SUB(RN, RM, res);
1902 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1906 static void dsp_opcode_cmpq(void)
1908 static int32_t sqtable[32] =
1909 { 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 };
1912 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);
1914 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1915 uint32_t res = RN - r1;
1916 SET_ZNC_SUB(RN, r1, res);
1919 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1923 static void dsp_opcode_and(void)
1927 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);
1933 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);
1937 static void dsp_opcode_or(void)
1941 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);
1947 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);
1951 static void dsp_opcode_xor(void)
1955 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);
1961 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);
1965 static void dsp_opcode_not(void)
1969 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);
1975 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1979 static void dsp_opcode_move_pc(void)
1984 static void dsp_opcode_store_r14_indexed(void)
1986 #ifdef DSP_DIS_STORE14I
1988 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));
1990 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1991 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1993 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1997 static void dsp_opcode_store_r15_indexed(void)
1999 #ifdef DSP_DIS_STORE15I
2001 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));
2003 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2004 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2006 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2010 static void dsp_opcode_load_r14_ri(void)
2012 #ifdef DSP_DIS_LOAD14R
2014 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);
2016 #ifdef DSP_CORRECT_ALIGNMENT
2017 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2019 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2021 #ifdef DSP_DIS_LOAD14R
2023 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2027 static void dsp_opcode_load_r15_ri(void)
2029 #ifdef DSP_DIS_LOAD15R
2031 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);
2033 #ifdef DSP_CORRECT_ALIGNMENT
2034 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2036 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2038 #ifdef DSP_DIS_LOAD15R
2040 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2044 static void dsp_opcode_store_r14_ri(void)
2046 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2049 static void dsp_opcode_store_r15_ri(void)
2051 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2054 static void dsp_opcode_nop(void)
2058 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2062 static void dsp_opcode_storeb(void)
2064 #ifdef DSP_DIS_STOREB
2066 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);
2068 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2069 DSPWriteLong(RM, RN & 0xFF, DSP);
2071 JaguarWriteByte(RM, RN, DSP);
2074 static void dsp_opcode_storew(void)
2076 #ifdef DSP_DIS_STOREW
2078 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);
2080 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2081 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2082 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2084 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2086 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2087 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2089 JaguarWriteWord(RM, RN, DSP);
2093 static void dsp_opcode_store(void)
2095 #ifdef DSP_DIS_STORE
2097 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);
2099 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2100 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2102 DSPWriteLong(RM, RN, DSP);
2106 static void dsp_opcode_loadb(void)
2108 #ifdef DSP_DIS_LOADB
2110 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);
2112 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2113 RN = DSPReadLong(RM, DSP) & 0xFF;
2115 RN = JaguarReadByte(RM, DSP);
2116 #ifdef DSP_DIS_LOADB
2118 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2122 static void dsp_opcode_loadw(void)
2124 #ifdef DSP_DIS_LOADW
2126 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);
2128 #ifdef DSP_CORRECT_ALIGNMENT
2129 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2130 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2132 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2134 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2135 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2137 RN = JaguarReadWord(RM, DSP);
2139 #ifdef DSP_DIS_LOADW
2141 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2145 static void dsp_opcode_load(void)
2149 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);
2151 #ifdef DSP_CORRECT_ALIGNMENT
2152 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2154 RN = DSPReadLong(RM, DSP);
2158 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2162 static void dsp_opcode_load_r14_indexed(void)
2164 #ifdef DSP_DIS_LOAD14I
2166 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);
2168 #ifdef DSP_CORRECT_ALIGNMENT
2169 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2171 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2173 #ifdef DSP_DIS_LOAD14I
2175 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2179 static void dsp_opcode_load_r15_indexed(void)
2181 #ifdef DSP_DIS_LOAD15I
2183 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);
2185 #ifdef DSP_CORRECT_ALIGNMENT
2186 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2188 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2190 #ifdef DSP_DIS_LOAD15I
2192 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2196 static void dsp_opcode_movei(void)
2198 #ifdef DSP_DIS_MOVEI
2200 WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, (uint32_t)DSPReadWord(dsp_pc) | ((uint32_t)DSPReadWord(dsp_pc + 2) << 16), IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2202 // This instruction is followed by 32-bit value in LSW / MSW format...
2203 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2205 #ifdef DSP_DIS_MOVEI
2207 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2211 static void dsp_opcode_moveta(void)
2213 #ifdef DSP_DIS_MOVETA
2215 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);
2218 #ifdef DSP_DIS_MOVETA
2220 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);
2224 static void dsp_opcode_movefa(void)
2226 #ifdef DSP_DIS_MOVEFA
2228 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);
2231 #ifdef DSP_DIS_MOVEFA
2233 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);
2237 static void dsp_opcode_move(void)
2241 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);
2246 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);
2250 static void dsp_opcode_moveq(void)
2252 #ifdef DSP_DIS_MOVEQ
2254 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);
2257 #ifdef DSP_DIS_MOVEQ
2259 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2263 static void dsp_opcode_resmac(void)
2265 #ifdef DSP_DIS_RESMAC
2267 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_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2269 RN = (uint32_t)dsp_acc;
2270 #ifdef DSP_DIS_RESMAC
2272 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2276 static void dsp_opcode_imult(void)
2278 #ifdef DSP_DIS_IMULT
2280 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);
2282 RN = (int16_t)RN * (int16_t)RM;
2284 #ifdef DSP_DIS_IMULT
2286 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);
2290 static void dsp_opcode_mult(void)
2294 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);
2296 RN = (uint16_t)RM * (uint16_t)RN;
2300 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);
2304 static void dsp_opcode_bclr(void)
2308 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);
2310 uint32_t res = RN & ~(1 << IMM_1);
2315 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2319 static void dsp_opcode_btst(void)
2323 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);
2325 dsp_flag_z = (~RN >> IMM_1) & 1;
2328 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2332 static void dsp_opcode_bset(void)
2336 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);
2338 uint32_t res = RN | (1 << IMM_1);
2343 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2347 static void dsp_opcode_subqt(void)
2349 #ifdef DSP_DIS_SUBQT
2351 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);
2353 RN -= dsp_convert_zero[IMM_1];
2354 #ifdef DSP_DIS_SUBQT
2356 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2360 static void dsp_opcode_addqt(void)
2362 #ifdef DSP_DIS_ADDQT
2364 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);
2366 RN += dsp_convert_zero[IMM_1];
2367 #ifdef DSP_DIS_ADDQT
2369 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2373 static void dsp_opcode_imacn(void)
2375 #ifdef DSP_DIS_IMACN
2377 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);
2379 int32_t res = (int16_t)RM * (int16_t)RN;
2380 dsp_acc += (int64_t)res;
2381 //Should we AND the result to fit into 40 bits here???
2382 #ifdef DSP_DIS_IMACN
2384 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2388 static void dsp_opcode_mtoi(void)
2390 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2394 static void dsp_opcode_normi(void)
2401 while ((_Rm & 0xffc00000) == 0)
2406 while ((_Rm & 0xff800000) != 0)
2416 static void dsp_opcode_mmult(void)
2418 int count = dsp_matrix_control&0x0f;
2419 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2423 if (!(dsp_matrix_control & 0x10))
2425 for (int i = 0; i < count; i++)
2429 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2431 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2432 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2439 for (int i = 0; i < count; i++)
2443 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2445 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2446 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2451 RN = res = (int32_t)accum;
2453 //NOTE: The flags are set based upon the last add/multiply done...
2457 static void dsp_opcode_abs(void)
2461 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);
2466 if (_Rn == 0x80000000)
2470 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2471 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2476 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2480 static void dsp_opcode_div(void)
2487 if (dsp_div_control & 1)
2489 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2490 if (dsp_remain&0x80000000)
2492 RN = (((uint64_t)_Rn) << 16) / _Rm;
2496 dsp_remain = _Rn % _Rm;
2497 if (dsp_remain&0x80000000)
2506 static void dsp_opcode_imultn(void)
2508 #ifdef DSP_DIS_IMULTN
2510 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);
2512 // This is OK, since this multiply won't overflow 32 bits...
2513 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2514 dsp_acc = (int64_t)res;
2516 #ifdef DSP_DIS_IMULTN
2518 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2522 static void dsp_opcode_neg(void)
2526 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);
2529 SET_ZNC_SUB(0, RN, res);
2533 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2537 static void dsp_opcode_shlq(void)
2541 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);
2543 // NB: This instruction is the *only* one that does (32 - immediate data).
2544 int32_t r1 = 32 - IMM_1;
2545 uint32_t res = RN << r1;
2546 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2550 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2554 static void dsp_opcode_shrq(void)
2558 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);
2560 int32_t r1 = dsp_convert_zero[IMM_1];
2561 uint32_t res = RN >> r1;
2562 SET_ZN(res); dsp_flag_c = RN & 1;
2566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2570 static void dsp_opcode_ror(void)
2574 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);
2576 uint32_t r1 = RM & 0x1F;
2577 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2578 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2582 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);
2586 static void dsp_opcode_rorq(void)
2590 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);
2592 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2594 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2596 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2599 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2603 static void dsp_opcode_sha(void)
2605 int32_t sRm=(int32_t)RM;
2610 uint32_t shift=-sRm;
2611 if (shift>=32) shift=32;
2612 dsp_flag_c=(_Rn&0x80000000)>>31;
2622 if (shift>=32) shift=32;
2626 _Rn=((int32_t)_Rn)>>1;
2634 static void dsp_opcode_sharq(void)
2636 #ifdef DSP_DIS_SHARQ
2638 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);
2640 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2641 SET_ZN(res); dsp_flag_c = RN & 0x01;
2643 #ifdef DSP_DIS_SHARQ
2645 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2649 static void dsp_opcode_sh(void)
2651 int32_t sRm=(int32_t)RM;
2656 uint32_t shift=(-sRm);
2657 if (shift>=32) shift=32;
2658 dsp_flag_c=(_Rn&0x80000000)>>31;
2668 if (shift>=32) shift=32;
2680 void dsp_opcode_addqmod(void)
2682 #ifdef DSP_DIS_ADDQMOD
2684 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);
2686 uint32_t r1 = dsp_convert_zero[IMM_1];
2688 uint32_t res = r2 + r1;
2689 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2691 SET_ZNC_ADD(r2, r1, res);
2692 #ifdef DSP_DIS_ADDQMOD
2694 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2698 void dsp_opcode_subqmod(void)
2700 uint32_t r1 = dsp_convert_zero[IMM_1];
2702 uint32_t res = r2 - r1;
2703 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2706 SET_ZNC_SUB(r2, r1, res);
2709 void dsp_opcode_mirror(void)
2712 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2716 void dsp_opcode_sat32s(void)
2718 int32_t r2 = (uint32_t)RN;
2719 int32_t temp = dsp_acc >> 32;
2720 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2725 void dsp_opcode_sat16s(void)
2728 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2733 void dsp_opcode_illegal(void)
2735 // Don't know what it does, but it does *something*...
2736 WriteLog("%06X: illegal %u, %u [NCZ:%u%u%u]\n", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2740 // New pipelined DSP core
2743 static void DSP_abs(void);
2744 static void DSP_add(void);
2745 static void DSP_addc(void);
2746 static void DSP_addq(void);
2747 static void DSP_addqmod(void);
2748 static void DSP_addqt(void);
2749 static void DSP_and(void);
2750 static void DSP_bclr(void);
2751 static void DSP_bset(void);
2752 static void DSP_btst(void);
2753 static void DSP_cmp(void);
2754 static void DSP_cmpq(void);
2755 static void DSP_div(void);
2756 static void DSP_imacn(void);
2757 static void DSP_imult(void);
2758 static void DSP_imultn(void);
2759 static void DSP_illegal(void);
2760 static void DSP_jr(void);
2761 static void DSP_jump(void);
2762 static void DSP_load(void);
2763 static void DSP_loadb(void);
2764 static void DSP_loadw(void);
2765 static void DSP_load_r14_i(void);
2766 static void DSP_load_r14_r(void);
2767 static void DSP_load_r15_i(void);
2768 static void DSP_load_r15_r(void);
2769 static void DSP_mirror(void);
2770 static void DSP_mmult(void);
2771 static void DSP_move(void);
2772 static void DSP_movefa(void);
2773 static void DSP_movei(void);
2774 static void DSP_movepc(void);
2775 static void DSP_moveq(void);
2776 static void DSP_moveta(void);
2777 static void DSP_mtoi(void);
2778 static void DSP_mult(void);
2779 static void DSP_neg(void);
2780 static void DSP_nop(void);
2781 static void DSP_normi(void);
2782 static void DSP_not(void);
2783 static void DSP_or(void);
2784 static void DSP_resmac(void);
2785 static void DSP_ror(void);
2786 static void DSP_rorq(void);
2787 static void DSP_sat16s(void);
2788 static void DSP_sat32s(void);
2789 static void DSP_sh(void);
2790 static void DSP_sha(void);
2791 static void DSP_sharq(void);
2792 static void DSP_shlq(void);
2793 static void DSP_shrq(void);
2794 static void DSP_store(void);
2795 static void DSP_storeb(void);
2796 static void DSP_storew(void);
2797 static void DSP_store_r14_i(void);
2798 static void DSP_store_r14_r(void);
2799 static void DSP_store_r15_i(void);
2800 static void DSP_store_r15_r(void);
2801 static void DSP_sub(void);
2802 static void DSP_subc(void);
2803 static void DSP_subq(void);
2804 static void DSP_subqmod(void);
2805 static void DSP_subqt(void);
2806 static void DSP_xor(void);
2808 void (* DSPOpcode[64])() =
2810 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2811 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2812 DSP_neg, DSP_and, DSP_or, DSP_xor,
2813 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2815 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2816 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2817 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2818 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2820 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2821 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2822 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2823 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2825 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2826 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2827 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2828 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2831 bool readAffected[64][2] =
2833 { true, true}, { true, true}, {false, true}, {false, true},
2834 { true, true}, { true, true}, {false, true}, {false, true},
2835 {false, true}, { true, true}, { true, true}, { true, true},
2836 {false, true}, {false, true}, {false, true}, {false, true},
2838 { true, true}, { true, true}, { true, true}, {false, true},
2839 { true, true}, { true, true}, {false, true}, { true, true},
2840 {false, true}, {false, true}, { true, true}, {false, true},
2841 { true, true}, {false, true}, { true, true}, {false, true},
2843 {false, true}, {false, true}, { true, false}, {false, false},
2844 { true, false}, {false, false}, {false, false}, { true, false},
2845 { true, false}, { true, false}, {false, true}, { true, false},
2846 { true, false}, { true, true}, { true, true}, { true, true},
2848 {false, true}, { true, true}, { true, true}, {false, true},
2849 { true, false}, { true, false}, { true, true}, { true, false},
2850 { true, false}, {false, false}, { true, false}, { true, false},
2851 { true, true}, { true, true}, {false, false}, {false, true}
2854 bool isLoadStore[65] =
2856 false, false, false, false, false, false, false, false,
2857 false, false, false, false, false, false, false, false,
2859 false, false, false, false, false, false, false, false,
2860 false, false, false, false, false, false, false, false,
2862 false, false, false, false, false, false, false, true,
2863 true, true, false, true, true, true, true, true,
2865 false, true, true, false, false, false, false, false,
2866 false, false, true, true, true, true, false, false, false
2869 void FlushDSPPipeline(void)
2871 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2873 for(int i=0; i<4; i++)
2874 pipeline[i].opcode = PIPELINE_STALL;
2876 for(int i=0; i<32; i++)
2881 // New pipelined DSP execution core
2883 /*void DSPExecP(int32_t cycles)
2885 // bool inhibitFetch = false;
2887 dsp_releaseTimeSlice_flag = 0;
2890 while (cycles > 0 && DSP_RUNNING)
2892 WriteLog("DSPExecP: Pipeline status...\n");
2893 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);
2894 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);
2895 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);
2896 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);
2897 WriteLog(" --> Scoreboard: ");
2898 for(int i=0; i<32; i++)
2899 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2901 // Stage 1: Instruction fetch
2902 // if (!inhibitFetch)
2904 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2905 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2906 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2907 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2908 if (pipeline[plPtrFetch].opcode == 38)
2909 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2910 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2913 // inhibitFetch = false;
2914 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2916 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2917 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);
2918 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);
2919 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);
2920 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);
2921 // Stage 2: Read registers
2922 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2923 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2924 if (scoreboard[pipeline[plPtrRead].operand2])
2925 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2926 // We have a hit in the scoreboard, so we have to stall the pipeline...
2928 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2929 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2930 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2931 pipeline[plPtrFetch] = pipeline[plPtrRead];
2932 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2936 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2937 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2938 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2940 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2941 // Shouldn't we be more selective with the register scoreboarding?
2942 // Yes, we should. !!! FIX !!!
2943 scoreboard[pipeline[plPtrRead].operand2] = true;
2944 //Advance PC here??? Yes.
2945 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2946 //This is a mangling of the pipeline stages, but what else to do???
2947 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2950 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2951 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);
2952 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);
2953 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);
2954 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);
2956 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2958 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2959 DSPOpcode[pipeline[plPtrExec].opcode]();
2960 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2961 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2966 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2967 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);
2968 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);
2969 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);
2970 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);
2971 // Stage 4: Write back register
2972 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2974 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2975 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2977 scoreboard[pipeline[plPtrWrite].operand1]
2978 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2981 // Push instructions through the pipeline...
2982 plPtrFetch = (++plPtrFetch) & 0x03;
2983 plPtrRead = (++plPtrRead) & 0x03;
2984 plPtrExec = (++plPtrExec) & 0x03;
2985 plPtrWrite = (++plPtrWrite) & 0x03;
2992 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2994 // Should be fixed now. Another problem is figuring how to do the sequence following
2995 // a branch followed with the JR & JUMP instructions...
2997 // There are two conflicting problems:
3000 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3001 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3002 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3003 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3004 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3005 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3006 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3007 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3008 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3009 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3010 DSP: Finished interrupt.
3011 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3012 ; bank 0 (where is was prepared)!
3013 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3014 F1B252: NOP [NCZ:001]
3017 // The other is when you see this at the end of an IRQ:
3020 JUMP T, (R29) ; R29 = Previous stack + 2
3021 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3023 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3024 ; 1) The STORE goes through the pipeline and is executed/written back
3025 ; 2) The pipeline is flushed
3026 ; 3) The DSP_PC is set to the new address
3027 ; 4) Execution resumes
3029 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3030 ; bank 0 instead of the current bank 1 and so goes astray!
3033 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3034 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3038 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3039 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3040 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3041 If it were done properly, the STORE write back would occur *after* (well, technically,
3042 during) the execution of the the JUMP that follows it.
3046 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3047 F1B08A: NOP [NCZ:001]
3049 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3052 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3055 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3056 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3057 F1B08A: NOP [NCZ:001]
3059 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3062 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3063 DSP: CPU -> DSP interrupt
3064 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3065 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3067 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3070 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3071 F1B006: NOP [NCZ:001]
3073 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3076 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3077 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3080 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3081 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3084 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3085 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3088 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3089 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3092 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3095 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3098 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3099 F1B0FE: NOP [NCZ:000]
3101 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3104 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3107 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3108 F1B138: NOP [NCZ:000]
3110 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3113 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3114 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3115 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3118 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3119 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3122 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3123 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3124 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3126 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3127 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3130 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3131 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3132 DSP: Finished interrupt.
3133 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3135 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3138 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3139 F1B016: NOP [NCZ:001]
3141 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3144 uint32_t pcQueue1[0x400];
3145 uint32_t pcQPtr1 = 0;
3146 static uint32_t prevR1;
3147 //Let's try a 3 stage pipeline....
3148 //Looks like 3 stage is correct, otherwise bad things happen...
3149 void DSPExecP2(int32_t cycles)
3151 dsp_releaseTimeSlice_flag = 0;
3154 while (cycles > 0 && DSP_RUNNING)
3156 /*extern uint32_t totalFrames;
3157 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3158 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3159 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3161 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3164 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3166 if (dsp_pc == 0xF1B092)
3167 doDSPDis = false;//*/
3168 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3169 doDSPDis = true;//*/
3170 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3171 doDSPDis = true;//*/
3172 /*if (dsp_pc == 0xF1B0A0)
3173 doDSPDis = true;//*/
3174 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3175 doDSPDis = true;//*/
3176 //Two parter... (not sure how to write this)
3177 //if (dsp_pc == 0xF1B0D2)
3178 // prevR1 = dsp_reg[1];
3180 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3181 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3184 pcQueue1[pcQPtr1++] = dsp_pc;
3187 #ifdef DSP_DEBUG_PL2
3188 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3190 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3195 for(int i=0; i<0x400; i++)
3197 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3198 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3204 if (IMASKCleared) // If IMASK was cleared,
3206 #ifdef DSP_DEBUG_IRQ
3207 WriteLog("DSP: Finished interrupt.\n");
3209 DSPHandleIRQs(); // See if any other interrupts are pending!
3210 IMASKCleared = false;
3213 //if (dsp_flags & REGPAGE)
3214 // WriteLog(" --> REGPAGE has just been set!\n");
3215 #ifdef DSP_DEBUG_PL2
3218 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3219 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]);
3220 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]);
3221 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]);
3222 WriteLog(" --> Scoreboard: ");
3223 for(int i=0; i<32; i++)
3224 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3228 // Stage 1a: Instruction fetch
3229 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3230 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3231 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3232 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3233 if (pipeline[plPtrRead].opcode == 38)
3234 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3235 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3236 #ifdef DSP_DEBUG_PL2
3239 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3240 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3241 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]);
3242 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]);
3243 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]);
3246 // Stage 1b: Read registers
3247 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3248 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3250 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3251 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3252 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3253 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3254 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3255 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3256 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3258 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3259 // We have a hit in the scoreboard, so we have to stall the pipeline...
3260 #ifdef DSP_DEBUG_PL2
3264 WriteLog(" --> Stalling pipeline: ");
3265 if (readAffected[pipeline[plPtrRead].opcode][0])
3266 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3267 if (readAffected[pipeline[plPtrRead].opcode][1])
3268 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3272 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3273 #ifdef DSP_DEBUG_PL2
3278 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3279 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3280 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3282 // Shouldn't we be more selective with the register scoreboarding?
3283 // Yes, we should. !!! FIX !!! Kinda [DONE]
3284 #ifndef NEW_SCOREBOARD
3285 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3287 //Hopefully this will fix the dual MOVEQ # problem...
3288 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3291 //Advance PC here??? Yes.
3292 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3295 #ifdef DSP_DEBUG_PL2
3298 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3299 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]);
3300 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]);
3301 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]);
3305 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3307 #ifdef DSP_DEBUG_PL2
3309 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"));
3313 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3318 lastExec = pipeline[plPtrExec].instruction;
3319 //WriteLog("[lastExec = %04X]\n", lastExec);
3321 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3322 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3323 DSPOpcode[pipeline[plPtrExec].opcode]();
3324 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3328 //Let's not, until we do the stalling correctly...
3329 //But, we gotta while we're doing the comparison core...!
3330 //Or do we? cycles--;
3331 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3332 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3333 //to model this clock cycle behavior correctly...
3334 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3335 //don't affect the reads at stage 1...
3336 #ifdef DSP_DEBUG_STALL
3338 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3342 #ifdef DSP_DEBUG_PL2
3345 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3346 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]);
3347 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]);
3348 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]);
3352 // Stage 3: Write back register/memory address
3353 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3355 /*if (pipeline[plPtrWrite].writebackRegister == 3
3356 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3359 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3362 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3364 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3365 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3368 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3369 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3370 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3371 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3373 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3377 #ifndef NEW_SCOREBOARD
3378 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3379 scoreboard[pipeline[plPtrWrite].operand2] = false;
3381 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3382 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3383 if (scoreboard[pipeline[plPtrWrite].operand2])
3384 scoreboard[pipeline[plPtrWrite].operand2]--;
3388 // Push instructions through the pipeline...
3389 plPtrRead = (++plPtrRead) & 0x03;
3390 plPtrExec = (++plPtrExec) & 0x03;
3391 plPtrWrite = (++plPtrWrite) & 0x03;
3400 //#define DSP_DEBUG_PL3
3401 //Let's try a 2 stage pipeline....
3402 void DSPExecP3(int32_t cycles)
3404 dsp_releaseTimeSlice_flag = 0;
3407 while (cycles > 0 && DSP_RUNNING)
3409 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3411 #ifdef DSP_DEBUG_PL3
3412 WriteLog("DSPExecP: Pipeline status...\n");
3413 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]);
3414 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]);
3415 WriteLog(" --> Scoreboard: ");
3416 for(int i=0; i<32; i++)
3417 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3420 // Stage 1a: Instruction fetch
3421 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3422 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3423 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3424 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3425 if (pipeline[plPtrRead].opcode == 38)
3426 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3427 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3428 #ifdef DSP_DEBUG_PL3
3429 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3430 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3431 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]);
3432 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]);
3434 // Stage 1b: Read registers
3435 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3436 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3437 // We have a hit in the scoreboard, so we have to stall the pipeline...
3438 #ifdef DSP_DEBUG_PL3
3440 WriteLog(" --> Stalling pipeline: ");
3441 if (readAffected[pipeline[plPtrRead].opcode][0])
3442 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3443 if (readAffected[pipeline[plPtrRead].opcode][1])
3444 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3447 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3448 #ifdef DSP_DEBUG_PL3
3453 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3454 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3455 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3457 // Shouldn't we be more selective with the register scoreboarding?
3458 // Yes, we should. !!! FIX !!! [Kinda DONE]
3459 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3461 //Advance PC here??? Yes.
3462 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3465 #ifdef DSP_DEBUG_PL3
3466 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3467 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]);
3468 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]);
3470 // Stage 2a: Execute
3471 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3473 #ifdef DSP_DEBUG_PL3
3474 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3476 DSPOpcode[pipeline[plPtrExec].opcode]();
3477 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3478 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3483 #ifdef DSP_DEBUG_PL3
3484 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3485 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]);
3486 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]);
3489 // Stage 2b: Write back register
3490 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3492 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3493 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3495 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3496 scoreboard[pipeline[plPtrExec].operand2] = false;
3499 // Push instructions through the pipeline...
3500 plPtrRead = (++plPtrRead) & 0x03;
3501 plPtrExec = (++plPtrExec) & 0x03;
3508 // DSP pipelined opcode handlers
3511 #define PRM pipeline[plPtrExec].reg1
3512 #define PRN pipeline[plPtrExec].reg2
3513 #define PIMM1 pipeline[plPtrExec].operand1
3514 #define PIMM2 pipeline[plPtrExec].operand2
3515 #define PRES pipeline[plPtrExec].result
3516 #define PWBR pipeline[plPtrExec].writebackRegister
3517 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3518 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3519 #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))
3520 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3522 static void DSP_abs(void)
3526 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);
3530 if (_Rn == 0x80000000)
3534 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3535 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3536 CLR_ZN; SET_Z(PRES);
3540 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3544 static void DSP_add(void)
3548 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);
3550 uint32_t res = PRN + PRM;
3551 SET_ZNC_ADD(PRN, PRM, res);
3555 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);
3559 static void DSP_addc(void)
3563 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);
3565 uint32_t res = PRN + PRM + dsp_flag_c;
3566 uint32_t carry = dsp_flag_c;
3567 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3568 SET_ZNC_ADD(PRN + carry, PRM, res);
3569 // SET_ZNC_ADD(PRN, PRM + carry, res);
3573 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);
3577 static void DSP_addq(void)
3581 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);
3583 uint32_t r1 = dsp_convert_zero[PIMM1];
3584 uint32_t res = PRN + r1;
3585 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3589 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3593 static void DSP_addqmod(void)
3595 #ifdef DSP_DIS_ADDQMOD
3597 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);
3599 uint32_t r1 = dsp_convert_zero[PIMM1];
3601 uint32_t res = r2 + r1;
3602 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3604 SET_ZNC_ADD(r2, r1, res);
3605 #ifdef DSP_DIS_ADDQMOD
3607 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3611 static void DSP_addqt(void)
3613 #ifdef DSP_DIS_ADDQT
3615 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);
3617 PRES = PRN + dsp_convert_zero[PIMM1];
3618 #ifdef DSP_DIS_ADDQT
3620 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3624 static void DSP_and(void)
3628 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);
3634 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);
3638 static void DSP_bclr(void)
3642 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);
3644 PRES = PRN & ~(1 << PIMM1);
3648 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3652 static void DSP_bset(void)
3656 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);
3658 PRES = PRN | (1 << PIMM1);
3662 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3666 static void DSP_btst(void)
3670 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);
3672 dsp_flag_z = (~PRN >> PIMM1) & 1;
3676 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3680 static void DSP_cmp(void)
3684 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);
3686 uint32_t res = PRN - PRM;
3687 SET_ZNC_SUB(PRN, PRM, res);
3691 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3695 static void DSP_cmpq(void)
3697 static int32_t sqtable[32] =
3698 { 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 };
3701 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);
3703 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3704 uint32_t res = PRN - r1;
3705 SET_ZNC_SUB(PRN, r1, res);
3709 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3713 static void DSP_div(void)
3715 uint32_t _Rm = PRM, _Rn = PRN;
3719 if (dsp_div_control & 1)
3721 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3722 if (dsp_remain & 0x80000000)
3724 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3728 dsp_remain = _Rn % _Rm;
3729 if (dsp_remain & 0x80000000)
3738 static void DSP_imacn(void)
3740 #ifdef DSP_DIS_IMACN
3742 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);
3744 int32_t res = (int16_t)PRM * (int16_t)PRN;
3745 dsp_acc += (int64_t)res;
3746 //Should we AND the result to fit into 40 bits here???
3748 #ifdef DSP_DIS_IMACN
3750 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
3754 static void DSP_imult(void)
3756 #ifdef DSP_DIS_IMULT
3758 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);
3760 PRES = (int16_t)PRN * (int16_t)PRM;
3762 #ifdef DSP_DIS_IMULT
3764 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);
3768 static void DSP_imultn(void)
3770 #ifdef DSP_DIS_IMULTN
3772 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);
3774 // This is OK, since this multiply won't overflow 32 bits...
3775 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3776 dsp_acc = (int64_t)res;
3779 #ifdef DSP_DIS_IMULTN
3781 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
3785 static void DSP_illegal(void)
3787 #ifdef DSP_DIS_ILLEGAL
3789 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3794 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3795 // can cause trouble because an interrupt can occur *before* the instruction following the
3796 // jump can execute... !!! FIX !!!
3797 // This can probably be solved by judicious coding in the pipeline execution core...
3798 // And should be fixed now...
3799 static void DSP_jr(void)
3802 const char * condition[32] =
3803 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3804 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3805 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3806 "???", "???", "???", "F" };
3808 //How come this is always off by 2???
3809 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);
3811 // KLUDGE: Used by BRANCH_CONDITION macro
3812 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3814 if (BRANCH_CONDITION(PIMM2))
3818 WriteLog("Branched!\n");
3820 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3821 //Account for pipeline effects...
3822 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3823 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3825 // Now that we've branched, we have to make sure that the following instruction
3826 // is executed atomically with this one and then flush the pipeline before setting
3829 // Step 1: Handle writebacks at stage 3 of pipeline
3830 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3832 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3833 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3835 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3836 scoreboard[pipeline[plPtrWrite].operand2] = false;
3838 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3840 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3842 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3843 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3846 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3847 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3848 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3849 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3851 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3855 #ifndef NEW_SCOREBOARD
3856 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3857 scoreboard[pipeline[plPtrWrite].operand2] = false;
3859 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3860 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3861 if (scoreboard[pipeline[plPtrWrite].operand2])
3862 scoreboard[pipeline[plPtrWrite].operand2]--;
3866 // Step 2: Push instruction through pipeline & execute following instruction
3867 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3868 // we effectively handle the final push of the instruction through the
3869 // pipeline when the new PC takes effect (since when we return, the
3870 // pipeline code will be executing the writeback stage. If we reverse
3871 // the execution order of the pipeline stages, this will no longer be
3873 pipeline[plPtrExec] = pipeline[plPtrRead];
3874 //This is BAD. We need to get that next opcode and execute it!
3875 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3876 // remove this crap.
3877 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3879 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3880 pipeline[plPtrExec].opcode = instruction >> 10;
3881 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3882 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3883 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3884 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3885 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3887 dsp_pc += 2; // For DSP_DIS_* accuracy
3888 DSPOpcode[pipeline[plPtrExec].opcode]();
3889 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3890 pipeline[plPtrWrite] = pipeline[plPtrExec];
3892 // Step 3: Flush pipeline & set new PC
3893 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3900 WriteLog("Branch NOT taken.\n");
3906 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3909 static void DSP_jump(void)
3912 const char * condition[32] =
3913 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3914 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3915 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3916 "???", "???", "???", "F" };
3918 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);
3920 // KLUDGE: Used by BRANCH_CONDITION macro
3921 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3923 if (BRANCH_CONDITION(PIMM2))
3927 WriteLog("Branched!\n");
3929 uint32_t PCSave = PRM;
3930 // Now that we've branched, we have to make sure that the following instruction
3931 // is executed atomically with this one and then flush the pipeline before setting
3934 // Step 1: Handle writebacks at stage 3 of pipeline
3935 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3937 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3938 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3940 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3941 scoreboard[pipeline[plPtrWrite].operand2] = false;
3943 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3945 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3947 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3948 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3951 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3952 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3953 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3954 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3956 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3960 #ifndef NEW_SCOREBOARD
3961 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3962 scoreboard[pipeline[plPtrWrite].operand2] = false;
3964 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3965 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3966 if (scoreboard[pipeline[plPtrWrite].operand2])
3967 scoreboard[pipeline[plPtrWrite].operand2]--;
3971 // Step 2: Push instruction through pipeline & execute following instruction
3972 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3973 // we effectively handle the final push of the instruction through the
3974 // pipeline when the new PC takes effect (since when we return, the
3975 // pipeline code will be executing the writeback stage. If we reverse
3976 // the execution order of the pipeline stages, this will no longer be
3978 pipeline[plPtrExec] = pipeline[plPtrRead];
3979 //This is BAD. We need to get that next opcode and execute it!
3980 //Also, same problem in JR!
3981 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3982 // remove this crap.
3983 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3985 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3986 pipeline[plPtrExec].opcode = instruction >> 10;
3987 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3988 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3989 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3990 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3991 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3993 dsp_pc += 2; // For DSP_DIS_* accuracy
3994 DSPOpcode[pipeline[plPtrExec].opcode]();
3995 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3996 pipeline[plPtrWrite] = pipeline[plPtrExec];
3998 // Step 3: Flush pipeline & set new PC
3999 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4006 WriteLog("Branch NOT taken.\n");
4014 static void DSP_load(void)
4018 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);
4020 #ifdef DSP_CORRECT_ALIGNMENT
4021 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4023 PRES = DSPReadLong(PRM, DSP);
4027 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4031 static void DSP_loadb(void)
4033 #ifdef DSP_DIS_LOADB
4035 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);
4037 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4038 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4040 PRES = JaguarReadByte(PRM, DSP);
4041 #ifdef DSP_DIS_LOADB
4043 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4047 static void DSP_loadw(void)
4049 #ifdef DSP_DIS_LOADW
4051 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);
4053 #ifdef DSP_CORRECT_ALIGNMENT
4054 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4055 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4057 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4059 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4060 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4062 PRES = JaguarReadWord(PRM, DSP);
4064 #ifdef DSP_DIS_LOADW
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_load_r14_i(void)
4072 #ifdef DSP_DIS_LOAD14I
4074 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);
4076 #ifdef DSP_CORRECT_ALIGNMENT
4077 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4079 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4081 #ifdef DSP_DIS_LOAD14I
4083 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4087 static void DSP_load_r14_r(void)
4089 #ifdef DSP_DIS_LOAD14R
4091 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);
4093 #ifdef DSP_CORRECT_ALIGNMENT
4094 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4096 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4098 #ifdef DSP_DIS_LOAD14R
4100 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4104 static void DSP_load_r15_i(void)
4106 #ifdef DSP_DIS_LOAD15I
4108 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);
4110 #ifdef DSP_CORRECT_ALIGNMENT
4111 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4113 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4115 #ifdef DSP_DIS_LOAD15I
4117 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4121 static void DSP_load_r15_r(void)
4123 #ifdef DSP_DIS_LOAD15R
4125 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);
4127 #ifdef DSP_CORRECT_ALIGNMENT
4128 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4130 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4132 #ifdef DSP_DIS_LOAD15R
4134 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4138 static void DSP_mirror(void)
4141 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4145 static void DSP_mmult(void)
4147 int count = dsp_matrix_control&0x0f;
4148 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4152 if (!(dsp_matrix_control & 0x10))
4154 for (int i = 0; i < count; i++)
4158 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4160 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4161 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4168 for (int i = 0; i < count; i++)
4172 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4174 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4175 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4181 PRES = res = (int32_t)accum;
4183 //NOTE: The flags are set based upon the last add/multiply done...
4187 static void DSP_move(void)
4191 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);
4196 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);
4200 static void DSP_movefa(void)
4202 #ifdef DSP_DIS_MOVEFA
4204 // 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);
4205 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);
4207 // PRES = ALTERNATE_RM;
4208 PRES = dsp_alternate_reg[PIMM1];
4209 #ifdef DSP_DIS_MOVEFA
4211 // 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);
4212 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);
4216 static void DSP_movei(void)
4218 #ifdef DSP_DIS_MOVEI
4220 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);
4222 // // This instruction is followed by 32-bit value in LSW / MSW format...
4223 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4225 #ifdef DSP_DIS_MOVEI
4227 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4231 static void DSP_movepc(void)
4233 #ifdef DSP_DIS_MOVEPC
4235 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);
4237 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4238 // PRES = dsp_pc - 2;
4239 //Account for pipeline effects...
4240 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4241 #ifdef DSP_DIS_MOVEPC
4243 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4247 static void DSP_moveq(void)
4249 #ifdef DSP_DIS_MOVEQ
4251 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);
4254 #ifdef DSP_DIS_MOVEQ
4256 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4260 static void DSP_moveta(void)
4262 #ifdef DSP_DIS_MOVETA
4264 // 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);
4265 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]);
4267 // ALTERNATE_RN = PRM;
4268 dsp_alternate_reg[PIMM2] = PRM;
4270 #ifdef DSP_DIS_MOVETA
4272 // 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);
4273 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]);
4277 static void DSP_mtoi(void)
4279 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4283 static void DSP_mult(void)
4287 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);
4289 PRES = (uint16_t)PRM * (uint16_t)PRN;
4293 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);
4297 static void DSP_neg(void)
4301 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);
4303 uint32_t res = -PRN;
4304 SET_ZNC_SUB(0, PRN, res);
4308 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4312 static void DSP_nop(void)
4316 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4321 static void DSP_normi(void)
4328 while ((_Rm & 0xffc00000) == 0)
4333 while ((_Rm & 0xff800000) != 0)
4343 static void DSP_not(void)
4347 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);
4353 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4357 static void DSP_or(void)
4361 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);
4367 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);
4371 static void DSP_resmac(void)
4373 #ifdef DSP_DIS_RESMAC
4375 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_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
4377 PRES = (uint32_t)dsp_acc;
4378 #ifdef DSP_DIS_RESMAC
4380 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4384 static void DSP_ror(void)
4388 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);
4390 uint32_t r1 = PRM & 0x1F;
4391 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4392 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4396 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);
4400 static void DSP_rorq(void)
4404 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);
4406 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4408 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4410 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4413 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4417 static void DSP_sat16s(void)
4420 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4425 static void DSP_sat32s(void)
4427 int32_t r2 = (uint32_t)PRN;
4428 int32_t temp = dsp_acc >> 32;
4429 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4434 static void DSP_sh(void)
4436 int32_t sRm = (int32_t)PRM;
4441 uint32_t shift = -sRm;
4446 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4456 uint32_t shift = sRm;
4461 dsp_flag_c = _Rn & 0x1;
4474 static void DSP_sha(void)
4476 int32_t sRm = (int32_t)PRM;
4481 uint32_t shift = -sRm;
4486 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4496 uint32_t shift = sRm;
4501 dsp_flag_c = _Rn & 0x1;
4505 _Rn = ((int32_t)_Rn) >> 1;
4514 static void DSP_sharq(void)
4516 #ifdef DSP_DIS_SHARQ
4518 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);
4520 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4521 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4523 #ifdef DSP_DIS_SHARQ
4525 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4529 static void DSP_shlq(void)
4533 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);
4535 int32_t r1 = 32 - PIMM1;
4536 uint32_t res = PRN << r1;
4537 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4541 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4545 static void DSP_shrq(void)
4549 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);
4551 int32_t r1 = dsp_convert_zero[PIMM1];
4552 uint32_t res = PRN >> r1;
4553 SET_ZN(res); dsp_flag_c = PRN & 1;
4557 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4561 static void DSP_store(void)
4563 #ifdef DSP_DIS_STORE
4565 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);
4567 // DSPWriteLong(PRM, PRN, DSP);
4569 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4570 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4572 pipeline[plPtrExec].address = PRM;
4574 pipeline[plPtrExec].value = PRN;
4575 pipeline[plPtrExec].type = TYPE_DWORD;
4579 static void DSP_storeb(void)
4581 #ifdef DSP_DIS_STOREB
4583 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);
4585 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4586 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4588 // JaguarWriteByte(PRM, PRN, DSP);
4591 pipeline[plPtrExec].address = PRM;
4593 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4595 pipeline[plPtrExec].value = PRN & 0xFF;
4596 pipeline[plPtrExec].type = TYPE_DWORD;
4600 pipeline[plPtrExec].value = PRN;
4601 pipeline[plPtrExec].type = TYPE_BYTE;
4607 static void DSP_storew(void)
4609 #ifdef DSP_DIS_STOREW
4611 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);
4613 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4614 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4616 // JaguarWriteWord(PRM, PRN, DSP);
4619 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4620 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4622 pipeline[plPtrExec].address = PRM;
4625 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4627 pipeline[plPtrExec].value = PRN & 0xFFFF;
4628 pipeline[plPtrExec].type = TYPE_DWORD;
4632 pipeline[plPtrExec].value = PRN;
4633 pipeline[plPtrExec].type = TYPE_WORD;
4638 static void DSP_store_r14_i(void)
4640 #ifdef DSP_DIS_STORE14I
4642 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));
4644 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4646 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4647 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4649 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4651 pipeline[plPtrExec].value = PRN;
4652 pipeline[plPtrExec].type = TYPE_DWORD;
4656 static void DSP_store_r14_r(void)
4658 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4660 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4661 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4663 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4665 pipeline[plPtrExec].value = PRN;
4666 pipeline[plPtrExec].type = TYPE_DWORD;
4670 static void DSP_store_r15_i(void)
4672 #ifdef DSP_DIS_STORE15I
4674 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));
4676 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4678 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4679 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4681 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4683 pipeline[plPtrExec].value = PRN;
4684 pipeline[plPtrExec].type = TYPE_DWORD;
4688 static void DSP_store_r15_r(void)
4690 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4692 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4693 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4695 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4697 pipeline[plPtrExec].value = PRN;
4698 pipeline[plPtrExec].type = TYPE_DWORD;
4702 static void DSP_sub(void)
4706 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);
4708 uint32_t res = PRN - PRM;
4709 SET_ZNC_SUB(PRN, PRM, res);
4713 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);
4717 static void DSP_subc(void)
4721 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);
4723 uint32_t res = PRN - PRM - dsp_flag_c;
4724 uint32_t borrow = dsp_flag_c;
4725 SET_ZNC_SUB(PRN - borrow, PRM, res);
4729 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);
4733 static void DSP_subq(void)
4737 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);
4739 uint32_t r1 = dsp_convert_zero[PIMM1];
4740 uint32_t res = PRN - r1;
4741 SET_ZNC_SUB(PRN, r1, res);
4745 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4749 static void DSP_subqmod(void)
4751 uint32_t r1 = dsp_convert_zero[PIMM1];
4753 uint32_t res = r2 - r1;
4754 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4756 SET_ZNC_SUB(r2, r1, res);
4759 static void DSP_subqt(void)
4761 #ifdef DSP_DIS_SUBQT
4763 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);
4765 PRES = PRN - dsp_convert_zero[PIMM1];
4766 #ifdef DSP_DIS_SUBQT
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_xor(void)
4776 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);
4782 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);