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);
1644 // DSP opcode handlers
1647 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1648 // can cause trouble because an interrupt can occur *before* the instruction following the
1649 // jump can execute... !!! FIX !!!
1650 static void dsp_opcode_jump(void)
1653 const char * condition[32] =
1654 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1655 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1656 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1657 "???", "???", "???", "F" };
1659 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);
1662 /* dsp_flag_c=dsp_flag_c?1:0;
1663 dsp_flag_z=dsp_flag_z?1:0;
1664 dsp_flag_n=dsp_flag_n?1:0;*/
1665 // KLUDGE: Used by BRANCH_CONDITION
1666 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1668 if (BRANCH_CONDITION(IMM_2))
1672 WriteLog("Branched!\n");
1674 uint32_t delayed_pc = RM;
1676 dsp_pc = delayed_pc;
1681 WriteLog("Branch NOT taken.\n");
1686 static void dsp_opcode_jr(void)
1689 const char * condition[32] =
1690 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1691 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1692 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1693 "???", "???", "???", "F" };
1695 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);
1698 /* dsp_flag_c=dsp_flag_c?1:0;
1699 dsp_flag_z=dsp_flag_z?1:0;
1700 dsp_flag_n=dsp_flag_n?1:0;*/
1701 // KLUDGE: Used by BRANCH_CONDITION
1702 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1704 if (BRANCH_CONDITION(IMM_2))
1708 WriteLog("Branched!\n");
1710 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1711 int32_t delayed_pc = dsp_pc + (offset * 2);
1713 dsp_pc = delayed_pc;
1718 WriteLog("Branch NOT taken.\n");
1723 static void dsp_opcode_add(void)
1727 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);
1729 uint32_t res = RN + RM;
1730 SET_ZNC_ADD(RN, RM, res);
1734 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);
1739 static void dsp_opcode_addc(void)
1743 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);
1745 uint32_t res = RN + RM + dsp_flag_c;
1746 uint32_t carry = dsp_flag_c;
1747 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1748 SET_ZNC_ADD(RN + carry, RM, res);
1749 // SET_ZNC_ADD(RN, RM + carry, res);
1753 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);
1758 static void dsp_opcode_addq(void)
1762 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);
1764 uint32_t r1 = dsp_convert_zero[IMM_1];
1765 uint32_t res = RN + r1;
1766 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1770 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1775 static void dsp_opcode_sub(void)
1779 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);
1781 uint32_t res = RN - RM;
1782 SET_ZNC_SUB(RN, RM, res);
1786 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1791 static void dsp_opcode_subc(void)
1795 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);
1797 // This is how the DSP ALU does it--Two's complement with inverted carry
1798 uint64_t res = (uint64_t)RN + (uint64_t)(RM ^ 0xFFFFFFFF) + (dsp_flag_c ^ 1);
1799 // Carry out of the result is inverted too
1800 dsp_flag_c = ((res >> 32) & 0x01) ^ 1;
1801 RN = (res & 0xFFFFFFFF);
1805 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);
1810 static void dsp_opcode_subq(void)
1814 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);
1816 uint32_t r1 = dsp_convert_zero[IMM_1];
1817 uint32_t res = RN - r1;
1818 SET_ZNC_SUB(RN, r1, res);
1822 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1827 static void dsp_opcode_cmp(void)
1831 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);
1833 uint32_t res = RN - RM;
1834 SET_ZNC_SUB(RN, RM, res);
1837 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1842 static void dsp_opcode_cmpq(void)
1844 static int32_t sqtable[32] =
1845 { 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 };
1848 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);
1850 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1851 uint32_t res = RN - r1;
1852 SET_ZNC_SUB(RN, r1, res);
1855 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1860 static void dsp_opcode_and(void)
1864 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);
1870 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_or(void)
1879 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);
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);
1890 static void dsp_opcode_xor(void)
1894 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);
1900 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);
1905 static void dsp_opcode_not(void)
1909 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);
1915 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1920 static void dsp_opcode_move_pc(void)
1926 static void dsp_opcode_store_r14_indexed(void)
1928 #ifdef DSP_DIS_STORE14I
1930 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));
1932 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1933 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1935 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1940 static void dsp_opcode_store_r15_indexed(void)
1942 #ifdef DSP_DIS_STORE15I
1944 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));
1946 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1947 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1949 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1954 static void dsp_opcode_load_r14_ri(void)
1956 #ifdef DSP_DIS_LOAD14R
1958 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);
1960 #ifdef DSP_CORRECT_ALIGNMENT
1961 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1963 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1965 #ifdef DSP_DIS_LOAD14R
1967 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1972 static void dsp_opcode_load_r15_ri(void)
1974 #ifdef DSP_DIS_LOAD15R
1976 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);
1978 #ifdef DSP_CORRECT_ALIGNMENT
1979 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1981 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1983 #ifdef DSP_DIS_LOAD15R
1985 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1990 static void dsp_opcode_store_r14_ri(void)
1992 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1996 static void dsp_opcode_store_r15_ri(void)
1998 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2002 static void dsp_opcode_nop(void)
2006 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2011 static void dsp_opcode_storeb(void)
2013 #ifdef DSP_DIS_STOREB
2015 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);
2017 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2018 DSPWriteLong(RM, RN & 0xFF, DSP);
2020 JaguarWriteByte(RM, RN, DSP);
2024 static void dsp_opcode_storew(void)
2026 #ifdef DSP_DIS_STOREW
2028 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);
2030 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2031 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2032 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2034 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2036 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2039 JaguarWriteWord(RM, RN, DSP);
2044 static void dsp_opcode_store(void)
2046 #ifdef DSP_DIS_STORE
2048 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);
2050 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2051 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2053 DSPWriteLong(RM, RN, DSP);
2058 static void dsp_opcode_loadb(void)
2060 #ifdef DSP_DIS_LOADB
2062 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);
2064 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2065 RN = DSPReadLong(RM, DSP) & 0xFF;
2067 RN = JaguarReadByte(RM, DSP);
2068 #ifdef DSP_DIS_LOADB
2070 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2075 static void dsp_opcode_loadw(void)
2077 #ifdef DSP_DIS_LOADW
2079 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);
2081 #ifdef DSP_CORRECT_ALIGNMENT
2082 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2083 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2085 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2087 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2088 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2090 RN = JaguarReadWord(RM, DSP);
2092 #ifdef DSP_DIS_LOADW
2094 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2099 static void dsp_opcode_load(void)
2103 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);
2105 #ifdef DSP_CORRECT_ALIGNMENT
2106 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2108 RN = DSPReadLong(RM, DSP);
2112 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2117 static void dsp_opcode_load_r14_indexed(void)
2119 #ifdef DSP_DIS_LOAD14I
2121 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);
2123 #ifdef DSP_CORRECT_ALIGNMENT
2124 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2126 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2128 #ifdef DSP_DIS_LOAD14I
2130 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_load_r15_indexed(void)
2137 #ifdef DSP_DIS_LOAD15I
2139 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);
2141 #ifdef DSP_CORRECT_ALIGNMENT
2142 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2144 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2146 #ifdef DSP_DIS_LOAD15I
2148 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2153 static void dsp_opcode_movei(void)
2155 #ifdef DSP_DIS_MOVEI
2157 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);
2159 // This instruction is followed by 32-bit value in LSW / MSW format...
2160 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2162 #ifdef DSP_DIS_MOVEI
2164 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2169 static void dsp_opcode_moveta(void)
2171 #ifdef DSP_DIS_MOVETA
2173 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);
2176 #ifdef DSP_DIS_MOVETA
2178 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);
2183 static void dsp_opcode_movefa(void)
2185 #ifdef DSP_DIS_MOVEFA
2187 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);
2190 #ifdef DSP_DIS_MOVEFA
2192 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);
2197 static void dsp_opcode_move(void)
2201 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);
2206 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);
2211 static void dsp_opcode_moveq(void)
2213 #ifdef DSP_DIS_MOVEQ
2215 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);
2218 #ifdef DSP_DIS_MOVEQ
2220 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2225 static void dsp_opcode_resmac(void)
2227 #ifdef DSP_DIS_RESMAC
2229 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));
2231 RN = (uint32_t)dsp_acc;
2232 #ifdef DSP_DIS_RESMAC
2234 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2239 static void dsp_opcode_imult(void)
2241 #ifdef DSP_DIS_IMULT
2243 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);
2245 RN = (int16_t)RN * (int16_t)RM;
2247 #ifdef DSP_DIS_IMULT
2249 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);
2254 static void dsp_opcode_mult(void)
2258 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);
2260 RN = (uint16_t)RM * (uint16_t)RN;
2264 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);
2269 static void dsp_opcode_bclr(void)
2273 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);
2275 uint32_t res = RN & ~(1 << IMM_1);
2280 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2285 static void dsp_opcode_btst(void)
2289 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);
2291 dsp_flag_z = (~RN >> IMM_1) & 1;
2294 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2299 static void dsp_opcode_bset(void)
2303 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);
2305 uint32_t res = RN | (1 << IMM_1);
2310 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2315 static void dsp_opcode_subqt(void)
2317 #ifdef DSP_DIS_SUBQT
2319 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);
2321 RN -= dsp_convert_zero[IMM_1];
2322 #ifdef DSP_DIS_SUBQT
2324 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2329 static void dsp_opcode_addqt(void)
2331 #ifdef DSP_DIS_ADDQT
2333 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);
2335 RN += dsp_convert_zero[IMM_1];
2336 #ifdef DSP_DIS_ADDQT
2338 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2343 static void dsp_opcode_imacn(void)
2345 #ifdef DSP_DIS_IMACN
2347 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);
2349 int32_t res = (int16_t)RM * (int16_t)RN;
2350 dsp_acc += (int64_t)res;
2351 //Should we AND the result to fit into 40 bits here???
2352 #ifdef DSP_DIS_IMACN
2354 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));
2359 static void dsp_opcode_mtoi(void)
2361 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2366 static void dsp_opcode_normi(void)
2373 while ((_Rm & 0xffc00000) == 0)
2378 while ((_Rm & 0xff800000) != 0)
2389 static void dsp_opcode_mmult(void)
2391 int count = dsp_matrix_control&0x0f;
2392 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2396 if (!(dsp_matrix_control & 0x10))
2398 for (int i = 0; i < count; i++)
2402 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2404 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2405 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2412 for (int i = 0; i < count; i++)
2416 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2418 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2419 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2424 RN = res = (int32_t)accum;
2426 //NOTE: The flags are set based upon the last add/multiply done...
2431 static void dsp_opcode_abs(void)
2435 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);
2440 if (_Rn == 0x80000000)
2444 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2445 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2450 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2455 static void dsp_opcode_div(void)
2460 if (dsp_div_control & 0x01) // 16.16 division
2462 dsp_remain = ((uint64_t)RN << 16) % RM;
2463 RN = ((uint64_t)RN << 16) / RM;
2467 // We calculate the remainder first because we destroy RN after
2468 // this by assigning it to itself.
2469 dsp_remain = RN % RM;
2476 // This is what happens according to SCPCD. NYAN!
2481 // Real algorithm, courtesy of SCPCD: NYAN!
2485 // If 16.16 division, stuff top 16 bits of RN into remainder and put the
2486 // bottom 16 of RN in top 16 of quotient
2487 if (dsp_div_control & 0x01)
2488 q <<= 16, r = RN >> 16;
2490 for(int i=0; i<32; i++)
2492 // uint32_t sign = (r >> 31) & 0x01;
2493 uint32_t sign = r & 0x80000000;
2494 r = (r << 1) | ((q >> 31) & 0x01);
2495 r += (sign ? RM : -RM);
2496 q = (q << 1) | (((~r) >> 31) & 0x01);
2505 static void dsp_opcode_imultn(void)
2507 #ifdef DSP_DIS_IMULTN
2509 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);
2511 // This is OK, since this multiply won't overflow 32 bits...
2512 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2513 dsp_acc = (int64_t)res;
2515 #ifdef DSP_DIS_IMULTN
2517 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2522 static void dsp_opcode_neg(void)
2526 WriteLog("%06X: NEG R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2529 SET_ZNC_SUB(0, RN, res);
2533 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2538 static void dsp_opcode_shlq(void)
2542 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);
2544 // NB: This instruction is the *only* one that does (32 - immediate data).
2545 int32_t r1 = 32 - IMM_1;
2546 uint32_t res = RN << r1;
2547 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2556 static void dsp_opcode_shrq(void)
2560 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);
2562 int32_t r1 = dsp_convert_zero[IMM_1];
2563 uint32_t res = RN >> r1;
2564 SET_ZN(res); dsp_flag_c = RN & 1;
2568 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_ror(void)
2577 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);
2579 uint32_t r1 = RM & 0x1F;
2580 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2581 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2585 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);
2590 static void dsp_opcode_rorq(void)
2594 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);
2596 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2598 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2600 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2603 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2608 static void dsp_opcode_sha(void)
2610 int32_t sRm=(int32_t)RM;
2615 uint32_t shift=-sRm;
2616 if (shift>=32) shift=32;
2617 dsp_flag_c=(_Rn&0x80000000)>>31;
2627 if (shift>=32) shift=32;
2631 _Rn=((int32_t)_Rn)>>1;
2640 static void dsp_opcode_sharq(void)
2642 #ifdef DSP_DIS_SHARQ
2644 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);
2646 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2647 SET_ZN(res); dsp_flag_c = RN & 0x01;
2649 #ifdef DSP_DIS_SHARQ
2651 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2656 static void dsp_opcode_sh(void)
2658 int32_t sRm=(int32_t)RM;
2663 uint32_t shift=(-sRm);
2664 if (shift>=32) shift=32;
2665 dsp_flag_c=(_Rn&0x80000000)>>31;
2675 if (shift>=32) shift=32;
2687 void dsp_opcode_addqmod(void)
2689 #ifdef DSP_DIS_ADDQMOD
2691 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);
2693 uint32_t r1 = dsp_convert_zero[IMM_1];
2695 uint32_t res = r2 + r1;
2696 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2698 SET_ZNC_ADD(r2, r1, res);
2699 #ifdef DSP_DIS_ADDQMOD
2701 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2705 void dsp_opcode_subqmod(void)
2707 uint32_t r1 = dsp_convert_zero[IMM_1];
2709 uint32_t res = r2 - r1;
2710 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2713 SET_ZNC_SUB(r2, r1, res);
2716 void dsp_opcode_mirror(void)
2719 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2723 void dsp_opcode_sat32s(void)
2725 int32_t r2 = (uint32_t)RN;
2726 int32_t temp = dsp_acc >> 32;
2727 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2732 void dsp_opcode_sat16s(void)
2735 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2740 void dsp_opcode_illegal(void)
2742 // Don't know what it does, but it does *something*...
2743 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);
2747 // New pipelined DSP core
2750 static void DSP_abs(void);
2751 static void DSP_add(void);
2752 static void DSP_addc(void);
2753 static void DSP_addq(void);
2754 static void DSP_addqmod(void);
2755 static void DSP_addqt(void);
2756 static void DSP_and(void);
2757 static void DSP_bclr(void);
2758 static void DSP_bset(void);
2759 static void DSP_btst(void);
2760 static void DSP_cmp(void);
2761 static void DSP_cmpq(void);
2762 static void DSP_div(void);
2763 static void DSP_imacn(void);
2764 static void DSP_imult(void);
2765 static void DSP_imultn(void);
2766 static void DSP_illegal(void);
2767 static void DSP_jr(void);
2768 static void DSP_jump(void);
2769 static void DSP_load(void);
2770 static void DSP_loadb(void);
2771 static void DSP_loadw(void);
2772 static void DSP_load_r14_i(void);
2773 static void DSP_load_r14_r(void);
2774 static void DSP_load_r15_i(void);
2775 static void DSP_load_r15_r(void);
2776 static void DSP_mirror(void);
2777 static void DSP_mmult(void);
2778 static void DSP_move(void);
2779 static void DSP_movefa(void);
2780 static void DSP_movei(void);
2781 static void DSP_movepc(void);
2782 static void DSP_moveq(void);
2783 static void DSP_moveta(void);
2784 static void DSP_mtoi(void);
2785 static void DSP_mult(void);
2786 static void DSP_neg(void);
2787 static void DSP_nop(void);
2788 static void DSP_normi(void);
2789 static void DSP_not(void);
2790 static void DSP_or(void);
2791 static void DSP_resmac(void);
2792 static void DSP_ror(void);
2793 static void DSP_rorq(void);
2794 static void DSP_sat16s(void);
2795 static void DSP_sat32s(void);
2796 static void DSP_sh(void);
2797 static void DSP_sha(void);
2798 static void DSP_sharq(void);
2799 static void DSP_shlq(void);
2800 static void DSP_shrq(void);
2801 static void DSP_store(void);
2802 static void DSP_storeb(void);
2803 static void DSP_storew(void);
2804 static void DSP_store_r14_i(void);
2805 static void DSP_store_r14_r(void);
2806 static void DSP_store_r15_i(void);
2807 static void DSP_store_r15_r(void);
2808 static void DSP_sub(void);
2809 static void DSP_subc(void);
2810 static void DSP_subq(void);
2811 static void DSP_subqmod(void);
2812 static void DSP_subqt(void);
2813 static void DSP_xor(void);
2815 void (* DSPOpcode[64])() =
2817 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2818 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2819 DSP_neg, DSP_and, DSP_or, DSP_xor,
2820 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2822 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2823 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2824 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2825 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2827 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2828 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2829 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2830 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2832 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2833 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2834 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2835 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2838 bool readAffected[64][2] =
2840 { true, true}, { true, true}, {false, true}, {false, true},
2841 { true, true}, { true, true}, {false, true}, {false, true},
2842 {false, true}, { true, true}, { true, true}, { true, true},
2843 {false, true}, {false, true}, {false, true}, {false, true},
2845 { true, true}, { true, true}, { true, true}, {false, true},
2846 { true, true}, { true, true}, {false, true}, { true, true},
2847 {false, true}, {false, true}, { true, true}, {false, true},
2848 { true, true}, {false, true}, { true, true}, {false, true},
2850 {false, true}, {false, true}, { true, false}, {false, false},
2851 { true, false}, {false, false}, {false, false}, { true, false},
2852 { true, false}, { true, false}, {false, true}, { true, false},
2853 { true, false}, { true, true}, { true, true}, { true, true},
2855 {false, true}, { true, true}, { true, true}, {false, true},
2856 { true, false}, { true, false}, { true, true}, { true, false},
2857 { true, false}, {false, false}, { true, false}, { true, false},
2858 { true, true}, { true, true}, {false, false}, {false, true}
2861 bool isLoadStore[65] =
2863 false, false, false, false, false, false, false, false,
2864 false, false, false, false, false, false, false, false,
2866 false, false, false, false, false, false, false, false,
2867 false, false, false, false, false, false, false, false,
2869 false, false, false, false, false, false, false, true,
2870 true, true, false, true, true, true, true, true,
2872 false, true, true, false, false, false, false, false,
2873 false, false, true, true, true, true, false, false, false
2876 void FlushDSPPipeline(void)
2878 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2880 for(int i=0; i<4; i++)
2881 pipeline[i].opcode = PIPELINE_STALL;
2883 for(int i=0; i<32; i++)
2888 // New pipelined DSP execution core
2890 /*void DSPExecP(int32_t cycles)
2892 // bool inhibitFetch = false;
2894 dsp_releaseTimeSlice_flag = 0;
2897 while (cycles > 0 && DSP_RUNNING)
2899 WriteLog("DSPExecP: Pipeline status...\n");
2900 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);
2901 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);
2902 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);
2903 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);
2904 WriteLog(" --> Scoreboard: ");
2905 for(int i=0; i<32; i++)
2906 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2908 // Stage 1: Instruction fetch
2909 // if (!inhibitFetch)
2911 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2912 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2913 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2914 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2915 if (pipeline[plPtrFetch].opcode == 38)
2916 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2917 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2920 // inhibitFetch = false;
2921 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2923 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2924 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);
2925 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);
2926 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);
2927 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);
2928 // Stage 2: Read registers
2929 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2930 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2931 if (scoreboard[pipeline[plPtrRead].operand2])
2932 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2933 // We have a hit in the scoreboard, so we have to stall the pipeline...
2935 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2936 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2937 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2938 pipeline[plPtrFetch] = pipeline[plPtrRead];
2939 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2943 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2944 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2945 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2947 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2948 // Shouldn't we be more selective with the register scoreboarding?
2949 // Yes, we should. !!! FIX !!!
2950 scoreboard[pipeline[plPtrRead].operand2] = true;
2951 //Advance PC here??? Yes.
2952 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2953 //This is a mangling of the pipeline stages, but what else to do???
2954 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2957 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2958 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);
2959 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);
2960 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);
2961 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);
2963 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2965 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2966 DSPOpcode[pipeline[plPtrExec].opcode]();
2967 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2968 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2973 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2974 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2975 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2976 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2977 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2978 // Stage 4: Write back register
2979 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2981 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2982 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2984 scoreboard[pipeline[plPtrWrite].operand1]
2985 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2988 // Push instructions through the pipeline...
2989 plPtrFetch = (++plPtrFetch) & 0x03;
2990 plPtrRead = (++plPtrRead) & 0x03;
2991 plPtrExec = (++plPtrExec) & 0x03;
2992 plPtrWrite = (++plPtrWrite) & 0x03;
2999 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3001 // Should be fixed now. Another problem is figuring how to do the sequence following
3002 // a branch followed with the JR & JUMP instructions...
3004 // There are two conflicting problems:
3007 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3008 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3009 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3010 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3011 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3012 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3013 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3014 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3015 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3016 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3017 DSP: Finished interrupt.
3018 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3019 ; bank 0 (where is was prepared)!
3020 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3021 F1B252: NOP [NCZ:001]
3024 // The other is when you see this at the end of an IRQ:
3027 JUMP T, (R29) ; R29 = Previous stack + 2
3028 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3030 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3031 ; 1) The STORE goes through the pipeline and is executed/written back
3032 ; 2) The pipeline is flushed
3033 ; 3) The DSP_PC is set to the new address
3034 ; 4) Execution resumes
3036 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3037 ; bank 0 instead of the current bank 1 and so goes astray!
3040 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3041 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3045 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3046 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3047 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3048 If it were done properly, the STORE write back would occur *after* (well, technically,
3049 during) the execution of the the JUMP that follows it.
3053 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3054 F1B08A: NOP [NCZ:001]
3056 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3059 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3062 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3063 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3064 F1B08A: NOP [NCZ:001]
3066 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3069 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3070 DSP: CPU -> DSP interrupt
3071 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3072 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3074 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3077 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3078 F1B006: NOP [NCZ:001]
3080 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3083 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3084 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3087 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3088 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3091 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3092 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3095 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3096 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3099 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3102 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3105 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3106 F1B0FE: NOP [NCZ:000]
3108 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3111 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3114 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3115 F1B138: NOP [NCZ:000]
3117 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3120 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3121 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3122 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3125 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3126 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3129 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3130 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3131 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3133 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3134 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3137 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3138 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3139 DSP: Finished interrupt.
3140 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3142 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3145 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3146 F1B016: NOP [NCZ:001]
3148 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3151 uint32_t pcQueue1[0x400];
3152 uint32_t pcQPtr1 = 0;
3153 static uint32_t prevR1;
3154 //Let's try a 3 stage pipeline....
3155 //Looks like 3 stage is correct, otherwise bad things happen...
3156 void DSPExecP2(int32_t cycles)
3158 dsp_releaseTimeSlice_flag = 0;
3161 while (cycles > 0 && DSP_RUNNING)
3163 /*extern uint32_t totalFrames;
3164 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3165 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3166 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3168 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3171 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3173 if (dsp_pc == 0xF1B092)
3174 doDSPDis = false;//*/
3175 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3176 doDSPDis = true;//*/
3177 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3178 doDSPDis = true;//*/
3179 /*if (dsp_pc == 0xF1B0A0)
3180 doDSPDis = true;//*/
3181 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3182 doDSPDis = true;//*/
3183 //Two parter... (not sure how to write this)
3184 //if (dsp_pc == 0xF1B0D2)
3185 // prevR1 = dsp_reg[1];
3187 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3188 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3191 pcQueue1[pcQPtr1++] = dsp_pc;
3194 #ifdef DSP_DEBUG_PL2
3195 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3197 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3202 for(int i=0; i<0x400; i++)
3204 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3205 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3211 if (IMASKCleared) // If IMASK was cleared,
3213 #ifdef DSP_DEBUG_IRQ
3214 WriteLog("DSP: Finished interrupt.\n");
3216 DSPHandleIRQs(); // See if any other interrupts are pending!
3217 IMASKCleared = false;
3220 //if (dsp_flags & REGPAGE)
3221 // WriteLog(" --> REGPAGE has just been set!\n");
3222 #ifdef DSP_DEBUG_PL2
3225 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3226 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]);
3227 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]);
3228 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 WriteLog(" --> Scoreboard: ");
3230 for(int i=0; i<32; i++)
3231 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3235 // Stage 1a: Instruction fetch
3236 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3237 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3238 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3239 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3240 if (pipeline[plPtrRead].opcode == 38)
3241 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3242 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3243 #ifdef DSP_DEBUG_PL2
3246 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3247 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3248 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]);
3249 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]);
3250 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]);
3253 // Stage 1b: Read registers
3254 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3255 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3257 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3258 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3259 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3260 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3261 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3262 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3263 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3265 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3266 // We have a hit in the scoreboard, so we have to stall the pipeline...
3267 #ifdef DSP_DEBUG_PL2
3271 WriteLog(" --> Stalling pipeline: ");
3272 if (readAffected[pipeline[plPtrRead].opcode][0])
3273 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3274 if (readAffected[pipeline[plPtrRead].opcode][1])
3275 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3279 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3280 #ifdef DSP_DEBUG_PL2
3285 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3286 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3287 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3289 // Shouldn't we be more selective with the register scoreboarding?
3290 // Yes, we should. !!! FIX !!! Kinda [DONE]
3291 #ifndef NEW_SCOREBOARD
3292 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3294 //Hopefully this will fix the dual MOVEQ # problem...
3295 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3298 //Advance PC here??? Yes.
3299 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3302 #ifdef DSP_DEBUG_PL2
3305 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3306 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]);
3307 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]);
3308 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]);
3312 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3314 #ifdef DSP_DEBUG_PL2
3316 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"));
3320 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3325 lastExec = pipeline[plPtrExec].instruction;
3326 //WriteLog("[lastExec = %04X]\n", lastExec);
3328 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3329 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3330 DSPOpcode[pipeline[plPtrExec].opcode]();
3331 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3335 //Let's not, until we do the stalling correctly...
3336 //But, we gotta while we're doing the comparison core...!
3337 //Or do we? cycles--;
3338 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3339 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3340 //to model this clock cycle behavior correctly...
3341 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3342 //don't affect the reads at stage 1...
3343 #ifdef DSP_DEBUG_STALL
3345 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3349 #ifdef DSP_DEBUG_PL2
3352 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3353 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]);
3354 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]);
3355 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]);
3359 // Stage 3: Write back register/memory address
3360 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3362 /*if (pipeline[plPtrWrite].writebackRegister == 3
3363 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3366 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3369 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3371 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3372 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3375 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3376 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3377 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3378 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3380 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3384 #ifndef NEW_SCOREBOARD
3385 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3386 scoreboard[pipeline[plPtrWrite].operand2] = false;
3388 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3389 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3390 if (scoreboard[pipeline[plPtrWrite].operand2])
3391 scoreboard[pipeline[plPtrWrite].operand2]--;
3395 // Push instructions through the pipeline...
3396 plPtrRead = (++plPtrRead) & 0x03;
3397 plPtrExec = (++plPtrExec) & 0x03;
3398 plPtrWrite = (++plPtrWrite) & 0x03;
3407 //#define DSP_DEBUG_PL3
3408 //Let's try a 2 stage pipeline....
3409 void DSPExecP3(int32_t cycles)
3411 dsp_releaseTimeSlice_flag = 0;
3414 while (cycles > 0 && DSP_RUNNING)
3416 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3418 #ifdef DSP_DEBUG_PL3
3419 WriteLog("DSPExecP: Pipeline status...\n");
3420 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]);
3421 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]);
3422 WriteLog(" --> Scoreboard: ");
3423 for(int i=0; i<32; i++)
3424 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3427 // Stage 1a: Instruction fetch
3428 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3429 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3430 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3431 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3432 if (pipeline[plPtrRead].opcode == 38)
3433 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3434 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3435 #ifdef DSP_DEBUG_PL3
3436 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3437 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3438 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]);
3439 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]);
3441 // Stage 1b: Read registers
3442 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3443 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3444 // We have a hit in the scoreboard, so we have to stall the pipeline...
3445 #ifdef DSP_DEBUG_PL3
3447 WriteLog(" --> Stalling pipeline: ");
3448 if (readAffected[pipeline[plPtrRead].opcode][0])
3449 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3450 if (readAffected[pipeline[plPtrRead].opcode][1])
3451 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3454 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3455 #ifdef DSP_DEBUG_PL3
3460 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3461 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3462 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3464 // Shouldn't we be more selective with the register scoreboarding?
3465 // Yes, we should. !!! FIX !!! [Kinda DONE]
3466 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3468 //Advance PC here??? Yes.
3469 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3472 #ifdef DSP_DEBUG_PL3
3473 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3474 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]);
3475 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]);
3477 // Stage 2a: Execute
3478 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3480 #ifdef DSP_DEBUG_PL3
3481 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3483 DSPOpcode[pipeline[plPtrExec].opcode]();
3484 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3485 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3490 #ifdef DSP_DEBUG_PL3
3491 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3492 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]);
3493 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]);
3496 // Stage 2b: Write back register
3497 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3499 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3500 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3502 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3503 scoreboard[pipeline[plPtrExec].operand2] = false;
3506 // Push instructions through the pipeline...
3507 plPtrRead = (++plPtrRead) & 0x03;
3508 plPtrExec = (++plPtrExec) & 0x03;
3515 // DSP pipelined opcode handlers
3518 #define PRM pipeline[plPtrExec].reg1
3519 #define PRN pipeline[plPtrExec].reg2
3520 #define PIMM1 pipeline[plPtrExec].operand1
3521 #define PIMM2 pipeline[plPtrExec].operand2
3522 #define PRES pipeline[plPtrExec].result
3523 #define PWBR pipeline[plPtrExec].writebackRegister
3524 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3525 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3526 #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))
3527 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3529 static void DSP_abs(void)
3533 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);
3537 if (_Rn == 0x80000000)
3541 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3542 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3543 CLR_ZN; SET_Z(PRES);
3547 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3551 static void DSP_add(void)
3555 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);
3557 uint32_t res = PRN + PRM;
3558 SET_ZNC_ADD(PRN, PRM, res);
3562 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);
3566 static void DSP_addc(void)
3570 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);
3572 uint32_t res = PRN + PRM + dsp_flag_c;
3573 uint32_t carry = dsp_flag_c;
3574 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3575 SET_ZNC_ADD(PRN + carry, PRM, res);
3576 // SET_ZNC_ADD(PRN, PRM + carry, res);
3580 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);
3584 static void DSP_addq(void)
3588 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);
3590 uint32_t r1 = dsp_convert_zero[PIMM1];
3591 uint32_t res = PRN + r1;
3592 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3596 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3600 static void DSP_addqmod(void)
3602 #ifdef DSP_DIS_ADDQMOD
3604 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);
3606 uint32_t r1 = dsp_convert_zero[PIMM1];
3608 uint32_t res = r2 + r1;
3609 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3611 SET_ZNC_ADD(r2, r1, res);
3612 #ifdef DSP_DIS_ADDQMOD
3614 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3618 static void DSP_addqt(void)
3620 #ifdef DSP_DIS_ADDQT
3622 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);
3624 PRES = PRN + dsp_convert_zero[PIMM1];
3625 #ifdef DSP_DIS_ADDQT
3627 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3631 static void DSP_and(void)
3635 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);
3641 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);
3645 static void DSP_bclr(void)
3649 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);
3651 PRES = PRN & ~(1 << PIMM1);
3655 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3659 static void DSP_bset(void)
3663 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);
3665 PRES = PRN | (1 << PIMM1);
3669 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3673 static void DSP_btst(void)
3677 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);
3679 dsp_flag_z = (~PRN >> PIMM1) & 1;
3683 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3687 static void DSP_cmp(void)
3691 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);
3693 uint32_t res = PRN - PRM;
3694 SET_ZNC_SUB(PRN, PRM, res);
3698 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3702 static void DSP_cmpq(void)
3704 static int32_t sqtable[32] =
3705 { 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 };
3708 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);
3710 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3711 uint32_t res = PRN - r1;
3712 SET_ZNC_SUB(PRN, r1, res);
3716 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3720 static void DSP_div(void)
3722 uint32_t _Rm = PRM, _Rn = PRN;
3726 if (dsp_div_control & 1)
3728 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3729 if (dsp_remain & 0x80000000)
3731 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3735 dsp_remain = _Rn % _Rm;
3736 if (dsp_remain & 0x80000000)
3745 static void DSP_imacn(void)
3747 #ifdef DSP_DIS_IMACN
3749 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);
3751 int32_t res = (int16_t)PRM * (int16_t)PRN;
3752 dsp_acc += (int64_t)res;
3753 //Should we AND the result to fit into 40 bits here???
3755 #ifdef DSP_DIS_IMACN
3757 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));
3761 static void DSP_imult(void)
3763 #ifdef DSP_DIS_IMULT
3765 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);
3767 PRES = (int16_t)PRN * (int16_t)PRM;
3769 #ifdef DSP_DIS_IMULT
3771 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);
3775 static void DSP_imultn(void)
3777 #ifdef DSP_DIS_IMULTN
3779 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);
3781 // This is OK, since this multiply won't overflow 32 bits...
3782 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3783 dsp_acc = (int64_t)res;
3786 #ifdef DSP_DIS_IMULTN
3788 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));
3792 static void DSP_illegal(void)
3794 #ifdef DSP_DIS_ILLEGAL
3796 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3801 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3802 // can cause trouble because an interrupt can occur *before* the instruction following the
3803 // jump can execute... !!! FIX !!!
3804 // This can probably be solved by judicious coding in the pipeline execution core...
3805 // And should be fixed now...
3806 static void DSP_jr(void)
3809 const char * condition[32] =
3810 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3811 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3812 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3813 "???", "???", "???", "F" };
3815 //How come this is always off by 2???
3816 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);
3818 // KLUDGE: Used by BRANCH_CONDITION macro
3819 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3821 if (BRANCH_CONDITION(PIMM2))
3825 WriteLog("Branched!\n");
3827 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3828 //Account for pipeline effects...
3829 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3830 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3832 // Now that we've branched, we have to make sure that the following instruction
3833 // is executed atomically with this one and then flush the pipeline before setting
3836 // Step 1: Handle writebacks at stage 3 of pipeline
3837 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3839 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3840 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3842 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3843 scoreboard[pipeline[plPtrWrite].operand2] = false;
3845 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3847 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3849 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3850 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3853 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3854 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3855 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3856 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3858 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3862 #ifndef NEW_SCOREBOARD
3863 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3864 scoreboard[pipeline[plPtrWrite].operand2] = false;
3866 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3867 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3868 if (scoreboard[pipeline[plPtrWrite].operand2])
3869 scoreboard[pipeline[plPtrWrite].operand2]--;
3873 // Step 2: Push instruction through pipeline & execute following instruction
3874 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3875 // we effectively handle the final push of the instruction through the
3876 // pipeline when the new PC takes effect (since when we return, the
3877 // pipeline code will be executing the writeback stage. If we reverse
3878 // the execution order of the pipeline stages, this will no longer be
3880 pipeline[plPtrExec] = pipeline[plPtrRead];
3881 //This is BAD. We need to get that next opcode and execute it!
3882 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3883 // remove this crap.
3884 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3886 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3887 pipeline[plPtrExec].opcode = instruction >> 10;
3888 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3889 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3890 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3891 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3892 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3894 dsp_pc += 2; // For DSP_DIS_* accuracy
3895 DSPOpcode[pipeline[plPtrExec].opcode]();
3896 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3897 pipeline[plPtrWrite] = pipeline[plPtrExec];
3899 // Step 3: Flush pipeline & set new PC
3900 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3907 WriteLog("Branch NOT taken.\n");
3913 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3916 static void DSP_jump(void)
3919 const char * condition[32] =
3920 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3921 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3922 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3923 "???", "???", "???", "F" };
3925 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);
3927 // KLUDGE: Used by BRANCH_CONDITION macro
3928 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3930 if (BRANCH_CONDITION(PIMM2))
3934 WriteLog("Branched!\n");
3936 uint32_t PCSave = PRM;
3937 // Now that we've branched, we have to make sure that the following instruction
3938 // is executed atomically with this one and then flush the pipeline before setting
3941 // Step 1: Handle writebacks at stage 3 of pipeline
3942 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3944 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3945 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3947 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3948 scoreboard[pipeline[plPtrWrite].operand2] = false;
3950 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3952 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3954 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3955 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3958 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3959 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3960 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3961 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3963 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3967 #ifndef NEW_SCOREBOARD
3968 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3969 scoreboard[pipeline[plPtrWrite].operand2] = false;
3971 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3972 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3973 if (scoreboard[pipeline[plPtrWrite].operand2])
3974 scoreboard[pipeline[plPtrWrite].operand2]--;
3978 // Step 2: Push instruction through pipeline & execute following instruction
3979 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3980 // we effectively handle the final push of the instruction through the
3981 // pipeline when the new PC takes effect (since when we return, the
3982 // pipeline code will be executing the writeback stage. If we reverse
3983 // the execution order of the pipeline stages, this will no longer be
3985 pipeline[plPtrExec] = pipeline[plPtrRead];
3986 //This is BAD. We need to get that next opcode and execute it!
3987 //Also, same problem in JR!
3988 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3989 // remove this crap.
3990 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3992 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3993 pipeline[plPtrExec].opcode = instruction >> 10;
3994 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3995 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3996 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3997 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3998 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4000 dsp_pc += 2; // For DSP_DIS_* accuracy
4001 DSPOpcode[pipeline[plPtrExec].opcode]();
4002 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4003 pipeline[plPtrWrite] = pipeline[plPtrExec];
4005 // Step 3: Flush pipeline & set new PC
4006 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4013 WriteLog("Branch NOT taken.\n");
4021 static void DSP_load(void)
4025 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);
4027 #ifdef DSP_CORRECT_ALIGNMENT
4028 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4030 PRES = DSPReadLong(PRM, DSP);
4034 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4038 static void DSP_loadb(void)
4040 #ifdef DSP_DIS_LOADB
4042 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);
4044 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4045 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4047 PRES = JaguarReadByte(PRM, DSP);
4048 #ifdef DSP_DIS_LOADB
4050 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4054 static void DSP_loadw(void)
4056 #ifdef DSP_DIS_LOADW
4058 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);
4060 #ifdef DSP_CORRECT_ALIGNMENT
4061 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4062 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4064 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4066 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4067 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4069 PRES = JaguarReadWord(PRM, DSP);
4071 #ifdef DSP_DIS_LOADW
4073 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4077 static void DSP_load_r14_i(void)
4079 #ifdef DSP_DIS_LOAD14I
4081 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);
4083 #ifdef DSP_CORRECT_ALIGNMENT
4084 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4086 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4088 #ifdef DSP_DIS_LOAD14I
4090 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4094 static void DSP_load_r14_r(void)
4096 #ifdef DSP_DIS_LOAD14R
4098 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);
4100 #ifdef DSP_CORRECT_ALIGNMENT
4101 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4103 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4105 #ifdef DSP_DIS_LOAD14R
4107 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4111 static void DSP_load_r15_i(void)
4113 #ifdef DSP_DIS_LOAD15I
4115 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);
4117 #ifdef DSP_CORRECT_ALIGNMENT
4118 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4120 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4122 #ifdef DSP_DIS_LOAD15I
4124 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4128 static void DSP_load_r15_r(void)
4130 #ifdef DSP_DIS_LOAD15R
4132 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);
4134 #ifdef DSP_CORRECT_ALIGNMENT
4135 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4137 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4139 #ifdef DSP_DIS_LOAD15R
4141 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4145 static void DSP_mirror(void)
4148 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4152 static void DSP_mmult(void)
4154 int count = dsp_matrix_control&0x0f;
4155 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4159 if (!(dsp_matrix_control & 0x10))
4161 for (int i = 0; i < count; i++)
4165 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4167 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4168 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4175 for (int i = 0; i < count; i++)
4179 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4181 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4182 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4188 PRES = res = (int32_t)accum;
4190 //NOTE: The flags are set based upon the last add/multiply done...
4194 static void DSP_move(void)
4198 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);
4203 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);
4207 static void DSP_movefa(void)
4209 #ifdef DSP_DIS_MOVEFA
4211 // 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);
4212 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);
4214 // PRES = ALTERNATE_RM;
4215 PRES = dsp_alternate_reg[PIMM1];
4216 #ifdef DSP_DIS_MOVEFA
4218 // 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);
4219 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);
4223 static void DSP_movei(void)
4225 #ifdef DSP_DIS_MOVEI
4227 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);
4229 // // This instruction is followed by 32-bit value in LSW / MSW format...
4230 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4232 #ifdef DSP_DIS_MOVEI
4234 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4238 static void DSP_movepc(void)
4240 #ifdef DSP_DIS_MOVEPC
4242 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);
4244 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4245 // PRES = dsp_pc - 2;
4246 //Account for pipeline effects...
4247 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4248 #ifdef DSP_DIS_MOVEPC
4250 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4254 static void DSP_moveq(void)
4256 #ifdef DSP_DIS_MOVEQ
4258 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);
4261 #ifdef DSP_DIS_MOVEQ
4263 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4267 static void DSP_moveta(void)
4269 #ifdef DSP_DIS_MOVETA
4271 // 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);
4272 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]);
4274 // ALTERNATE_RN = PRM;
4275 dsp_alternate_reg[PIMM2] = PRM;
4277 #ifdef DSP_DIS_MOVETA
4279 // 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);
4280 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]);
4284 static void DSP_mtoi(void)
4286 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4290 static void DSP_mult(void)
4294 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);
4296 PRES = (uint16_t)PRM * (uint16_t)PRN;
4300 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);
4304 static void DSP_neg(void)
4308 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);
4310 uint32_t res = -PRN;
4311 SET_ZNC_SUB(0, PRN, res);
4315 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4319 static void DSP_nop(void)
4323 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4328 static void DSP_normi(void)
4335 while ((_Rm & 0xffc00000) == 0)
4340 while ((_Rm & 0xff800000) != 0)
4350 static void DSP_not(void)
4354 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);
4360 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4364 static void DSP_or(void)
4368 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);
4374 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);
4378 static void DSP_resmac(void)
4380 #ifdef DSP_DIS_RESMAC
4382 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));
4384 PRES = (uint32_t)dsp_acc;
4385 #ifdef DSP_DIS_RESMAC
4387 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4391 static void DSP_ror(void)
4395 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);
4397 uint32_t r1 = PRM & 0x1F;
4398 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4399 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4403 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);
4407 static void DSP_rorq(void)
4411 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);
4413 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4415 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4417 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4420 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4424 static void DSP_sat16s(void)
4427 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4432 static void DSP_sat32s(void)
4434 int32_t r2 = (uint32_t)PRN;
4435 int32_t temp = dsp_acc >> 32;
4436 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4441 static void DSP_sh(void)
4443 int32_t sRm = (int32_t)PRM;
4448 uint32_t shift = -sRm;
4453 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4463 uint32_t shift = sRm;
4468 dsp_flag_c = _Rn & 0x1;
4481 static void DSP_sha(void)
4483 int32_t sRm = (int32_t)PRM;
4488 uint32_t shift = -sRm;
4493 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4503 uint32_t shift = sRm;
4508 dsp_flag_c = _Rn & 0x1;
4512 _Rn = ((int32_t)_Rn) >> 1;
4521 static void DSP_sharq(void)
4523 #ifdef DSP_DIS_SHARQ
4525 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);
4527 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4528 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4530 #ifdef DSP_DIS_SHARQ
4532 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4536 static void DSP_shlq(void)
4540 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);
4542 int32_t r1 = 32 - PIMM1;
4543 uint32_t res = PRN << r1;
4544 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4548 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4552 static void DSP_shrq(void)
4556 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);
4558 int32_t r1 = dsp_convert_zero[PIMM1];
4559 uint32_t res = PRN >> r1;
4560 SET_ZN(res); dsp_flag_c = PRN & 1;
4564 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4568 static void DSP_store(void)
4570 #ifdef DSP_DIS_STORE
4572 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);
4574 // DSPWriteLong(PRM, PRN, DSP);
4576 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4577 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4579 pipeline[plPtrExec].address = PRM;
4581 pipeline[plPtrExec].value = PRN;
4582 pipeline[plPtrExec].type = TYPE_DWORD;
4586 static void DSP_storeb(void)
4588 #ifdef DSP_DIS_STOREB
4590 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);
4592 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4593 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4595 // JaguarWriteByte(PRM, PRN, DSP);
4598 pipeline[plPtrExec].address = PRM;
4600 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4602 pipeline[plPtrExec].value = PRN & 0xFF;
4603 pipeline[plPtrExec].type = TYPE_DWORD;
4607 pipeline[plPtrExec].value = PRN;
4608 pipeline[plPtrExec].type = TYPE_BYTE;
4614 static void DSP_storew(void)
4616 #ifdef DSP_DIS_STOREW
4618 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);
4620 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4621 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4623 // JaguarWriteWord(PRM, PRN, DSP);
4626 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4627 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4629 pipeline[plPtrExec].address = PRM;
4632 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4634 pipeline[plPtrExec].value = PRN & 0xFFFF;
4635 pipeline[plPtrExec].type = TYPE_DWORD;
4639 pipeline[plPtrExec].value = PRN;
4640 pipeline[plPtrExec].type = TYPE_WORD;
4645 static void DSP_store_r14_i(void)
4647 #ifdef DSP_DIS_STORE14I
4649 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));
4651 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4653 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4654 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4656 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4658 pipeline[plPtrExec].value = PRN;
4659 pipeline[plPtrExec].type = TYPE_DWORD;
4663 static void DSP_store_r14_r(void)
4665 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4667 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4668 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4670 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4672 pipeline[plPtrExec].value = PRN;
4673 pipeline[plPtrExec].type = TYPE_DWORD;
4677 static void DSP_store_r15_i(void)
4679 #ifdef DSP_DIS_STORE15I
4681 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));
4683 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4685 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4686 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4688 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4690 pipeline[plPtrExec].value = PRN;
4691 pipeline[plPtrExec].type = TYPE_DWORD;
4695 static void DSP_store_r15_r(void)
4697 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4699 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4700 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4702 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4704 pipeline[plPtrExec].value = PRN;
4705 pipeline[plPtrExec].type = TYPE_DWORD;
4709 static void DSP_sub(void)
4713 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);
4715 uint32_t res = PRN - PRM;
4716 SET_ZNC_SUB(PRN, PRM, res);
4720 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);
4724 static void DSP_subc(void)
4728 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);
4730 uint32_t res = PRN - PRM - dsp_flag_c;
4731 uint32_t borrow = dsp_flag_c;
4732 SET_ZNC_SUB(PRN - borrow, PRM, res);
4736 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
4740 static void DSP_subq(void)
4744 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);
4746 uint32_t r1 = dsp_convert_zero[PIMM1];
4747 uint32_t res = PRN - r1;
4748 SET_ZNC_SUB(PRN, r1, res);
4752 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4756 static void DSP_subqmod(void)
4758 uint32_t r1 = dsp_convert_zero[PIMM1];
4760 uint32_t res = r2 - r1;
4761 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4763 SET_ZNC_SUB(r2, r1, res);
4766 static void DSP_subqt(void)
4768 #ifdef DSP_DIS_SUBQT
4770 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);
4772 PRES = PRN - dsp_convert_zero[PIMM1];
4773 #ifdef DSP_DIS_SUBQT
4775 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4779 static void DSP_xor(void)
4783 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);
4789 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);