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...
27 #include "m68000/m68kinterface.h"
31 // Seems alignment in loads & stores was off...
32 #define DSP_CORRECT_ALIGNMENT
33 //#define DSP_CORRECT_ALIGNMENT_STORE
36 //#define DSP_DEBUG_IRQ
37 //#define DSP_DEBUG_PL2
38 //#define DSP_DEBUG_STALL
39 //#define DSP_DEBUG_CC
40 #define NEW_SCOREBOARD
42 // Disassembly definitions
49 #define DSP_DIS_ADDQMOD
59 #define DSP_DIS_IMULTN
60 #define DSP_DIS_ILLEGAL
64 #define DSP_DIS_LOAD14I
65 #define DSP_DIS_LOAD14R
66 #define DSP_DIS_LOAD15I
67 #define DSP_DIS_LOAD15R
73 #define DSP_DIS_MOVEFA
74 #define DSP_DIS_MOVEPC // Pipeline only!
75 #define DSP_DIS_MOVETA
81 #define DSP_DIS_RESMAC
88 #define DSP_DIS_STORE14I
89 #define DSP_DIS_STORE15I
90 #define DSP_DIS_STOREB
91 #define DSP_DIS_STOREW
98 bool doDSPDis = false;
99 //bool doDSPDis = true;
101 bool doDSPDis = false;
103 //#define DSP_DIS_JUMP
137 + load_r15_indexed 284500
139 + store_r15_indexed 47416
143 + load_r14_ri 1229448
146 // Pipeline structures
148 const bool affectsScoreboard[64] =
150 true, true, true, true,
151 true, true, true, true,
152 true, true, true, true,
153 true, false, true, true,
155 true, true, false, true,
156 false, true, true, true,
157 true, true, true, true,
158 true, true, false, false,
160 true, true, true, true,
161 false, true, true, true,
162 true, true, true, true,
163 true, false, false, false,
165 true, false, false, true,
166 false, false, true, true,
167 true, false, true, true,
168 false, false, false, true
173 uint16_t instruction;
174 uint8_t opcode, operand1, operand2;
175 uint32_t reg1, reg2, areg1, areg2;
177 uint8_t writebackRegister;
178 // General memory store...
187 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
188 #ifndef NEW_SCOREBOARD
191 uint8_t scoreboard[32];
193 uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
194 PipelineStage pipeline[4];
195 bool IMASKCleared = false;
197 // DSP flags (old--have to get rid of this crap)
199 #define CINT0FLAG 0x00200
200 #define CINT1FLAG 0x00400
201 #define CINT2FLAG 0x00800
202 #define CINT3FLAG 0x01000
203 #define CINT4FLAG 0x02000
204 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
205 #define CINT5FLAG 0x20000 /* DSP only */
209 #define ZERO_FLAG 0x00001
210 #define CARRY_FLAG 0x00002
211 #define NEGA_FLAG 0x00004
212 #define IMASK 0x00008
213 #define INT_ENA0 0x00010
214 #define INT_ENA1 0x00020
215 #define INT_ENA2 0x00040
216 #define INT_ENA3 0x00080
217 #define INT_ENA4 0x00100
218 #define INT_CLR0 0x00200
219 #define INT_CLR1 0x00400
220 #define INT_CLR2 0x00800
221 #define INT_CLR3 0x01000
222 #define INT_CLR4 0x02000
223 #define REGPAGE 0x04000
224 #define DMAEN 0x08000
225 #define INT_ENA5 0x10000
226 #define INT_CLR5 0x20000
230 #define DSPGO 0x00001
231 #define CPUINT 0x00002
232 #define DSPINT0 0x00004
233 #define SINGLE_STEP 0x00008
234 #define SINGLE_GO 0x00010
236 #define INT_LAT0 0x00040
237 #define INT_LAT1 0x00080
238 #define INT_LAT2 0x00100
239 #define INT_LAT3 0x00200
240 #define INT_LAT4 0x00400
241 #define BUS_HOG 0x00800
242 #define VERSION 0x0F000
243 #define INT_LAT5 0x10000
245 extern uint32_t jaguar_mainRom_crc32;
247 // Is opcode 62 *really* a NOP? Seems like it...
248 static void dsp_opcode_abs(void);
249 static void dsp_opcode_add(void);
250 static void dsp_opcode_addc(void);
251 static void dsp_opcode_addq(void);
252 static void dsp_opcode_addqmod(void);
253 static void dsp_opcode_addqt(void);
254 static void dsp_opcode_and(void);
255 static void dsp_opcode_bclr(void);
256 static void dsp_opcode_bset(void);
257 static void dsp_opcode_btst(void);
258 static void dsp_opcode_cmp(void);
259 static void dsp_opcode_cmpq(void);
260 static void dsp_opcode_div(void);
261 static void dsp_opcode_imacn(void);
262 static void dsp_opcode_imult(void);
263 static void dsp_opcode_imultn(void);
264 static void dsp_opcode_jr(void);
265 static void dsp_opcode_jump(void);
266 static void dsp_opcode_load(void);
267 static void dsp_opcode_loadb(void);
268 static void dsp_opcode_loadw(void);
269 static void dsp_opcode_load_r14_indexed(void);
270 static void dsp_opcode_load_r14_ri(void);
271 static void dsp_opcode_load_r15_indexed(void);
272 static void dsp_opcode_load_r15_ri(void);
273 static void dsp_opcode_mirror(void);
274 static void dsp_opcode_mmult(void);
275 static void dsp_opcode_move(void);
276 static void dsp_opcode_movei(void);
277 static void dsp_opcode_movefa(void);
278 static void dsp_opcode_move_pc(void);
279 static void dsp_opcode_moveq(void);
280 static void dsp_opcode_moveta(void);
281 static void dsp_opcode_mtoi(void);
282 static void dsp_opcode_mult(void);
283 static void dsp_opcode_neg(void);
284 static void dsp_opcode_nop(void);
285 static void dsp_opcode_normi(void);
286 static void dsp_opcode_not(void);
287 static void dsp_opcode_or(void);
288 static void dsp_opcode_resmac(void);
289 static void dsp_opcode_ror(void);
290 static void dsp_opcode_rorq(void);
291 static void dsp_opcode_xor(void);
292 static void dsp_opcode_sat16s(void);
293 static void dsp_opcode_sat32s(void);
294 static void dsp_opcode_sh(void);
295 static void dsp_opcode_sha(void);
296 static void dsp_opcode_sharq(void);
297 static void dsp_opcode_shlq(void);
298 static void dsp_opcode_shrq(void);
299 static void dsp_opcode_store(void);
300 static void dsp_opcode_storeb(void);
301 static void dsp_opcode_storew(void);
302 static void dsp_opcode_store_r14_indexed(void);
303 static void dsp_opcode_store_r14_ri(void);
304 static void dsp_opcode_store_r15_indexed(void);
305 static void dsp_opcode_store_r15_ri(void);
306 static void dsp_opcode_sub(void);
307 static void dsp_opcode_subc(void);
308 static void dsp_opcode_subq(void);
309 static void dsp_opcode_subqmod(void);
310 static void dsp_opcode_subqt(void);
311 static void dsp_opcode_illegal(void);
313 /*uint8_t dsp_opcode_cycles[64] =
315 3, 3, 3, 3, 3, 3, 3, 3,
316 3, 3, 3, 3, 3, 3, 3, 3,
317 3, 3, 1, 3, 1, 18, 3, 3,
318 3, 3, 3, 3, 3, 3, 3, 3,
319 3, 3, 2, 2, 2, 2, 3, 4,
320 5, 4, 5, 6, 6, 1, 1, 1,
321 1, 2, 2, 2, 1, 1, 9, 3,
322 3, 1, 6, 6, 2, 2, 3, 3
324 //Here's a QnD kludge...
325 //This is wrong, wrong, WRONG, but it seems to work for the time being...
326 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
327 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
328 // Yup, without cheating like this, the sound in things like Rayman, FACTS, &
329 // Tripper Getem get starved for time and sounds like crap. So we have to figure
330 // out how to fix that. :-/
331 uint8_t dsp_opcode_cycles[64] =
333 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 9, 1, 1,
336 1, 1, 1, 1, 1, 1, 1, 1,
337 1, 1, 1, 1, 1, 1, 1, 2,
338 2, 2, 2, 3, 3, 1, 1, 1,
339 1, 1, 1, 1, 1, 1, 4, 1,
340 1, 1, 3, 3, 1, 1, 1, 1
343 void (* dsp_opcode[64])() =
345 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
346 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
347 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
348 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
349 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
350 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
351 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
352 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
353 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
354 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
355 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
356 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
357 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
358 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
359 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
360 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod,
363 uint32_t dsp_opcode_use[65];
365 const char * dsp_opcode_str[65]=
367 "add", "addc", "addq", "addqt",
368 "sub", "subc", "subq", "subqt",
369 "neg", "and", "or", "xor",
370 "not", "btst", "bset", "bclr",
371 "mult", "imult", "imultn", "resmac",
372 "imacn", "div", "abs", "sh",
373 "shlq", "shrq", "sha", "sharq",
374 "ror", "rorq", "cmp", "cmpq",
375 "subqmod", "sat16s", "move", "moveq",
376 "moveta", "movefa", "movei", "loadb",
377 "loadw", "load", "sat32s", "load_r14_indexed",
378 "load_r15_indexed", "storeb", "storew", "store",
379 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
380 "jump", "jr", "mmult", "mtoi",
381 "normi", "nop", "load_r14_ri", "load_r15_ri",
382 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
387 static uint64_t dsp_acc; // 40 bit register, NOT 32!
388 static uint32_t dsp_remain;
389 static uint32_t dsp_modulo;
390 static uint32_t dsp_flags;
391 static uint32_t dsp_matrix_control;
392 static uint32_t dsp_pointer_to_matrix;
393 static uint32_t dsp_data_organization;
394 uint32_t dsp_control;
395 static uint32_t dsp_div_control;
396 static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
397 static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
398 uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
400 static uint32_t dsp_opcode_first_parameter;
401 static uint32_t dsp_opcode_second_parameter;
403 #define DSP_RUNNING (dsp_control & 0x01)
405 #define RM dsp_reg[dsp_opcode_first_parameter]
406 #define RN dsp_reg[dsp_opcode_second_parameter]
407 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
408 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
409 #define IMM_1 dsp_opcode_first_parameter
410 #define IMM_2 dsp_opcode_second_parameter
412 #define CLR_Z (dsp_flag_z = 0)
413 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
414 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
415 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
416 #define SET_N(r) (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
417 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
418 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
419 #define SET_ZN(r) SET_N(r); SET_Z(r)
420 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
421 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
423 uint32_t dsp_convert_zero[32] = {
424 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
425 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
428 uint8_t dsp_branch_condition_table[32 * 8];
429 static uint16_t mirror_table[65536];
430 static uint8_t dsp_ram_8[0x2000];
432 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
434 static uint32_t dsp_in_exec = 0;
435 static uint32_t dsp_releaseTimeSlice_flag = 0;
440 // Comparison core vars (used only for core comparison! :-)
441 static uint64_t count = 0;
442 static uint8_t ram1[0x2000], ram2[0x2000];
443 static uint32_t regs1[64], regs2[64];
444 static uint32_t ctrl1[14], ctrl2[14];
447 // Private function prototypes
449 void DSPDumpRegisters(void);
450 void DSPDumpDisassembly(void);
451 void FlushDSPPipeline(void);
454 void dsp_reset_stats(void)
456 for(int i=0; i<65; i++)
457 dsp_opcode_use[i] = 0;
460 void DSPReleaseTimeslice(void)
462 //This does absolutely nothing!!! !!! FIX !!!
463 dsp_releaseTimeSlice_flag = 1;
466 void dsp_build_branch_condition_table(void)
468 // Fill in the mirror table
469 for(int i=0; i<65536; i++)
471 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
472 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
473 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
474 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
475 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
476 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
477 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
478 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
481 // Fill in the condition table
482 for(int i=0; i<8; i++)
484 for(int j=0; j<32; j++)
488 if ((j & 1) && (i & ZERO_FLAG))
491 if ((j & 2) && (!(i & ZERO_FLAG)))
494 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
497 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
500 dsp_branch_condition_table[i * 32 + j] = result;
505 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
507 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
508 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
510 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
513 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
515 if (offset==0xF1CFE0)
518 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
519 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
521 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
523 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
525 if ((offset&0x03)==0)
528 if ((offset&0x03)==1)
529 return((data>>16)&0xff);
531 if ((offset&0x03)==2)
532 return((data>>8)&0xff);
534 if ((offset&0x03)==3)
538 return JaguarReadByte(offset, who);
541 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
543 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
544 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
546 offset &= 0xFFFFFFFE;
548 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
550 offset -= DSP_WORK_RAM_BASE;
551 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
553 return GET16(dsp_ram_8, offset);
555 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
557 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
560 return data & 0xFFFF;
565 return JaguarReadWord(offset, who);
568 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
570 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
571 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
574 offset &= 0xFFFFFFFC;
575 /*if (offset == 0xF1BCF4)
577 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));
578 DSPDumpDisassembly();
580 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
582 offset -= DSP_WORK_RAM_BASE;
583 return GET32(dsp_ram_8, offset);
585 //NOTE: Didn't return DSP_ACCUM!!!
586 //Mebbe it's not 'spose to! Yes, it is!
587 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
593 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
594 return dsp_flags & 0xFFFFC1FF;
595 case 0x04: return dsp_matrix_control;
596 case 0x08: return dsp_pointer_to_matrix;
597 case 0x0C: return dsp_data_organization;
598 case 0x10: return dsp_pc;
599 case 0x14: return dsp_control;
600 case 0x18: return dsp_modulo;
601 case 0x1C: return dsp_remain;
603 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
605 // unaligned long read-- !!! FIX !!!
609 return JaguarReadLong(offset, who);
612 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
614 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
615 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
617 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
619 offset -= DSP_WORK_RAM_BASE;
620 dsp_ram_8[offset] = data;
621 //This is rather stupid! !!! FIX !!!
622 /* if (dsp_in_exec == 0)
624 m68k_end_timeslice();
625 dsp_releaseTimeslice();
629 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
631 uint32_t reg = offset & 0x1C;
632 int bytenum = offset & 0x03;
634 if ((reg >= 0x1C) && (reg <= 0x1F))
635 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
638 //This looks funky. !!! FIX !!!
639 uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
640 bytenum = 3 - bytenum; // convention motorola !!!
641 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
642 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
646 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
647 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
648 JaguarWriteByte(offset, data, who);
651 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
653 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
654 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
655 offset &= 0xFFFFFFFE;
656 /*if (offset == 0xF1BCF4)
658 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
660 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
661 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
663 /*if (offset == 0xF1B2F4)
665 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
667 offset -= DSP_WORK_RAM_BASE;
668 dsp_ram_8[offset] = data >> 8;
669 dsp_ram_8[offset+1] = data & 0xFF;
670 //This is rather stupid! !!! FIX !!!
671 /* if (dsp_in_exec == 0)
673 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
674 m68k_end_timeslice();
675 dsp_releaseTimeslice();
679 SET16(ram1, offset, data),
680 SET16(ram2, offset, data);
685 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
687 if ((offset & 0x1C) == 0x1C)
690 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
692 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
696 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
699 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
701 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
703 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
709 JaguarWriteWord(offset, data, who);
712 //bool badWrite = false;
713 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
715 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
716 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
718 offset &= 0xFFFFFFFC;
719 /*if (offset == 0xF1BCF4)
721 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
723 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
724 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
726 /*if (offset == 0xF1BE2C)
728 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
730 offset -= DSP_WORK_RAM_BASE;
731 SET32(dsp_ram_8, offset, data);
734 SET32(ram1, offset, data),
735 SET32(ram2, offset, data);
740 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
748 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
750 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
751 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
752 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
753 // IRQ logic can set it. So we mask it out here to prevent problems...
754 dsp_flags = data & (~IMASK);
755 dsp_flag_z = dsp_flags & 0x01;
756 dsp_flag_c = (dsp_flags >> 1) & 0x01;
757 dsp_flag_n = (dsp_flags >> 2) & 0x01;
758 DSPUpdateRegisterBanks();
759 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
760 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
764 dsp_matrix_control = data;
767 // According to JTRM, only lines 2-11 are addressable, the rest being
768 // hardwired to $F1Bxxx.
769 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
772 dsp_data_organization = data;
777 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
782 ctrl1[0] = ctrl2[0] = data;
789 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
791 bool wasRunning = DSP_RUNNING;
792 // uint32_t dsp_was_running = DSP_RUNNING;
793 // Check for DSP -> CPU interrupt
797 WriteLog("DSP: DSP -> CPU interrupt\n");
800 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
801 if (JERRYIRQEnabled(IRQ2_DSP))
803 JERRYSetPendingIRQ(IRQ2_DSP);
804 DSPReleaseTimeslice();
805 m68k_set_irq(2); // Set 68000 IPL 2...
809 // Check for CPU -> DSP interrupt
813 WriteLog("DSP: CPU -> DSP interrupt\n");
815 m68k_end_timeslice();
816 DSPReleaseTimeslice();
817 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
821 if (data & SINGLE_STEP)
823 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
826 // Protect writes to VERSION and the interrupt latches...
827 uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
828 dsp_control = (dsp_control & mask) | (data & ~mask);
832 ctrl1[8] = ctrl2[8] = dsp_control;
836 // if dsp wasn't running but is now running
837 // execute a few cycles
838 //This is just plain wrong, wrong, WRONG!
839 #ifndef DSP_SINGLE_STEPPING
840 /* if (!dsp_was_running && DSP_RUNNING)
845 //This is WRONG! !!! FIX !!!
846 if (dsp_control & 0x18)
851 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
853 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
856 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
857 // !!! FIX !!! [DONE]
861 m68k_end_timeslice();
863 DSPReleaseTimeslice();
867 //DSPDumpDisassembly();
872 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
876 dsp_div_control = data;
878 // default: // unaligned long read
884 //We don't have to break this up like this! We CAN do 32 bit writes!
885 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
886 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
887 //if (offset > 0xF1FFFF)
889 JaguarWriteLong(offset, data, who);
893 // Update the DSP register file pointers depending on REGPAGE bit
895 void DSPUpdateRegisterBanks(void)
897 int bank = (dsp_flags & REGPAGE);
899 if (dsp_flags & IMASK)
900 bank = 0; // IMASK forces main bank to be bank 0
903 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
905 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
908 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
913 // Check for and handle any asserted DSP IRQs
915 void DSPHandleIRQs(void)
917 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
920 // Get the active interrupt bits (latches) & interrupt mask (enables)
921 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
922 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
924 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
927 if (!bits) // Bail if nothing is enabled
930 int which = 0; // Determine which interrupt
946 WriteLog("DSP: Generating interrupt #%i...", which);
949 //if (which == 0) doDSPDis = true;
951 // NOTE: Since the actual Jaguar hardware injects the code sequence below
952 // directly into the pipeline, it has the side effect of ensuring that the
953 // instruction interrupted also gets to do its writeback. We simulate that
955 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
957 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
958 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
960 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
961 scoreboard[pipeline[plPtrWrite].operand2] = false;
963 //This should be execute (or should it?--not sure now!)
964 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
965 //and what just executed is now in the Write position...). So why didn't it do the
966 //writeback into register 0?
968 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
969 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]);
970 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]);
971 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]);
973 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
975 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
977 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
978 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
981 if (pipeline[plPtrWrite].type == TYPE_BYTE)
982 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
983 else if (pipeline[plPtrWrite].type == TYPE_WORD)
984 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
986 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
990 #ifndef NEW_SCOREBOARD
991 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
992 scoreboard[pipeline[plPtrWrite].operand2] = false;
994 //Yup, sequential MOVEQ # problem fixing (I hope!)...
995 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
996 if (scoreboard[pipeline[plPtrWrite].operand2])
997 scoreboard[pipeline[plPtrWrite].operand2]--;
1004 ctrl2[4] = dsp_flags;
1007 DSPUpdateRegisterBanks();
1008 #ifdef DSP_DEBUG_IRQ
1009 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1010 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]);
1013 // subqt #4,r31 ; pre-decrement stack pointer
1014 // move pc,r30 ; address of interrupted code
1015 // store r30,(r31) ; store return address
1022 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1023 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1024 //It missed the place that it was supposed to come back to, so this is WRONG!
1026 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1028 // R -> baz (<- PC points here)
1029 // E -> bar (when it should point here!)
1032 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1033 // which means (assuming they're all 2 bytes long) that the code below will come back on
1034 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1035 // instruction stream...
1037 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1038 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1041 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1045 // movei #service_address,r30 ; pointer to ISR entry
1046 // jump (r30) ; jump to ISR
1048 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1051 ctrl2[0] = regs2[30] = dsp_pc;
1058 // Non-pipelined version...
1060 void DSPHandleIRQsNP(void)
1064 memcpy(dsp_ram_8, ram1, 0x2000);
1065 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1066 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1069 dsp_remain = ctrl1[2];
1070 dsp_modulo = ctrl1[3];
1071 dsp_flags = ctrl1[4];
1072 dsp_matrix_control = ctrl1[5];
1073 dsp_pointer_to_matrix = ctrl1[6];
1074 dsp_data_organization = ctrl1[7];
1075 dsp_control = ctrl1[8];
1076 dsp_div_control = ctrl1[9];
1077 IMASKCleared = ctrl1[10];
1078 dsp_flag_z = ctrl1[11];
1079 dsp_flag_n = ctrl1[12];
1080 dsp_flag_c = ctrl1[13];
1081 DSPUpdateRegisterBanks();
1084 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1087 // Get the active interrupt bits (latches) & interrupt mask (enables)
1088 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1089 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1091 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1094 if (!bits) // Bail if nothing is enabled
1097 int which = 0; // Determine which interrupt
1111 dsp_flags |= IMASK; // Force Bank #0
1114 ctrl1[4] = dsp_flags;
1117 #ifdef DSP_DEBUG_IRQ
1118 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1119 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1121 DSPUpdateRegisterBanks();
1122 #ifdef DSP_DEBUG_IRQ
1123 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1124 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1127 #ifdef DSP_DEBUG_IRQ
1128 WriteLog("DSP: Generating interrupt #%i...", which);
1129 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1132 // subqt #4,r31 ; pre-decrement stack pointer
1133 // move pc,r30 ; address of interrupted code
1134 // store r30,(r31) ; store return address
1136 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1143 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1144 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1147 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1151 // movei #service_address,r30 ; pointer to ISR entry
1152 // jump (r30) ; jump to ISR
1154 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1157 ctrl1[0] = regs1[30] = dsp_pc;
1163 // Set the specified DSP IRQ line to a given state
1165 void DSPSetIRQLine(int irqline, int state)
1167 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1168 uint32_t mask = INT_LAT0 << irqline;
1169 dsp_control &= ~mask; // Clear the latch bit
1172 ctrl1[8] = ctrl2[8] = dsp_control;
1178 dsp_control |= mask; // Set the latch bit
1179 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1184 ctrl1[8] = ctrl2[8] = dsp_control;
1190 // Not sure if this is correct behavior, but according to JTRM,
1191 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1192 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1193 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1196 bool DSPIsRunning(void)
1198 return (DSP_RUNNING ? true : false);
1203 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1204 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1205 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1207 dsp_build_branch_condition_table();
1213 dsp_pc = 0x00F1B000;
1214 dsp_acc = 0x00000000;
1215 dsp_remain = 0x00000000;
1216 dsp_modulo = 0xFFFFFFFF;
1217 dsp_flags = 0x00040000;
1218 dsp_matrix_control = 0x00000000;
1219 dsp_pointer_to_matrix = 0x00000000;
1220 dsp_data_organization = 0xFFFFFFFF;
1221 dsp_control = 0x00002000; // Report DSP version 2
1222 dsp_div_control = 0x00000000;
1225 dsp_reg = dsp_reg_bank_0;
1226 dsp_alternate_reg = dsp_reg_bank_1;
1228 for(int i=0; i<32; i++)
1229 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1232 IMASKCleared = false;
1236 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1237 for(uint32_t i=0; i<8192; i+=4)
1238 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1241 void DSPDumpDisassembly(void)
1245 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1246 uint32_t j = 0xF1B000;
1248 while (j <= 0xF1CFFF)
1251 j += dasmjag(JAGUAR_DSP, buffer, j);
1252 WriteLog("\t%08X: %s\n", oldj, buffer);
1256 void DSPDumpRegisters(void)
1258 //Shoud add modulus, etc to dump here...
1259 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1260 WriteLog("\nRegisters bank 0\n");
1262 for(int j=0; j<8; j++)
1264 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1265 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1266 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1267 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1268 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1271 WriteLog("Registers bank 1\n");
1273 for(int j=0; j<8; j++)
1275 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1276 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1277 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1278 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1279 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1286 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1287 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1289 // get the active interrupt bits
1290 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1291 // get the interrupt mask
1292 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1294 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1295 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1296 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1297 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1298 WriteLog("\nRegisters bank 0\n");
1300 for(int j=0; j<8; j++)
1302 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1303 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1304 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1305 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1306 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1309 WriteLog("\nRegisters bank 1\n");
1313 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1314 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1315 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1316 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1317 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1322 static char buffer[512];
1323 j = DSP_WORK_RAM_BASE;
1325 while (j <= 0xF1CFFF)
1328 j += dasmjag(JAGUAR_DSP, buffer, j);
1329 WriteLog("\t%08X: %s\n", oldj, buffer);
1332 WriteLog("DSP opcodes use:\n");
1336 if (dsp_opcode_use[i])
1337 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1344 // DSP comparison core...
1347 static uint16_t lastExec;
1348 void DSPExecComp(int32_t cycles)
1350 while (cycles > 0 && DSP_RUNNING)
1352 // Load up vars for non-pipelined core
1353 memcpy(dsp_ram_8, ram1, 0x2000);
1354 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1355 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1358 dsp_remain = ctrl1[2];
1359 dsp_modulo = ctrl1[3];
1360 dsp_flags = ctrl1[4];
1361 dsp_matrix_control = ctrl1[5];
1362 dsp_pointer_to_matrix = ctrl1[6];
1363 dsp_data_organization = ctrl1[7];
1364 dsp_control = ctrl1[8];
1365 dsp_div_control = ctrl1[9];
1366 IMASKCleared = ctrl1[10];
1367 dsp_flag_z = ctrl1[11];
1368 dsp_flag_n = ctrl1[12];
1369 dsp_flag_c = ctrl1[13];
1370 DSPUpdateRegisterBanks();
1372 // Decrement cycles based on non-pipelined core...
1373 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1374 cycles -= dsp_opcode_cycles[instr1 >> 10];
1376 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1377 DSPExec(1); // Do *one* instruction
1380 memcpy(ram1, dsp_ram_8, 0x2000);
1381 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1382 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1385 ctrl1[2] = dsp_remain;
1386 ctrl1[3] = dsp_modulo;
1387 ctrl1[4] = dsp_flags;
1388 ctrl1[5] = dsp_matrix_control;
1389 ctrl1[6] = dsp_pointer_to_matrix;
1390 ctrl1[7] = dsp_data_organization;
1391 ctrl1[8] = dsp_control;
1392 ctrl1[9] = dsp_div_control;
1393 ctrl1[10] = IMASKCleared;
1394 ctrl1[11] = dsp_flag_z;
1395 ctrl1[12] = dsp_flag_n;
1396 ctrl1[13] = dsp_flag_c;
1398 // Load up vars for pipelined core
1399 memcpy(dsp_ram_8, ram2, 0x2000);
1400 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1401 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1404 dsp_remain = ctrl2[2];
1405 dsp_modulo = ctrl2[3];
1406 dsp_flags = ctrl2[4];
1407 dsp_matrix_control = ctrl2[5];
1408 dsp_pointer_to_matrix = ctrl2[6];
1409 dsp_data_organization = ctrl2[7];
1410 dsp_control = ctrl2[8];
1411 dsp_div_control = ctrl2[9];
1412 IMASKCleared = ctrl2[10];
1413 dsp_flag_z = ctrl2[11];
1414 dsp_flag_n = ctrl2[12];
1415 dsp_flag_c = ctrl2[13];
1416 DSPUpdateRegisterBanks();
1418 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1419 DSPExecP2(1); // Do *one* instruction
1422 memcpy(ram2, dsp_ram_8, 0x2000);
1423 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1424 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1427 ctrl2[2] = dsp_remain;
1428 ctrl2[3] = dsp_modulo;
1429 ctrl2[4] = dsp_flags;
1430 ctrl2[5] = dsp_matrix_control;
1431 ctrl2[6] = dsp_pointer_to_matrix;
1432 ctrl2[7] = dsp_data_organization;
1433 ctrl2[8] = dsp_control;
1434 ctrl2[9] = dsp_div_control;
1435 ctrl2[10] = IMASKCleared;
1436 ctrl2[11] = dsp_flag_z;
1437 ctrl2[12] = dsp_flag_n;
1438 ctrl2[13] = dsp_flag_c;
1440 if (instr1 != lastExec)
1442 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1444 // 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));
1445 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1446 // if (ctrl1[0] < ppc) // P ran ahead of NP
1447 //How to test this crap???
1450 DSPExecP2(1); // Do one more instruction
1453 memcpy(ram2, dsp_ram_8, 0x2000);
1454 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1455 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1458 ctrl2[2] = dsp_remain;
1459 ctrl2[3] = dsp_modulo;
1460 ctrl2[4] = dsp_flags;
1461 ctrl2[5] = dsp_matrix_control;
1462 ctrl2[6] = dsp_pointer_to_matrix;
1463 ctrl2[7] = dsp_data_organization;
1464 ctrl2[8] = dsp_control;
1465 ctrl2[9] = dsp_div_control;
1466 ctrl2[10] = IMASKCleared;
1467 ctrl2[11] = dsp_flag_z;
1468 ctrl2[12] = dsp_flag_n;
1469 ctrl2[13] = dsp_flag_c;
1471 // else // NP ran ahead of P
1472 if (instr1 != lastExec) // Must be the other way...
1475 // Load up vars for non-pipelined core
1476 memcpy(dsp_ram_8, ram1, 0x2000);
1477 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1478 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1481 dsp_remain = ctrl1[2];
1482 dsp_modulo = ctrl1[3];
1483 dsp_flags = ctrl1[4];
1484 dsp_matrix_control = ctrl1[5];
1485 dsp_pointer_to_matrix = ctrl1[6];
1486 dsp_data_organization = ctrl1[7];
1487 dsp_control = ctrl1[8];
1488 dsp_div_control = ctrl1[9];
1489 IMASKCleared = ctrl1[10];
1490 dsp_flag_z = ctrl1[11];
1491 dsp_flag_n = ctrl1[12];
1492 dsp_flag_c = ctrl1[13];
1493 DSPUpdateRegisterBanks();
1495 for(int k=0; k<2; k++)
1497 // Decrement cycles based on non-pipelined core...
1498 instr1 = DSPReadWord(dsp_pc, DSP);
1499 cycles -= dsp_opcode_cycles[instr1 >> 10];
1501 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1502 DSPExec(1); // Do *one* instruction
1506 memcpy(ram1, dsp_ram_8, 0x2000);
1507 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1508 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1511 ctrl1[2] = dsp_remain;
1512 ctrl1[3] = dsp_modulo;
1513 ctrl1[4] = dsp_flags;
1514 ctrl1[5] = dsp_matrix_control;
1515 ctrl1[6] = dsp_pointer_to_matrix;
1516 ctrl1[7] = dsp_data_organization;
1517 ctrl1[8] = dsp_control;
1518 ctrl1[9] = dsp_div_control;
1519 ctrl1[10] = IMASKCleared;
1520 ctrl1[11] = dsp_flag_z;
1521 ctrl1[12] = dsp_flag_n;
1522 ctrl1[13] = dsp_flag_c;
1526 if (instr1 != lastExec)
1528 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1530 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1531 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1544 // DSP execution core
1546 //static bool R20Set = false, tripwire = false;
1547 //static uint32_t pcQueue[32], ptrPCQ = 0;
1548 void DSPExec(int32_t cycles)
1550 #ifdef DSP_SINGLE_STEPPING
1551 if (dsp_control & 0x18)
1554 dsp_control &= ~0x10;
1557 //There is *no* good reason to do this here!
1559 dsp_releaseTimeSlice_flag = 0;
1562 while (cycles > 0 && DSP_RUNNING)
1564 /*extern uint32_t totalFrames;
1565 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1566 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1567 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1569 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1572 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1574 if (dsp_pc == 0xF1B092)
1575 doDSPDis = false;//*/
1576 /*if (dsp_pc == 0xF1B140)
1577 doDSPDis = true;//*/
1579 if (IMASKCleared) // If IMASK was cleared,
1581 #ifdef DSP_DEBUG_IRQ
1582 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1584 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1585 IMASKCleared = false;
1590 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1591 for(int i=0; i<80; i+=4)
1592 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1595 /*if (dsp_pc == 0xF1B55E)
1597 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1599 /*if (dsp_pc == 0xF1B7D2) // Start here???
1601 pcQueue[ptrPCQ++] = dsp_pc;
1603 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1604 uint32_t index = opcode >> 10;
1605 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1606 dsp_opcode_second_parameter = opcode & 0x1F;
1608 dsp_opcode[index]();
1609 dsp_opcode_use[index]++;
1610 cycles -= dsp_opcode_cycles[index];
1611 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1613 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1616 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1618 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1620 DSPDumpDisassembly();
1623 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1626 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1629 WriteLog("\nBacktrace:\n");
1630 for(int i=0; i<32; i++)
1632 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1633 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1643 // DSP opcode handlers
1646 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1647 // can cause trouble because an interrupt can occur *before* the instruction following the
1648 // jump can execute... !!! FIX !!!
1649 static void dsp_opcode_jump(void)
1652 const char * condition[32] =
1653 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1654 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1655 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1656 "???", "???", "???", "F" };
1658 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);
1661 /* dsp_flag_c=dsp_flag_c?1:0;
1662 dsp_flag_z=dsp_flag_z?1:0;
1663 dsp_flag_n=dsp_flag_n?1:0;*/
1664 // KLUDGE: Used by BRANCH_CONDITION
1665 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1667 if (BRANCH_CONDITION(IMM_2))
1671 WriteLog("Branched!\n");
1673 uint32_t delayed_pc = RM;
1675 dsp_pc = delayed_pc;
1680 WriteLog("Branch NOT taken.\n");
1684 static void dsp_opcode_jr(void)
1687 const char * condition[32] =
1688 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1689 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1690 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1691 "???", "???", "???", "F" };
1693 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);
1696 /* dsp_flag_c=dsp_flag_c?1:0;
1697 dsp_flag_z=dsp_flag_z?1:0;
1698 dsp_flag_n=dsp_flag_n?1:0;*/
1699 // KLUDGE: Used by BRANCH_CONDITION
1700 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1702 if (BRANCH_CONDITION(IMM_2))
1706 WriteLog("Branched!\n");
1708 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1709 int32_t delayed_pc = dsp_pc + (offset * 2);
1711 dsp_pc = delayed_pc;
1716 WriteLog("Branch NOT taken.\n");
1720 static void dsp_opcode_add(void)
1724 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);
1726 uint32_t res = RN + RM;
1727 SET_ZNC_ADD(RN, RM, res);
1731 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);
1735 static void dsp_opcode_addc(void)
1739 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);
1741 uint32_t res = RN + RM + dsp_flag_c;
1742 uint32_t carry = dsp_flag_c;
1743 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1744 SET_ZNC_ADD(RN + carry, RM, res);
1745 // SET_ZNC_ADD(RN, RM + carry, res);
1749 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);
1753 static void dsp_opcode_addq(void)
1757 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);
1759 uint32_t r1 = dsp_convert_zero[IMM_1];
1760 uint32_t res = RN + r1;
1761 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1765 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1769 static void dsp_opcode_sub(void)
1773 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);
1775 uint32_t res = RN - RM;
1776 SET_ZNC_SUB(RN, RM, res);
1780 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);
1784 static void dsp_opcode_subc(void)
1788 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);
1790 uint32_t res = RN - RM - dsp_flag_c;
1791 uint32_t borrow = dsp_flag_c;
1792 SET_ZNC_SUB(RN - borrow, RM, res);
1796 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);
1800 static void dsp_opcode_subq(void)
1804 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);
1806 uint32_t r1 = dsp_convert_zero[IMM_1];
1807 uint32_t res = RN - r1;
1808 SET_ZNC_SUB(RN, r1, res);
1812 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1816 static void dsp_opcode_cmp(void)
1820 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);
1822 uint32_t res = RN - RM;
1823 SET_ZNC_SUB(RN, RM, res);
1826 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1830 static void dsp_opcode_cmpq(void)
1832 static int32_t sqtable[32] =
1833 { 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 };
1836 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);
1838 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1839 uint32_t res = RN - r1;
1840 SET_ZNC_SUB(RN, r1, res);
1843 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1847 static void dsp_opcode_and(void)
1851 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);
1857 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);
1861 static void dsp_opcode_or(void)
1865 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);
1871 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);
1875 static void dsp_opcode_xor(void)
1879 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);
1885 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);
1889 static void dsp_opcode_not(void)
1893 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);
1899 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1903 static void dsp_opcode_move_pc(void)
1908 static void dsp_opcode_store_r14_indexed(void)
1910 #ifdef DSP_DIS_STORE14I
1912 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));
1914 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1915 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1917 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1921 static void dsp_opcode_store_r15_indexed(void)
1923 #ifdef DSP_DIS_STORE15I
1925 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));
1927 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1928 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1930 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1934 static void dsp_opcode_load_r14_ri(void)
1936 #ifdef DSP_DIS_LOAD14R
1938 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);
1940 #ifdef DSP_CORRECT_ALIGNMENT
1941 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1943 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1945 #ifdef DSP_DIS_LOAD14R
1947 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1951 static void dsp_opcode_load_r15_ri(void)
1953 #ifdef DSP_DIS_LOAD15R
1955 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);
1957 #ifdef DSP_CORRECT_ALIGNMENT
1958 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1960 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1962 #ifdef DSP_DIS_LOAD15R
1964 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1968 static void dsp_opcode_store_r14_ri(void)
1970 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1973 static void dsp_opcode_store_r15_ri(void)
1975 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1978 static void dsp_opcode_nop(void)
1982 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1986 static void dsp_opcode_storeb(void)
1988 #ifdef DSP_DIS_STOREB
1990 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);
1992 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1993 DSPWriteLong(RM, RN & 0xFF, DSP);
1995 JaguarWriteByte(RM, RN, DSP);
1998 static void dsp_opcode_storew(void)
2000 #ifdef DSP_DIS_STOREW
2002 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);
2004 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2005 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2006 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2008 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2010 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2011 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2013 JaguarWriteWord(RM, RN, DSP);
2017 static void dsp_opcode_store(void)
2019 #ifdef DSP_DIS_STORE
2021 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);
2023 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2024 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2026 DSPWriteLong(RM, RN, DSP);
2030 static void dsp_opcode_loadb(void)
2032 #ifdef DSP_DIS_LOADB
2034 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);
2036 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037 RN = DSPReadLong(RM, DSP) & 0xFF;
2039 RN = JaguarReadByte(RM, DSP);
2040 #ifdef DSP_DIS_LOADB
2042 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2046 static void dsp_opcode_loadw(void)
2048 #ifdef DSP_DIS_LOADW
2050 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);
2052 #ifdef DSP_CORRECT_ALIGNMENT
2053 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2054 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2056 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2058 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2059 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2061 RN = JaguarReadWord(RM, DSP);
2063 #ifdef DSP_DIS_LOADW
2065 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2069 static void dsp_opcode_load(void)
2073 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);
2075 #ifdef DSP_CORRECT_ALIGNMENT
2076 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2078 RN = DSPReadLong(RM, DSP);
2082 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2086 static void dsp_opcode_load_r14_indexed(void)
2088 #ifdef DSP_DIS_LOAD14I
2090 WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN);
2092 #ifdef DSP_CORRECT_ALIGNMENT
2093 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2095 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2097 #ifdef DSP_DIS_LOAD14I
2099 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2103 static void dsp_opcode_load_r15_indexed(void)
2105 #ifdef DSP_DIS_LOAD15I
2107 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);
2109 #ifdef DSP_CORRECT_ALIGNMENT
2110 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2112 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2114 #ifdef DSP_DIS_LOAD15I
2116 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2120 static void dsp_opcode_movei(void)
2122 #ifdef DSP_DIS_MOVEI
2124 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);
2126 // This instruction is followed by 32-bit value in LSW / MSW format...
2127 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2129 #ifdef DSP_DIS_MOVEI
2131 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2135 static void dsp_opcode_moveta(void)
2137 #ifdef DSP_DIS_MOVETA
2139 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);
2142 #ifdef DSP_DIS_MOVETA
2144 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);
2148 static void dsp_opcode_movefa(void)
2150 #ifdef DSP_DIS_MOVEFA
2152 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);
2155 #ifdef DSP_DIS_MOVEFA
2157 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);
2161 static void dsp_opcode_move(void)
2165 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);
2170 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);
2174 static void dsp_opcode_moveq(void)
2176 #ifdef DSP_DIS_MOVEQ
2178 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);
2181 #ifdef DSP_DIS_MOVEQ
2183 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2187 static void dsp_opcode_resmac(void)
2189 #ifdef DSP_DIS_RESMAC
2191 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));
2193 RN = (uint32_t)dsp_acc;
2194 #ifdef DSP_DIS_RESMAC
2196 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2200 static void dsp_opcode_imult(void)
2202 #ifdef DSP_DIS_IMULT
2204 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);
2206 RN = (int16_t)RN * (int16_t)RM;
2208 #ifdef DSP_DIS_IMULT
2210 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);
2214 static void dsp_opcode_mult(void)
2218 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);
2220 RN = (uint16_t)RM * (uint16_t)RN;
2224 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);
2228 static void dsp_opcode_bclr(void)
2232 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);
2234 uint32_t res = RN & ~(1 << IMM_1);
2239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2243 static void dsp_opcode_btst(void)
2247 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);
2249 dsp_flag_z = (~RN >> IMM_1) & 1;
2252 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2256 static void dsp_opcode_bset(void)
2260 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);
2262 uint32_t res = RN | (1 << IMM_1);
2267 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2271 static void dsp_opcode_subqt(void)
2273 #ifdef DSP_DIS_SUBQT
2275 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);
2277 RN -= dsp_convert_zero[IMM_1];
2278 #ifdef DSP_DIS_SUBQT
2280 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2284 static void dsp_opcode_addqt(void)
2286 #ifdef DSP_DIS_ADDQT
2288 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);
2290 RN += dsp_convert_zero[IMM_1];
2291 #ifdef DSP_DIS_ADDQT
2293 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2297 static void dsp_opcode_imacn(void)
2299 #ifdef DSP_DIS_IMACN
2301 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);
2303 int32_t res = (int16_t)RM * (int16_t)RN;
2304 dsp_acc += (int64_t)res;
2305 //Should we AND the result to fit into 40 bits here???
2306 #ifdef DSP_DIS_IMACN
2308 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));
2312 static void dsp_opcode_mtoi(void)
2314 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2318 static void dsp_opcode_normi(void)
2325 while ((_Rm & 0xffc00000) == 0)
2330 while ((_Rm & 0xff800000) != 0)
2340 static void dsp_opcode_mmult(void)
2342 int count = dsp_matrix_control&0x0f;
2343 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2347 if (!(dsp_matrix_control & 0x10))
2349 for (int i = 0; i < count; i++)
2353 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2355 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2356 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2363 for (int i = 0; i < count; i++)
2367 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2369 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2370 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2375 RN = res = (int32_t)accum;
2377 //NOTE: The flags are set based upon the last add/multiply done...
2381 static void dsp_opcode_abs(void)
2385 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);
2390 if (_Rn == 0x80000000)
2394 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2395 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2400 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2404 static void dsp_opcode_div(void)
2411 if (dsp_div_control & 1)
2413 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2414 if (dsp_remain&0x80000000)
2416 RN = (((uint64_t)_Rn) << 16) / _Rm;
2420 dsp_remain = _Rn % _Rm;
2421 if (dsp_remain&0x80000000)
2430 static void dsp_opcode_imultn(void)
2432 #ifdef DSP_DIS_IMULTN
2434 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);
2436 // This is OK, since this multiply won't overflow 32 bits...
2437 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2438 dsp_acc = (int64_t)res;
2440 #ifdef DSP_DIS_IMULTN
2442 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));
2446 static void dsp_opcode_neg(void)
2450 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);
2453 SET_ZNC_SUB(0, RN, res);
2457 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2461 static void dsp_opcode_shlq(void)
2465 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);
2467 // NB: This instruction is the *only* one that does (32 - immediate data).
2468 int32_t r1 = 32 - IMM_1;
2469 uint32_t res = RN << r1;
2470 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2474 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2478 static void dsp_opcode_shrq(void)
2482 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);
2484 int32_t r1 = dsp_convert_zero[IMM_1];
2485 uint32_t res = RN >> r1;
2486 SET_ZN(res); dsp_flag_c = RN & 1;
2490 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2494 static void dsp_opcode_ror(void)
2498 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);
2500 uint32_t r1 = RM & 0x1F;
2501 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2502 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2506 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);
2510 static void dsp_opcode_rorq(void)
2514 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);
2516 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2518 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2520 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2523 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2527 static void dsp_opcode_sha(void)
2529 int32_t sRm=(int32_t)RM;
2534 uint32_t shift=-sRm;
2535 if (shift>=32) shift=32;
2536 dsp_flag_c=(_Rn&0x80000000)>>31;
2546 if (shift>=32) shift=32;
2550 _Rn=((int32_t)_Rn)>>1;
2558 static void dsp_opcode_sharq(void)
2560 #ifdef DSP_DIS_SHARQ
2562 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);
2564 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2565 SET_ZN(res); dsp_flag_c = RN & 0x01;
2567 #ifdef DSP_DIS_SHARQ
2569 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2573 static void dsp_opcode_sh(void)
2575 int32_t sRm=(int32_t)RM;
2580 uint32_t shift=(-sRm);
2581 if (shift>=32) shift=32;
2582 dsp_flag_c=(_Rn&0x80000000)>>31;
2592 if (shift>=32) shift=32;
2604 void dsp_opcode_addqmod(void)
2606 #ifdef DSP_DIS_ADDQMOD
2608 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);
2610 uint32_t r1 = dsp_convert_zero[IMM_1];
2612 uint32_t res = r2 + r1;
2613 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2615 SET_ZNC_ADD(r2, r1, res);
2616 #ifdef DSP_DIS_ADDQMOD
2618 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2622 void dsp_opcode_subqmod(void)
2624 uint32_t r1 = dsp_convert_zero[IMM_1];
2626 uint32_t res = r2 - r1;
2627 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2630 SET_ZNC_SUB(r2, r1, res);
2633 void dsp_opcode_mirror(void)
2636 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2640 void dsp_opcode_sat32s(void)
2642 int32_t r2 = (uint32_t)RN;
2643 int32_t temp = dsp_acc >> 32;
2644 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2649 void dsp_opcode_sat16s(void)
2652 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2657 void dsp_opcode_illegal(void)
2659 // Don't know what it does, but it does *something*...
2660 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);
2664 // New pipelined DSP core
2667 static void DSP_abs(void);
2668 static void DSP_add(void);
2669 static void DSP_addc(void);
2670 static void DSP_addq(void);
2671 static void DSP_addqmod(void);
2672 static void DSP_addqt(void);
2673 static void DSP_and(void);
2674 static void DSP_bclr(void);
2675 static void DSP_bset(void);
2676 static void DSP_btst(void);
2677 static void DSP_cmp(void);
2678 static void DSP_cmpq(void);
2679 static void DSP_div(void);
2680 static void DSP_imacn(void);
2681 static void DSP_imult(void);
2682 static void DSP_imultn(void);
2683 static void DSP_illegal(void);
2684 static void DSP_jr(void);
2685 static void DSP_jump(void);
2686 static void DSP_load(void);
2687 static void DSP_loadb(void);
2688 static void DSP_loadw(void);
2689 static void DSP_load_r14_i(void);
2690 static void DSP_load_r14_r(void);
2691 static void DSP_load_r15_i(void);
2692 static void DSP_load_r15_r(void);
2693 static void DSP_mirror(void);
2694 static void DSP_mmult(void);
2695 static void DSP_move(void);
2696 static void DSP_movefa(void);
2697 static void DSP_movei(void);
2698 static void DSP_movepc(void);
2699 static void DSP_moveq(void);
2700 static void DSP_moveta(void);
2701 static void DSP_mtoi(void);
2702 static void DSP_mult(void);
2703 static void DSP_neg(void);
2704 static void DSP_nop(void);
2705 static void DSP_normi(void);
2706 static void DSP_not(void);
2707 static void DSP_or(void);
2708 static void DSP_resmac(void);
2709 static void DSP_ror(void);
2710 static void DSP_rorq(void);
2711 static void DSP_sat16s(void);
2712 static void DSP_sat32s(void);
2713 static void DSP_sh(void);
2714 static void DSP_sha(void);
2715 static void DSP_sharq(void);
2716 static void DSP_shlq(void);
2717 static void DSP_shrq(void);
2718 static void DSP_store(void);
2719 static void DSP_storeb(void);
2720 static void DSP_storew(void);
2721 static void DSP_store_r14_i(void);
2722 static void DSP_store_r14_r(void);
2723 static void DSP_store_r15_i(void);
2724 static void DSP_store_r15_r(void);
2725 static void DSP_sub(void);
2726 static void DSP_subc(void);
2727 static void DSP_subq(void);
2728 static void DSP_subqmod(void);
2729 static void DSP_subqt(void);
2730 static void DSP_xor(void);
2732 void (* DSPOpcode[64])() =
2734 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2735 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2736 DSP_neg, DSP_and, DSP_or, DSP_xor,
2737 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2739 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2740 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2741 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2742 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2744 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2745 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2746 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2747 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2749 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2750 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2751 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2752 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2755 bool readAffected[64][2] =
2757 { true, true}, { true, true}, {false, true}, {false, true},
2758 { true, true}, { true, true}, {false, true}, {false, true},
2759 {false, true}, { true, true}, { true, true}, { true, true},
2760 {false, true}, {false, true}, {false, true}, {false, true},
2762 { true, true}, { true, true}, { true, true}, {false, true},
2763 { true, true}, { true, true}, {false, true}, { true, true},
2764 {false, true}, {false, true}, { true, true}, {false, true},
2765 { true, true}, {false, true}, { true, true}, {false, true},
2767 {false, true}, {false, true}, { true, false}, {false, false},
2768 { true, false}, {false, false}, {false, false}, { true, false},
2769 { true, false}, { true, false}, {false, true}, { true, false},
2770 { true, false}, { true, true}, { true, true}, { true, true},
2772 {false, true}, { true, true}, { true, true}, {false, true},
2773 { true, false}, { true, false}, { true, true}, { true, false},
2774 { true, false}, {false, false}, { true, false}, { true, false},
2775 { true, true}, { true, true}, {false, false}, {false, true}
2778 bool isLoadStore[65] =
2780 false, false, false, false, false, false, false, false,
2781 false, false, false, false, false, false, false, false,
2783 false, false, false, false, false, false, false, false,
2784 false, false, false, false, false, false, false, false,
2786 false, false, false, false, false, false, false, true,
2787 true, true, false, true, true, true, true, true,
2789 false, true, true, false, false, false, false, false,
2790 false, false, true, true, true, true, false, false, false
2793 void FlushDSPPipeline(void)
2795 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2797 for(int i=0; i<4; i++)
2798 pipeline[i].opcode = PIPELINE_STALL;
2800 for(int i=0; i<32; i++)
2805 // New pipelined DSP execution core
2807 /*void DSPExecP(int32_t cycles)
2809 // bool inhibitFetch = false;
2811 dsp_releaseTimeSlice_flag = 0;
2814 while (cycles > 0 && DSP_RUNNING)
2816 WriteLog("DSPExecP: Pipeline status...\n");
2817 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);
2818 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);
2819 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);
2820 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);
2821 WriteLog(" --> Scoreboard: ");
2822 for(int i=0; i<32; i++)
2823 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2825 // Stage 1: Instruction fetch
2826 // if (!inhibitFetch)
2828 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2829 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2830 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2831 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2832 if (pipeline[plPtrFetch].opcode == 38)
2833 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2834 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2837 // inhibitFetch = false;
2838 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2840 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2841 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);
2842 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);
2843 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);
2844 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);
2845 // Stage 2: Read registers
2846 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2847 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2848 if (scoreboard[pipeline[plPtrRead].operand2])
2849 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2850 // We have a hit in the scoreboard, so we have to stall the pipeline...
2852 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2853 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2854 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2855 pipeline[plPtrFetch] = pipeline[plPtrRead];
2856 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2860 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2861 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2862 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2864 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2865 // Shouldn't we be more selective with the register scoreboarding?
2866 // Yes, we should. !!! FIX !!!
2867 scoreboard[pipeline[plPtrRead].operand2] = true;
2868 //Advance PC here??? Yes.
2869 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2870 //This is a mangling of the pipeline stages, but what else to do???
2871 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2874 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2875 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2876 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2877 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2878 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2880 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2882 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2883 DSPOpcode[pipeline[plPtrExec].opcode]();
2884 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2885 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2890 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2891 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);
2892 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);
2893 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);
2894 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);
2895 // Stage 4: Write back register
2896 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2898 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2899 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2901 scoreboard[pipeline[plPtrWrite].operand1]
2902 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2905 // Push instructions through the pipeline...
2906 plPtrFetch = (++plPtrFetch) & 0x03;
2907 plPtrRead = (++plPtrRead) & 0x03;
2908 plPtrExec = (++plPtrExec) & 0x03;
2909 plPtrWrite = (++plPtrWrite) & 0x03;
2916 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2918 // Should be fixed now. Another problem is figuring how to do the sequence following
2919 // a branch followed with the JR & JUMP instructions...
2921 // There are two conflicting problems:
2924 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2925 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2926 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2927 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2928 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2929 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2930 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2931 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2932 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2933 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2934 DSP: Finished interrupt.
2935 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2936 ; bank 0 (where is was prepared)!
2937 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2938 F1B252: NOP [NCZ:001]
2941 // The other is when you see this at the end of an IRQ:
2944 JUMP T, (R29) ; R29 = Previous stack + 2
2945 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2947 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2948 ; 1) The STORE goes through the pipeline and is executed/written back
2949 ; 2) The pipeline is flushed
2950 ; 3) The DSP_PC is set to the new address
2951 ; 4) Execution resumes
2953 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2954 ; bank 0 instead of the current bank 1 and so goes astray!
2957 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2958 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2962 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2963 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2964 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2965 If it were done properly, the STORE write back would occur *after* (well, technically,
2966 during) the execution of the the JUMP that follows it.
2970 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2971 F1B08A: NOP [NCZ:001]
2973 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2976 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
2979 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
2980 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2981 F1B08A: NOP [NCZ:001]
2983 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
2986 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
2987 DSP: CPU -> DSP interrupt
2988 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
2989 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
2991 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
2994 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
2995 F1B006: NOP [NCZ:001]
2997 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3000 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3001 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3004 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3005 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3008 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3009 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3012 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3013 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3016 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3019 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3022 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3023 F1B0FE: NOP [NCZ:000]
3025 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3028 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3031 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3032 F1B138: NOP [NCZ:000]
3034 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3037 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3038 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3039 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3042 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3043 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3046 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3047 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3048 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3050 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3051 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3054 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3055 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3056 DSP: Finished interrupt.
3057 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3059 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3062 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3063 F1B016: NOP [NCZ:001]
3065 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3068 uint32_t pcQueue1[0x400];
3069 uint32_t pcQPtr1 = 0;
3070 static uint32_t prevR1;
3071 //Let's try a 3 stage pipeline....
3072 //Looks like 3 stage is correct, otherwise bad things happen...
3073 void DSPExecP2(int32_t cycles)
3075 dsp_releaseTimeSlice_flag = 0;
3078 while (cycles > 0 && DSP_RUNNING)
3080 /*extern uint32_t totalFrames;
3081 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3082 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3083 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3085 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3088 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3090 if (dsp_pc == 0xF1B092)
3091 doDSPDis = false;//*/
3092 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3093 doDSPDis = true;//*/
3094 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3095 doDSPDis = true;//*/
3096 /*if (dsp_pc == 0xF1B0A0)
3097 doDSPDis = true;//*/
3098 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3099 doDSPDis = true;//*/
3100 //Two parter... (not sure how to write this)
3101 //if (dsp_pc == 0xF1B0D2)
3102 // prevR1 = dsp_reg[1];
3104 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3105 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3108 pcQueue1[pcQPtr1++] = dsp_pc;
3111 #ifdef DSP_DEBUG_PL2
3112 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3114 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3119 for(int i=0; i<0x400; i++)
3121 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3122 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3128 if (IMASKCleared) // If IMASK was cleared,
3130 #ifdef DSP_DEBUG_IRQ
3131 WriteLog("DSP: Finished interrupt.\n");
3133 DSPHandleIRQs(); // See if any other interrupts are pending!
3134 IMASKCleared = false;
3137 //if (dsp_flags & REGPAGE)
3138 // WriteLog(" --> REGPAGE has just been set!\n");
3139 #ifdef DSP_DEBUG_PL2
3142 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3143 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]);
3144 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]);
3145 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]);
3146 WriteLog(" --> Scoreboard: ");
3147 for(int i=0; i<32; i++)
3148 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3152 // Stage 1a: Instruction fetch
3153 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3154 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3155 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3156 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3157 if (pipeline[plPtrRead].opcode == 38)
3158 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3159 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3160 #ifdef DSP_DEBUG_PL2
3163 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3164 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3165 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]);
3166 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]);
3167 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]);
3170 // Stage 1b: Read registers
3171 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3172 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3174 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3175 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3176 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3177 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3178 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3179 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3180 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3182 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3183 // We have a hit in the scoreboard, so we have to stall the pipeline...
3184 #ifdef DSP_DEBUG_PL2
3188 WriteLog(" --> Stalling pipeline: ");
3189 if (readAffected[pipeline[plPtrRead].opcode][0])
3190 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3191 if (readAffected[pipeline[plPtrRead].opcode][1])
3192 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3196 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3197 #ifdef DSP_DEBUG_PL2
3202 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3203 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3204 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3206 // Shouldn't we be more selective with the register scoreboarding?
3207 // Yes, we should. !!! FIX !!! Kinda [DONE]
3208 #ifndef NEW_SCOREBOARD
3209 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3211 //Hopefully this will fix the dual MOVEQ # problem...
3212 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3215 //Advance PC here??? Yes.
3216 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3219 #ifdef DSP_DEBUG_PL2
3222 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3223 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]);
3224 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]);
3225 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]);
3229 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3231 #ifdef DSP_DEBUG_PL2
3233 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"));
3237 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3242 lastExec = pipeline[plPtrExec].instruction;
3243 //WriteLog("[lastExec = %04X]\n", lastExec);
3245 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3246 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3247 DSPOpcode[pipeline[plPtrExec].opcode]();
3248 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3252 //Let's not, until we do the stalling correctly...
3253 //But, we gotta while we're doing the comparison core...!
3254 //Or do we? cycles--;
3255 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3256 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3257 //to model this clock cycle behavior correctly...
3258 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3259 //don't affect the reads at stage 1...
3260 #ifdef DSP_DEBUG_STALL
3262 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3266 #ifdef DSP_DEBUG_PL2
3269 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3270 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]);
3271 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]);
3272 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]);
3276 // Stage 3: Write back register/memory address
3277 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3279 /*if (pipeline[plPtrWrite].writebackRegister == 3
3280 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3283 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3286 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3288 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3289 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3292 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3293 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3294 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3295 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3297 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3301 #ifndef NEW_SCOREBOARD
3302 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3303 scoreboard[pipeline[plPtrWrite].operand2] = false;
3305 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3306 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3307 if (scoreboard[pipeline[plPtrWrite].operand2])
3308 scoreboard[pipeline[plPtrWrite].operand2]--;
3312 // Push instructions through the pipeline...
3313 plPtrRead = (++plPtrRead) & 0x03;
3314 plPtrExec = (++plPtrExec) & 0x03;
3315 plPtrWrite = (++plPtrWrite) & 0x03;
3324 //#define DSP_DEBUG_PL3
3325 //Let's try a 2 stage pipeline....
3326 void DSPExecP3(int32_t cycles)
3328 dsp_releaseTimeSlice_flag = 0;
3331 while (cycles > 0 && DSP_RUNNING)
3333 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3335 #ifdef DSP_DEBUG_PL3
3336 WriteLog("DSPExecP: Pipeline status...\n");
3337 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]);
3338 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3339 WriteLog(" --> Scoreboard: ");
3340 for(int i=0; i<32; i++)
3341 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3344 // Stage 1a: Instruction fetch
3345 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3346 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3347 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3348 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3349 if (pipeline[plPtrRead].opcode == 38)
3350 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3351 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3352 #ifdef DSP_DEBUG_PL3
3353 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3354 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3355 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]);
3356 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]);
3358 // Stage 1b: Read registers
3359 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3360 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3361 // We have a hit in the scoreboard, so we have to stall the pipeline...
3362 #ifdef DSP_DEBUG_PL3
3364 WriteLog(" --> Stalling pipeline: ");
3365 if (readAffected[pipeline[plPtrRead].opcode][0])
3366 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3367 if (readAffected[pipeline[plPtrRead].opcode][1])
3368 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3371 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3372 #ifdef DSP_DEBUG_PL3
3377 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3378 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3379 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3381 // Shouldn't we be more selective with the register scoreboarding?
3382 // Yes, we should. !!! FIX !!! [Kinda DONE]
3383 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3385 //Advance PC here??? Yes.
3386 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3389 #ifdef DSP_DEBUG_PL3
3390 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3391 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]);
3392 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3394 // Stage 2a: Execute
3395 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3397 #ifdef DSP_DEBUG_PL3
3398 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3400 DSPOpcode[pipeline[plPtrExec].opcode]();
3401 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3402 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3407 #ifdef DSP_DEBUG_PL3
3408 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3409 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]);
3410 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]);
3413 // Stage 2b: Write back register
3414 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3416 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3417 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3419 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3420 scoreboard[pipeline[plPtrExec].operand2] = false;
3423 // Push instructions through the pipeline...
3424 plPtrRead = (++plPtrRead) & 0x03;
3425 plPtrExec = (++plPtrExec) & 0x03;
3432 // DSP pipelined opcode handlers
3435 #define PRM pipeline[plPtrExec].reg1
3436 #define PRN pipeline[plPtrExec].reg2
3437 #define PIMM1 pipeline[plPtrExec].operand1
3438 #define PIMM2 pipeline[plPtrExec].operand2
3439 #define PRES pipeline[plPtrExec].result
3440 #define PWBR pipeline[plPtrExec].writebackRegister
3441 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3442 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3443 #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))
3444 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3446 static void DSP_abs(void)
3450 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);
3454 if (_Rn == 0x80000000)
3458 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3459 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3460 CLR_ZN; SET_Z(PRES);
3464 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3468 static void DSP_add(void)
3472 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);
3474 uint32_t res = PRN + PRM;
3475 SET_ZNC_ADD(PRN, PRM, res);
3479 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);
3483 static void DSP_addc(void)
3487 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);
3489 uint32_t res = PRN + PRM + dsp_flag_c;
3490 uint32_t carry = dsp_flag_c;
3491 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3492 SET_ZNC_ADD(PRN + carry, PRM, res);
3493 // SET_ZNC_ADD(PRN, PRM + carry, res);
3497 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);
3501 static void DSP_addq(void)
3505 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);
3507 uint32_t r1 = dsp_convert_zero[PIMM1];
3508 uint32_t res = PRN + r1;
3509 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3513 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3517 static void DSP_addqmod(void)
3519 #ifdef DSP_DIS_ADDQMOD
3521 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);
3523 uint32_t r1 = dsp_convert_zero[PIMM1];
3525 uint32_t res = r2 + r1;
3526 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3528 SET_ZNC_ADD(r2, r1, res);
3529 #ifdef DSP_DIS_ADDQMOD
3531 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3535 static void DSP_addqt(void)
3537 #ifdef DSP_DIS_ADDQT
3539 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);
3541 PRES = PRN + dsp_convert_zero[PIMM1];
3542 #ifdef DSP_DIS_ADDQT
3544 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3548 static void DSP_and(void)
3552 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);
3558 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);
3562 static void DSP_bclr(void)
3566 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);
3568 PRES = PRN & ~(1 << PIMM1);
3572 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3576 static void DSP_bset(void)
3580 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);
3582 PRES = PRN | (1 << PIMM1);
3586 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3590 static void DSP_btst(void)
3594 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);
3596 dsp_flag_z = (~PRN >> PIMM1) & 1;
3600 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3604 static void DSP_cmp(void)
3608 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);
3610 uint32_t res = PRN - PRM;
3611 SET_ZNC_SUB(PRN, PRM, res);
3615 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3619 static void DSP_cmpq(void)
3621 static int32_t sqtable[32] =
3622 { 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 };
3625 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);
3627 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3628 uint32_t res = PRN - r1;
3629 SET_ZNC_SUB(PRN, r1, res);
3633 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3637 static void DSP_div(void)
3639 uint32_t _Rm = PRM, _Rn = PRN;
3643 if (dsp_div_control & 1)
3645 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3646 if (dsp_remain & 0x80000000)
3648 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3652 dsp_remain = _Rn % _Rm;
3653 if (dsp_remain & 0x80000000)
3662 static void DSP_imacn(void)
3664 #ifdef DSP_DIS_IMACN
3666 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);
3668 int32_t res = (int16_t)PRM * (int16_t)PRN;
3669 dsp_acc += (int64_t)res;
3670 //Should we AND the result to fit into 40 bits here???
3672 #ifdef DSP_DIS_IMACN
3674 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));
3678 static void DSP_imult(void)
3680 #ifdef DSP_DIS_IMULT
3682 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);
3684 PRES = (int16_t)PRN * (int16_t)PRM;
3686 #ifdef DSP_DIS_IMULT
3688 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);
3692 static void DSP_imultn(void)
3694 #ifdef DSP_DIS_IMULTN
3696 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);
3698 // This is OK, since this multiply won't overflow 32 bits...
3699 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3700 dsp_acc = (int64_t)res;
3703 #ifdef DSP_DIS_IMULTN
3705 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));
3709 static void DSP_illegal(void)
3711 #ifdef DSP_DIS_ILLEGAL
3713 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3718 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3719 // can cause trouble because an interrupt can occur *before* the instruction following the
3720 // jump can execute... !!! FIX !!!
3721 // This can probably be solved by judicious coding in the pipeline execution core...
3722 // And should be fixed now...
3723 static void DSP_jr(void)
3726 const char * condition[32] =
3727 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3728 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3729 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3730 "???", "???", "???", "F" };
3732 //How come this is always off by 2???
3733 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);
3735 // KLUDGE: Used by BRANCH_CONDITION macro
3736 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3738 if (BRANCH_CONDITION(PIMM2))
3742 WriteLog("Branched!\n");
3744 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3745 //Account for pipeline effects...
3746 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3747 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3749 // Now that we've branched, we have to make sure that the following instruction
3750 // is executed atomically with this one and then flush the pipeline before setting
3753 // Step 1: Handle writebacks at stage 3 of pipeline
3754 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3756 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3757 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3759 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3760 scoreboard[pipeline[plPtrWrite].operand2] = false;
3762 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3764 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3766 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3767 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3770 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3771 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3772 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3773 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3775 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3779 #ifndef NEW_SCOREBOARD
3780 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3781 scoreboard[pipeline[plPtrWrite].operand2] = false;
3783 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3784 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3785 if (scoreboard[pipeline[plPtrWrite].operand2])
3786 scoreboard[pipeline[plPtrWrite].operand2]--;
3790 // Step 2: Push instruction through pipeline & execute following instruction
3791 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3792 // we effectively handle the final push of the instruction through the
3793 // pipeline when the new PC takes effect (since when we return, the
3794 // pipeline code will be executing the writeback stage. If we reverse
3795 // the execution order of the pipeline stages, this will no longer be
3797 pipeline[plPtrExec] = pipeline[plPtrRead];
3798 //This is BAD. We need to get that next opcode and execute it!
3799 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3800 // remove this crap.
3801 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3803 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3804 pipeline[plPtrExec].opcode = instruction >> 10;
3805 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3806 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3807 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3808 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3809 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3811 dsp_pc += 2; // For DSP_DIS_* accuracy
3812 DSPOpcode[pipeline[plPtrExec].opcode]();
3813 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3814 pipeline[plPtrWrite] = pipeline[plPtrExec];
3816 // Step 3: Flush pipeline & set new PC
3817 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3824 WriteLog("Branch NOT taken.\n");
3830 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3833 static void DSP_jump(void)
3836 const char * condition[32] =
3837 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3838 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3839 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3840 "???", "???", "???", "F" };
3842 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);
3844 // KLUDGE: Used by BRANCH_CONDITION macro
3845 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3847 if (BRANCH_CONDITION(PIMM2))
3851 WriteLog("Branched!\n");
3853 uint32_t PCSave = PRM;
3854 // Now that we've branched, we have to make sure that the following instruction
3855 // is executed atomically with this one and then flush the pipeline before setting
3858 // Step 1: Handle writebacks at stage 3 of pipeline
3859 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3861 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3862 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3864 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3865 scoreboard[pipeline[plPtrWrite].operand2] = false;
3867 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3869 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3871 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3872 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3875 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3876 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3877 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3878 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3880 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3884 #ifndef NEW_SCOREBOARD
3885 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3886 scoreboard[pipeline[plPtrWrite].operand2] = false;
3888 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3889 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3890 if (scoreboard[pipeline[plPtrWrite].operand2])
3891 scoreboard[pipeline[plPtrWrite].operand2]--;
3895 // Step 2: Push instruction through pipeline & execute following instruction
3896 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3897 // we effectively handle the final push of the instruction through the
3898 // pipeline when the new PC takes effect (since when we return, the
3899 // pipeline code will be executing the writeback stage. If we reverse
3900 // the execution order of the pipeline stages, this will no longer be
3902 pipeline[plPtrExec] = pipeline[plPtrRead];
3903 //This is BAD. We need to get that next opcode and execute it!
3904 //Also, same problem in JR!
3905 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3906 // remove this crap.
3907 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3909 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3910 pipeline[plPtrExec].opcode = instruction >> 10;
3911 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3912 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3913 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3914 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3915 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3917 dsp_pc += 2; // For DSP_DIS_* accuracy
3918 DSPOpcode[pipeline[plPtrExec].opcode]();
3919 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3920 pipeline[plPtrWrite] = pipeline[plPtrExec];
3922 // Step 3: Flush pipeline & set new PC
3923 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3930 WriteLog("Branch NOT taken.\n");
3938 static void DSP_load(void)
3942 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);
3944 #ifdef DSP_CORRECT_ALIGNMENT
3945 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3947 PRES = DSPReadLong(PRM, DSP);
3951 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3955 static void DSP_loadb(void)
3957 #ifdef DSP_DIS_LOADB
3959 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);
3961 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3962 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3964 PRES = JaguarReadByte(PRM, DSP);
3965 #ifdef DSP_DIS_LOADB
3967 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3971 static void DSP_loadw(void)
3973 #ifdef DSP_DIS_LOADW
3975 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);
3977 #ifdef DSP_CORRECT_ALIGNMENT
3978 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3979 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
3981 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
3983 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3984 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
3986 PRES = JaguarReadWord(PRM, DSP);
3988 #ifdef DSP_DIS_LOADW
3990 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3994 static void DSP_load_r14_i(void)
3996 #ifdef DSP_DIS_LOAD14I
3998 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);
4000 #ifdef DSP_CORRECT_ALIGNMENT
4001 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4003 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4005 #ifdef DSP_DIS_LOAD14I
4007 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4011 static void DSP_load_r14_r(void)
4013 #ifdef DSP_DIS_LOAD14R
4015 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);
4017 #ifdef DSP_CORRECT_ALIGNMENT
4018 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4020 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4022 #ifdef DSP_DIS_LOAD14R
4024 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4028 static void DSP_load_r15_i(void)
4030 #ifdef DSP_DIS_LOAD15I
4032 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);
4034 #ifdef DSP_CORRECT_ALIGNMENT
4035 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4037 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4039 #ifdef DSP_DIS_LOAD15I
4041 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4045 static void DSP_load_r15_r(void)
4047 #ifdef DSP_DIS_LOAD15R
4049 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);
4051 #ifdef DSP_CORRECT_ALIGNMENT
4052 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4054 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4056 #ifdef DSP_DIS_LOAD15R
4058 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4062 static void DSP_mirror(void)
4065 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4069 static void DSP_mmult(void)
4071 int count = dsp_matrix_control&0x0f;
4072 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4076 if (!(dsp_matrix_control & 0x10))
4078 for (int i = 0; i < count; i++)
4082 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4084 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4085 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4092 for (int i = 0; i < count; i++)
4096 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4098 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4099 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4105 PRES = res = (int32_t)accum;
4107 //NOTE: The flags are set based upon the last add/multiply done...
4111 static void DSP_move(void)
4115 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);
4120 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);
4124 static void DSP_movefa(void)
4126 #ifdef DSP_DIS_MOVEFA
4128 // 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);
4129 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);
4131 // PRES = ALTERNATE_RM;
4132 PRES = dsp_alternate_reg[PIMM1];
4133 #ifdef DSP_DIS_MOVEFA
4135 // 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);
4136 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);
4140 static void DSP_movei(void)
4142 #ifdef DSP_DIS_MOVEI
4144 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);
4146 // // This instruction is followed by 32-bit value in LSW / MSW format...
4147 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4149 #ifdef DSP_DIS_MOVEI
4151 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4155 static void DSP_movepc(void)
4157 #ifdef DSP_DIS_MOVEPC
4159 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);
4161 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4162 // PRES = dsp_pc - 2;
4163 //Account for pipeline effects...
4164 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4165 #ifdef DSP_DIS_MOVEPC
4167 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4171 static void DSP_moveq(void)
4173 #ifdef DSP_DIS_MOVEQ
4175 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);
4178 #ifdef DSP_DIS_MOVEQ
4180 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4184 static void DSP_moveta(void)
4186 #ifdef DSP_DIS_MOVETA
4188 // 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);
4189 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]);
4191 // ALTERNATE_RN = PRM;
4192 dsp_alternate_reg[PIMM2] = PRM;
4194 #ifdef DSP_DIS_MOVETA
4196 // 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);
4197 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]);
4201 static void DSP_mtoi(void)
4203 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4207 static void DSP_mult(void)
4211 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);
4213 PRES = (uint16_t)PRM * (uint16_t)PRN;
4217 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);
4221 static void DSP_neg(void)
4225 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);
4227 uint32_t res = -PRN;
4228 SET_ZNC_SUB(0, PRN, res);
4232 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4236 static void DSP_nop(void)
4240 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4245 static void DSP_normi(void)
4252 while ((_Rm & 0xffc00000) == 0)
4257 while ((_Rm & 0xff800000) != 0)
4267 static void DSP_not(void)
4271 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);
4277 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4281 static void DSP_or(void)
4285 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);
4291 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);
4295 static void DSP_resmac(void)
4297 #ifdef DSP_DIS_RESMAC
4299 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));
4301 PRES = (uint32_t)dsp_acc;
4302 #ifdef DSP_DIS_RESMAC
4304 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4308 static void DSP_ror(void)
4312 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);
4314 uint32_t r1 = PRM & 0x1F;
4315 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4316 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4320 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);
4324 static void DSP_rorq(void)
4328 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);
4330 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4332 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4334 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4337 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4341 static void DSP_sat16s(void)
4344 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4349 static void DSP_sat32s(void)
4351 int32_t r2 = (uint32_t)PRN;
4352 int32_t temp = dsp_acc >> 32;
4353 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4358 static void DSP_sh(void)
4360 int32_t sRm = (int32_t)PRM;
4365 uint32_t shift = -sRm;
4370 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4380 uint32_t shift = sRm;
4385 dsp_flag_c = _Rn & 0x1;
4398 static void DSP_sha(void)
4400 int32_t sRm = (int32_t)PRM;
4405 uint32_t shift = -sRm;
4410 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4420 uint32_t shift = sRm;
4425 dsp_flag_c = _Rn & 0x1;
4429 _Rn = ((int32_t)_Rn) >> 1;
4438 static void DSP_sharq(void)
4440 #ifdef DSP_DIS_SHARQ
4442 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);
4444 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4445 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4447 #ifdef DSP_DIS_SHARQ
4449 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4453 static void DSP_shlq(void)
4457 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);
4459 int32_t r1 = 32 - PIMM1;
4460 uint32_t res = PRN << r1;
4461 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4465 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4469 static void DSP_shrq(void)
4473 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);
4475 int32_t r1 = dsp_convert_zero[PIMM1];
4476 uint32_t res = PRN >> r1;
4477 SET_ZN(res); dsp_flag_c = PRN & 1;
4481 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4485 static void DSP_store(void)
4487 #ifdef DSP_DIS_STORE
4489 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);
4491 // DSPWriteLong(PRM, PRN, DSP);
4493 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4494 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4496 pipeline[plPtrExec].address = PRM;
4498 pipeline[plPtrExec].value = PRN;
4499 pipeline[plPtrExec].type = TYPE_DWORD;
4503 static void DSP_storeb(void)
4505 #ifdef DSP_DIS_STOREB
4507 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);
4509 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4510 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4512 // JaguarWriteByte(PRM, PRN, DSP);
4515 pipeline[plPtrExec].address = PRM;
4517 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4519 pipeline[plPtrExec].value = PRN & 0xFF;
4520 pipeline[plPtrExec].type = TYPE_DWORD;
4524 pipeline[plPtrExec].value = PRN;
4525 pipeline[plPtrExec].type = TYPE_BYTE;
4531 static void DSP_storew(void)
4533 #ifdef DSP_DIS_STOREW
4535 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);
4537 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4538 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4540 // JaguarWriteWord(PRM, PRN, DSP);
4543 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4544 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4546 pipeline[plPtrExec].address = PRM;
4549 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4551 pipeline[plPtrExec].value = PRN & 0xFFFF;
4552 pipeline[plPtrExec].type = TYPE_DWORD;
4556 pipeline[plPtrExec].value = PRN;
4557 pipeline[plPtrExec].type = TYPE_WORD;
4562 static void DSP_store_r14_i(void)
4564 #ifdef DSP_DIS_STORE14I
4566 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));
4568 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4570 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4571 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4573 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4575 pipeline[plPtrExec].value = PRN;
4576 pipeline[plPtrExec].type = TYPE_DWORD;
4580 static void DSP_store_r14_r(void)
4582 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4584 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4585 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4587 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4589 pipeline[plPtrExec].value = PRN;
4590 pipeline[plPtrExec].type = TYPE_DWORD;
4594 static void DSP_store_r15_i(void)
4596 #ifdef DSP_DIS_STORE15I
4598 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));
4600 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4602 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4603 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4605 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4607 pipeline[plPtrExec].value = PRN;
4608 pipeline[plPtrExec].type = TYPE_DWORD;
4612 static void DSP_store_r15_r(void)
4614 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4616 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4617 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4619 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4621 pipeline[plPtrExec].value = PRN;
4622 pipeline[plPtrExec].type = TYPE_DWORD;
4626 static void DSP_sub(void)
4630 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);
4632 uint32_t res = PRN - PRM;
4633 SET_ZNC_SUB(PRN, PRM, res);
4637 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);
4641 static void DSP_subc(void)
4645 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);
4647 uint32_t res = PRN - PRM - dsp_flag_c;
4648 uint32_t borrow = dsp_flag_c;
4649 SET_ZNC_SUB(PRN - borrow, PRM, res);
4653 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);
4657 static void DSP_subq(void)
4661 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);
4663 uint32_t r1 = dsp_convert_zero[PIMM1];
4664 uint32_t res = PRN - r1;
4665 SET_ZNC_SUB(PRN, r1, res);
4669 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4673 static void DSP_subqmod(void)
4675 uint32_t r1 = dsp_convert_zero[PIMM1];
4677 uint32_t res = r2 - r1;
4678 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4680 SET_ZNC_SUB(r2, r1, res);
4683 static void DSP_subqt(void)
4685 #ifdef DSP_DIS_SUBQT
4687 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);
4689 PRES = PRN - dsp_convert_zero[PIMM1];
4690 #ifdef DSP_DIS_SUBQT
4692 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4696 static void DSP_xor(void)
4700 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);
4706 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);