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)
2463 if (dsp_div_control & 1)
2465 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2466 if (dsp_remain&0x80000000)
2468 RN = (((uint64_t)_Rn) << 16) / _Rm;
2472 dsp_remain = _Rn % _Rm;
2473 if (dsp_remain&0x80000000)
2483 if (dsp_div_control & 0x01) // 16.16 division
2485 dsp_remain = ((uint64_t)RN << 16) % RM;
2486 RN = ((uint64_t)RN << 16) / RM;
2490 // We calculate the remainder first because we destroy RN after
2491 // this by assigning it to itself.
2492 dsp_remain = RN % RM;
2496 // What we really should do here is figure out why this condition
2497 // happens in the real divide unit and emulate *that* behavior.
2499 if ((gpu_remain - RM) & 0x80000000) // If the result would have been negative...
2500 gpu_remain -= RM; // Then make it negative!
2509 static void dsp_opcode_imultn(void)
2511 #ifdef DSP_DIS_IMULTN
2513 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);
2515 // This is OK, since this multiply won't overflow 32 bits...
2516 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2517 dsp_acc = (int64_t)res;
2519 #ifdef DSP_DIS_IMULTN
2521 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));
2526 static void dsp_opcode_neg(void)
2530 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);
2533 SET_ZNC_SUB(0, RN, res);
2537 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2542 static void dsp_opcode_shlq(void)
2546 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);
2548 // NB: This instruction is the *only* one that does (32 - immediate data).
2549 int32_t r1 = 32 - IMM_1;
2550 uint32_t res = RN << r1;
2551 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2555 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2560 static void dsp_opcode_shrq(void)
2564 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);
2566 int32_t r1 = dsp_convert_zero[IMM_1];
2567 uint32_t res = RN >> r1;
2568 SET_ZN(res); dsp_flag_c = RN & 1;
2572 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2577 static void dsp_opcode_ror(void)
2581 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);
2583 uint32_t r1 = RM & 0x1F;
2584 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2585 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2589 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);
2594 static void dsp_opcode_rorq(void)
2598 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);
2600 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2602 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2604 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2607 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2612 static void dsp_opcode_sha(void)
2614 int32_t sRm=(int32_t)RM;
2619 uint32_t shift=-sRm;
2620 if (shift>=32) shift=32;
2621 dsp_flag_c=(_Rn&0x80000000)>>31;
2631 if (shift>=32) shift=32;
2635 _Rn=((int32_t)_Rn)>>1;
2644 static void dsp_opcode_sharq(void)
2646 #ifdef DSP_DIS_SHARQ
2648 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);
2650 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2651 SET_ZN(res); dsp_flag_c = RN & 0x01;
2653 #ifdef DSP_DIS_SHARQ
2655 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2660 static void dsp_opcode_sh(void)
2662 int32_t sRm=(int32_t)RM;
2667 uint32_t shift=(-sRm);
2668 if (shift>=32) shift=32;
2669 dsp_flag_c=(_Rn&0x80000000)>>31;
2679 if (shift>=32) shift=32;
2691 void dsp_opcode_addqmod(void)
2693 #ifdef DSP_DIS_ADDQMOD
2695 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);
2697 uint32_t r1 = dsp_convert_zero[IMM_1];
2699 uint32_t res = r2 + r1;
2700 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2702 SET_ZNC_ADD(r2, r1, res);
2703 #ifdef DSP_DIS_ADDQMOD
2705 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2709 void dsp_opcode_subqmod(void)
2711 uint32_t r1 = dsp_convert_zero[IMM_1];
2713 uint32_t res = r2 - r1;
2714 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2717 SET_ZNC_SUB(r2, r1, res);
2720 void dsp_opcode_mirror(void)
2723 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2727 void dsp_opcode_sat32s(void)
2729 int32_t r2 = (uint32_t)RN;
2730 int32_t temp = dsp_acc >> 32;
2731 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2736 void dsp_opcode_sat16s(void)
2739 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2744 void dsp_opcode_illegal(void)
2746 // Don't know what it does, but it does *something*...
2747 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);
2751 // New pipelined DSP core
2754 static void DSP_abs(void);
2755 static void DSP_add(void);
2756 static void DSP_addc(void);
2757 static void DSP_addq(void);
2758 static void DSP_addqmod(void);
2759 static void DSP_addqt(void);
2760 static void DSP_and(void);
2761 static void DSP_bclr(void);
2762 static void DSP_bset(void);
2763 static void DSP_btst(void);
2764 static void DSP_cmp(void);
2765 static void DSP_cmpq(void);
2766 static void DSP_div(void);
2767 static void DSP_imacn(void);
2768 static void DSP_imult(void);
2769 static void DSP_imultn(void);
2770 static void DSP_illegal(void);
2771 static void DSP_jr(void);
2772 static void DSP_jump(void);
2773 static void DSP_load(void);
2774 static void DSP_loadb(void);
2775 static void DSP_loadw(void);
2776 static void DSP_load_r14_i(void);
2777 static void DSP_load_r14_r(void);
2778 static void DSP_load_r15_i(void);
2779 static void DSP_load_r15_r(void);
2780 static void DSP_mirror(void);
2781 static void DSP_mmult(void);
2782 static void DSP_move(void);
2783 static void DSP_movefa(void);
2784 static void DSP_movei(void);
2785 static void DSP_movepc(void);
2786 static void DSP_moveq(void);
2787 static void DSP_moveta(void);
2788 static void DSP_mtoi(void);
2789 static void DSP_mult(void);
2790 static void DSP_neg(void);
2791 static void DSP_nop(void);
2792 static void DSP_normi(void);
2793 static void DSP_not(void);
2794 static void DSP_or(void);
2795 static void DSP_resmac(void);
2796 static void DSP_ror(void);
2797 static void DSP_rorq(void);
2798 static void DSP_sat16s(void);
2799 static void DSP_sat32s(void);
2800 static void DSP_sh(void);
2801 static void DSP_sha(void);
2802 static void DSP_sharq(void);
2803 static void DSP_shlq(void);
2804 static void DSP_shrq(void);
2805 static void DSP_store(void);
2806 static void DSP_storeb(void);
2807 static void DSP_storew(void);
2808 static void DSP_store_r14_i(void);
2809 static void DSP_store_r14_r(void);
2810 static void DSP_store_r15_i(void);
2811 static void DSP_store_r15_r(void);
2812 static void DSP_sub(void);
2813 static void DSP_subc(void);
2814 static void DSP_subq(void);
2815 static void DSP_subqmod(void);
2816 static void DSP_subqt(void);
2817 static void DSP_xor(void);
2819 void (* DSPOpcode[64])() =
2821 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2822 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2823 DSP_neg, DSP_and, DSP_or, DSP_xor,
2824 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2826 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2827 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2828 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2829 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2831 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2832 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2833 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2834 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2836 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2837 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2838 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2839 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2842 bool readAffected[64][2] =
2844 { true, true}, { true, true}, {false, true}, {false, true},
2845 { true, true}, { true, true}, {false, true}, {false, true},
2846 {false, true}, { true, true}, { true, true}, { true, true},
2847 {false, true}, {false, true}, {false, true}, {false, true},
2849 { true, true}, { true, true}, { true, true}, {false, true},
2850 { true, true}, { true, true}, {false, true}, { true, true},
2851 {false, true}, {false, true}, { true, true}, {false, true},
2852 { true, true}, {false, true}, { true, true}, {false, true},
2854 {false, true}, {false, true}, { true, false}, {false, false},
2855 { true, false}, {false, false}, {false, false}, { true, false},
2856 { true, false}, { true, false}, {false, true}, { true, false},
2857 { true, false}, { true, true}, { true, true}, { true, true},
2859 {false, true}, { true, true}, { true, true}, {false, true},
2860 { true, false}, { true, false}, { true, true}, { true, false},
2861 { true, false}, {false, false}, { true, false}, { true, false},
2862 { true, true}, { true, true}, {false, false}, {false, true}
2865 bool isLoadStore[65] =
2867 false, false, false, false, false, false, false, false,
2868 false, false, false, false, false, false, false, false,
2870 false, false, false, false, false, false, false, false,
2871 false, false, false, false, false, false, false, false,
2873 false, false, false, false, false, false, false, true,
2874 true, true, false, true, true, true, true, true,
2876 false, true, true, false, false, false, false, false,
2877 false, false, true, true, true, true, false, false, false
2880 void FlushDSPPipeline(void)
2882 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2884 for(int i=0; i<4; i++)
2885 pipeline[i].opcode = PIPELINE_STALL;
2887 for(int i=0; i<32; i++)
2892 // New pipelined DSP execution core
2894 /*void DSPExecP(int32_t cycles)
2896 // bool inhibitFetch = false;
2898 dsp_releaseTimeSlice_flag = 0;
2901 while (cycles > 0 && DSP_RUNNING)
2903 WriteLog("DSPExecP: Pipeline status...\n");
2904 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);
2905 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);
2906 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);
2907 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);
2908 WriteLog(" --> Scoreboard: ");
2909 for(int i=0; i<32; i++)
2910 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2912 // Stage 1: Instruction fetch
2913 // if (!inhibitFetch)
2915 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2916 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2917 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2918 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2919 if (pipeline[plPtrFetch].opcode == 38)
2920 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2921 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2924 // inhibitFetch = false;
2925 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2927 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2928 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);
2929 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);
2930 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);
2931 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);
2932 // Stage 2: Read registers
2933 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2934 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2935 if (scoreboard[pipeline[plPtrRead].operand2])
2936 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2937 // We have a hit in the scoreboard, so we have to stall the pipeline...
2939 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2940 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2941 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2942 pipeline[plPtrFetch] = pipeline[plPtrRead];
2943 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2947 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2948 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2949 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2951 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2952 // Shouldn't we be more selective with the register scoreboarding?
2953 // Yes, we should. !!! FIX !!!
2954 scoreboard[pipeline[plPtrRead].operand2] = true;
2955 //Advance PC here??? Yes.
2956 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2957 //This is a mangling of the pipeline stages, but what else to do???
2958 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2961 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2962 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);
2963 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);
2964 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);
2965 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);
2967 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2969 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2970 DSPOpcode[pipeline[plPtrExec].opcode]();
2971 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2972 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2977 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2978 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);
2979 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);
2980 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);
2981 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);
2982 // Stage 4: Write back register
2983 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2985 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2986 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2988 scoreboard[pipeline[plPtrWrite].operand1]
2989 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2992 // Push instructions through the pipeline...
2993 plPtrFetch = (++plPtrFetch) & 0x03;
2994 plPtrRead = (++plPtrRead) & 0x03;
2995 plPtrExec = (++plPtrExec) & 0x03;
2996 plPtrWrite = (++plPtrWrite) & 0x03;
3003 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3005 // Should be fixed now. Another problem is figuring how to do the sequence following
3006 // a branch followed with the JR & JUMP instructions...
3008 // There are two conflicting problems:
3011 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3012 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3013 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3014 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3015 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3016 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3017 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3018 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3019 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3020 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3021 DSP: Finished interrupt.
3022 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3023 ; bank 0 (where is was prepared)!
3024 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3025 F1B252: NOP [NCZ:001]
3028 // The other is when you see this at the end of an IRQ:
3031 JUMP T, (R29) ; R29 = Previous stack + 2
3032 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3034 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3035 ; 1) The STORE goes through the pipeline and is executed/written back
3036 ; 2) The pipeline is flushed
3037 ; 3) The DSP_PC is set to the new address
3038 ; 4) Execution resumes
3040 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3041 ; bank 0 instead of the current bank 1 and so goes astray!
3044 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3045 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3049 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3050 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3051 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3052 If it were done properly, the STORE write back would occur *after* (well, technically,
3053 during) the execution of the the JUMP that follows it.
3057 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3058 F1B08A: NOP [NCZ:001]
3060 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3063 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3066 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3067 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3068 F1B08A: NOP [NCZ:001]
3070 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3073 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3074 DSP: CPU -> DSP interrupt
3075 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3076 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3078 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3081 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3082 F1B006: NOP [NCZ:001]
3084 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3087 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3088 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3091 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3092 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3095 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3096 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3099 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3100 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3103 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3106 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3109 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3110 F1B0FE: NOP [NCZ:000]
3112 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3115 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3118 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3119 F1B138: NOP [NCZ:000]
3121 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3124 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3125 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3126 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3129 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3130 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3133 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3134 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3135 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3137 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3138 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3141 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3142 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3143 DSP: Finished interrupt.
3144 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3146 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3149 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3150 F1B016: NOP [NCZ:001]
3152 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3155 uint32_t pcQueue1[0x400];
3156 uint32_t pcQPtr1 = 0;
3157 static uint32_t prevR1;
3158 //Let's try a 3 stage pipeline....
3159 //Looks like 3 stage is correct, otherwise bad things happen...
3160 void DSPExecP2(int32_t cycles)
3162 dsp_releaseTimeSlice_flag = 0;
3165 while (cycles > 0 && DSP_RUNNING)
3167 /*extern uint32_t totalFrames;
3168 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3169 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3170 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3172 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3175 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3177 if (dsp_pc == 0xF1B092)
3178 doDSPDis = false;//*/
3179 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3180 doDSPDis = true;//*/
3181 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3182 doDSPDis = true;//*/
3183 /*if (dsp_pc == 0xF1B0A0)
3184 doDSPDis = true;//*/
3185 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3186 doDSPDis = true;//*/
3187 //Two parter... (not sure how to write this)
3188 //if (dsp_pc == 0xF1B0D2)
3189 // prevR1 = dsp_reg[1];
3191 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3192 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3195 pcQueue1[pcQPtr1++] = dsp_pc;
3198 #ifdef DSP_DEBUG_PL2
3199 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3201 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3206 for(int i=0; i<0x400; i++)
3208 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3209 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3215 if (IMASKCleared) // If IMASK was cleared,
3217 #ifdef DSP_DEBUG_IRQ
3218 WriteLog("DSP: Finished interrupt.\n");
3220 DSPHandleIRQs(); // See if any other interrupts are pending!
3221 IMASKCleared = false;
3224 //if (dsp_flags & REGPAGE)
3225 // WriteLog(" --> REGPAGE has just been set!\n");
3226 #ifdef DSP_DEBUG_PL2
3229 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3230 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]);
3231 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]);
3232 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]);
3233 WriteLog(" --> Scoreboard: ");
3234 for(int i=0; i<32; i++)
3235 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3239 // Stage 1a: Instruction fetch
3240 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3241 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3242 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3243 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3244 if (pipeline[plPtrRead].opcode == 38)
3245 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3246 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3247 #ifdef DSP_DEBUG_PL2
3250 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3251 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3252 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]);
3253 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]);
3254 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]);
3257 // Stage 1b: Read registers
3258 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3259 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3261 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3262 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3263 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3264 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3265 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3266 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3267 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3269 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3270 // We have a hit in the scoreboard, so we have to stall the pipeline...
3271 #ifdef DSP_DEBUG_PL2
3275 WriteLog(" --> Stalling pipeline: ");
3276 if (readAffected[pipeline[plPtrRead].opcode][0])
3277 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3278 if (readAffected[pipeline[plPtrRead].opcode][1])
3279 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3283 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3284 #ifdef DSP_DEBUG_PL2
3289 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3290 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3291 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3293 // Shouldn't we be more selective with the register scoreboarding?
3294 // Yes, we should. !!! FIX !!! Kinda [DONE]
3295 #ifndef NEW_SCOREBOARD
3296 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3298 //Hopefully this will fix the dual MOVEQ # problem...
3299 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3302 //Advance PC here??? Yes.
3303 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3306 #ifdef DSP_DEBUG_PL2
3309 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3310 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]);
3311 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]);
3312 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]);
3316 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3318 #ifdef DSP_DEBUG_PL2
3320 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"));
3324 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3329 lastExec = pipeline[plPtrExec].instruction;
3330 //WriteLog("[lastExec = %04X]\n", lastExec);
3332 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3333 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3334 DSPOpcode[pipeline[plPtrExec].opcode]();
3335 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3339 //Let's not, until we do the stalling correctly...
3340 //But, we gotta while we're doing the comparison core...!
3341 //Or do we? cycles--;
3342 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3343 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3344 //to model this clock cycle behavior correctly...
3345 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3346 //don't affect the reads at stage 1...
3347 #ifdef DSP_DEBUG_STALL
3349 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3353 #ifdef DSP_DEBUG_PL2
3356 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3357 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]);
3358 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]);
3359 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]);
3363 // Stage 3: Write back register/memory address
3364 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3366 /*if (pipeline[plPtrWrite].writebackRegister == 3
3367 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3370 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3373 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3375 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3376 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3379 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3380 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3381 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3382 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3384 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3388 #ifndef NEW_SCOREBOARD
3389 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3390 scoreboard[pipeline[plPtrWrite].operand2] = false;
3392 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3393 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3394 if (scoreboard[pipeline[plPtrWrite].operand2])
3395 scoreboard[pipeline[plPtrWrite].operand2]--;
3399 // Push instructions through the pipeline...
3400 plPtrRead = (++plPtrRead) & 0x03;
3401 plPtrExec = (++plPtrExec) & 0x03;
3402 plPtrWrite = (++plPtrWrite) & 0x03;
3411 //#define DSP_DEBUG_PL3
3412 //Let's try a 2 stage pipeline....
3413 void DSPExecP3(int32_t cycles)
3415 dsp_releaseTimeSlice_flag = 0;
3418 while (cycles > 0 && DSP_RUNNING)
3420 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3422 #ifdef DSP_DEBUG_PL3
3423 WriteLog("DSPExecP: Pipeline status...\n");
3424 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]);
3425 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]);
3426 WriteLog(" --> Scoreboard: ");
3427 for(int i=0; i<32; i++)
3428 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3431 // Stage 1a: Instruction fetch
3432 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3433 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3434 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3435 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3436 if (pipeline[plPtrRead].opcode == 38)
3437 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3438 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3439 #ifdef DSP_DEBUG_PL3
3440 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3441 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3442 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]);
3443 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]);
3445 // Stage 1b: Read registers
3446 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3447 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3448 // We have a hit in the scoreboard, so we have to stall the pipeline...
3449 #ifdef DSP_DEBUG_PL3
3451 WriteLog(" --> Stalling pipeline: ");
3452 if (readAffected[pipeline[plPtrRead].opcode][0])
3453 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3454 if (readAffected[pipeline[plPtrRead].opcode][1])
3455 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3458 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3459 #ifdef DSP_DEBUG_PL3
3464 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3465 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3466 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3468 // Shouldn't we be more selective with the register scoreboarding?
3469 // Yes, we should. !!! FIX !!! [Kinda DONE]
3470 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3472 //Advance PC here??? Yes.
3473 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3476 #ifdef DSP_DEBUG_PL3
3477 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3478 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]);
3479 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]);
3481 // Stage 2a: Execute
3482 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3484 #ifdef DSP_DEBUG_PL3
3485 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3487 DSPOpcode[pipeline[plPtrExec].opcode]();
3488 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3489 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3494 #ifdef DSP_DEBUG_PL3
3495 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3496 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]);
3497 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]);
3500 // Stage 2b: Write back register
3501 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3503 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3504 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3506 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3507 scoreboard[pipeline[plPtrExec].operand2] = false;
3510 // Push instructions through the pipeline...
3511 plPtrRead = (++plPtrRead) & 0x03;
3512 plPtrExec = (++plPtrExec) & 0x03;
3519 // DSP pipelined opcode handlers
3522 #define PRM pipeline[plPtrExec].reg1
3523 #define PRN pipeline[plPtrExec].reg2
3524 #define PIMM1 pipeline[plPtrExec].operand1
3525 #define PIMM2 pipeline[plPtrExec].operand2
3526 #define PRES pipeline[plPtrExec].result
3527 #define PWBR pipeline[plPtrExec].writebackRegister
3528 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3529 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3530 #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))
3531 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3533 static void DSP_abs(void)
3537 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);
3541 if (_Rn == 0x80000000)
3545 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3546 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3547 CLR_ZN; SET_Z(PRES);
3551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3555 static void DSP_add(void)
3559 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);
3561 uint32_t res = PRN + PRM;
3562 SET_ZNC_ADD(PRN, PRM, res);
3566 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);
3570 static void DSP_addc(void)
3574 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);
3576 uint32_t res = PRN + PRM + dsp_flag_c;
3577 uint32_t carry = dsp_flag_c;
3578 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3579 SET_ZNC_ADD(PRN + carry, PRM, res);
3580 // SET_ZNC_ADD(PRN, PRM + carry, res);
3584 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);
3588 static void DSP_addq(void)
3592 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);
3594 uint32_t r1 = dsp_convert_zero[PIMM1];
3595 uint32_t res = PRN + r1;
3596 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3600 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3604 static void DSP_addqmod(void)
3606 #ifdef DSP_DIS_ADDQMOD
3608 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);
3610 uint32_t r1 = dsp_convert_zero[PIMM1];
3612 uint32_t res = r2 + r1;
3613 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3615 SET_ZNC_ADD(r2, r1, res);
3616 #ifdef DSP_DIS_ADDQMOD
3618 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3622 static void DSP_addqt(void)
3624 #ifdef DSP_DIS_ADDQT
3626 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);
3628 PRES = PRN + dsp_convert_zero[PIMM1];
3629 #ifdef DSP_DIS_ADDQT
3631 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3635 static void DSP_and(void)
3639 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);
3645 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);
3649 static void DSP_bclr(void)
3653 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);
3655 PRES = PRN & ~(1 << PIMM1);
3659 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3663 static void DSP_bset(void)
3667 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);
3669 PRES = PRN | (1 << PIMM1);
3673 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3677 static void DSP_btst(void)
3681 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);
3683 dsp_flag_z = (~PRN >> PIMM1) & 1;
3687 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3691 static void DSP_cmp(void)
3695 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);
3697 uint32_t res = PRN - PRM;
3698 SET_ZNC_SUB(PRN, PRM, res);
3702 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3706 static void DSP_cmpq(void)
3708 static int32_t sqtable[32] =
3709 { 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 };
3712 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);
3714 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3715 uint32_t res = PRN - r1;
3716 SET_ZNC_SUB(PRN, r1, res);
3720 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3724 static void DSP_div(void)
3726 uint32_t _Rm = PRM, _Rn = PRN;
3730 if (dsp_div_control & 1)
3732 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3733 if (dsp_remain & 0x80000000)
3735 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3739 dsp_remain = _Rn % _Rm;
3740 if (dsp_remain & 0x80000000)
3749 static void DSP_imacn(void)
3751 #ifdef DSP_DIS_IMACN
3753 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);
3755 int32_t res = (int16_t)PRM * (int16_t)PRN;
3756 dsp_acc += (int64_t)res;
3757 //Should we AND the result to fit into 40 bits here???
3759 #ifdef DSP_DIS_IMACN
3761 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));
3765 static void DSP_imult(void)
3767 #ifdef DSP_DIS_IMULT
3769 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);
3771 PRES = (int16_t)PRN * (int16_t)PRM;
3773 #ifdef DSP_DIS_IMULT
3775 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);
3779 static void DSP_imultn(void)
3781 #ifdef DSP_DIS_IMULTN
3783 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);
3785 // This is OK, since this multiply won't overflow 32 bits...
3786 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3787 dsp_acc = (int64_t)res;
3790 #ifdef DSP_DIS_IMULTN
3792 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));
3796 static void DSP_illegal(void)
3798 #ifdef DSP_DIS_ILLEGAL
3800 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3805 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3806 // can cause trouble because an interrupt can occur *before* the instruction following the
3807 // jump can execute... !!! FIX !!!
3808 // This can probably be solved by judicious coding in the pipeline execution core...
3809 // And should be fixed now...
3810 static void DSP_jr(void)
3813 const char * condition[32] =
3814 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3815 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3816 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3817 "???", "???", "???", "F" };
3819 //How come this is always off by 2???
3820 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);
3822 // KLUDGE: Used by BRANCH_CONDITION macro
3823 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3825 if (BRANCH_CONDITION(PIMM2))
3829 WriteLog("Branched!\n");
3831 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3832 //Account for pipeline effects...
3833 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3834 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3836 // Now that we've branched, we have to make sure that the following instruction
3837 // is executed atomically with this one and then flush the pipeline before setting
3840 // Step 1: Handle writebacks at stage 3 of pipeline
3841 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3843 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3844 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3846 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3847 scoreboard[pipeline[plPtrWrite].operand2] = false;
3849 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3851 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3853 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3854 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3857 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3858 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3859 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3860 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3862 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3866 #ifndef NEW_SCOREBOARD
3867 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3868 scoreboard[pipeline[plPtrWrite].operand2] = false;
3870 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3871 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3872 if (scoreboard[pipeline[plPtrWrite].operand2])
3873 scoreboard[pipeline[plPtrWrite].operand2]--;
3877 // Step 2: Push instruction through pipeline & execute following instruction
3878 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3879 // we effectively handle the final push of the instruction through the
3880 // pipeline when the new PC takes effect (since when we return, the
3881 // pipeline code will be executing the writeback stage. If we reverse
3882 // the execution order of the pipeline stages, this will no longer be
3884 pipeline[plPtrExec] = pipeline[plPtrRead];
3885 //This is BAD. We need to get that next opcode and execute it!
3886 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3887 // remove this crap.
3888 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3890 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3891 pipeline[plPtrExec].opcode = instruction >> 10;
3892 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3893 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3894 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3895 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3896 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3898 dsp_pc += 2; // For DSP_DIS_* accuracy
3899 DSPOpcode[pipeline[plPtrExec].opcode]();
3900 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3901 pipeline[plPtrWrite] = pipeline[plPtrExec];
3903 // Step 3: Flush pipeline & set new PC
3904 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3911 WriteLog("Branch NOT taken.\n");
3917 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3920 static void DSP_jump(void)
3923 const char * condition[32] =
3924 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3925 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3926 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3927 "???", "???", "???", "F" };
3929 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);
3931 // KLUDGE: Used by BRANCH_CONDITION macro
3932 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3934 if (BRANCH_CONDITION(PIMM2))
3938 WriteLog("Branched!\n");
3940 uint32_t PCSave = PRM;
3941 // Now that we've branched, we have to make sure that the following instruction
3942 // is executed atomically with this one and then flush the pipeline before setting
3945 // Step 1: Handle writebacks at stage 3 of pipeline
3946 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3948 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3949 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3951 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3952 scoreboard[pipeline[plPtrWrite].operand2] = false;
3954 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3956 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3958 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3959 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3962 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3963 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3964 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3965 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3967 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3971 #ifndef NEW_SCOREBOARD
3972 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3973 scoreboard[pipeline[plPtrWrite].operand2] = false;
3975 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3976 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3977 if (scoreboard[pipeline[plPtrWrite].operand2])
3978 scoreboard[pipeline[plPtrWrite].operand2]--;
3982 // Step 2: Push instruction through pipeline & execute following instruction
3983 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3984 // we effectively handle the final push of the instruction through the
3985 // pipeline when the new PC takes effect (since when we return, the
3986 // pipeline code will be executing the writeback stage. If we reverse
3987 // the execution order of the pipeline stages, this will no longer be
3989 pipeline[plPtrExec] = pipeline[plPtrRead];
3990 //This is BAD. We need to get that next opcode and execute it!
3991 //Also, same problem in JR!
3992 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3993 // remove this crap.
3994 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3996 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3997 pipeline[plPtrExec].opcode = instruction >> 10;
3998 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3999 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4000 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4001 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4002 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4004 dsp_pc += 2; // For DSP_DIS_* accuracy
4005 DSPOpcode[pipeline[plPtrExec].opcode]();
4006 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4007 pipeline[plPtrWrite] = pipeline[plPtrExec];
4009 // Step 3: Flush pipeline & set new PC
4010 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4017 WriteLog("Branch NOT taken.\n");
4025 static void DSP_load(void)
4029 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);
4031 #ifdef DSP_CORRECT_ALIGNMENT
4032 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4034 PRES = DSPReadLong(PRM, DSP);
4038 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4042 static void DSP_loadb(void)
4044 #ifdef DSP_DIS_LOADB
4046 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);
4048 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4049 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4051 PRES = JaguarReadByte(PRM, DSP);
4052 #ifdef DSP_DIS_LOADB
4054 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4058 static void DSP_loadw(void)
4060 #ifdef DSP_DIS_LOADW
4062 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);
4064 #ifdef DSP_CORRECT_ALIGNMENT
4065 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4066 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4068 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4070 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4071 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4073 PRES = JaguarReadWord(PRM, DSP);
4075 #ifdef DSP_DIS_LOADW
4077 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4081 static void DSP_load_r14_i(void)
4083 #ifdef DSP_DIS_LOAD14I
4085 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);
4087 #ifdef DSP_CORRECT_ALIGNMENT
4088 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4090 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4092 #ifdef DSP_DIS_LOAD14I
4094 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4098 static void DSP_load_r14_r(void)
4100 #ifdef DSP_DIS_LOAD14R
4102 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);
4104 #ifdef DSP_CORRECT_ALIGNMENT
4105 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4107 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4109 #ifdef DSP_DIS_LOAD14R
4111 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4115 static void DSP_load_r15_i(void)
4117 #ifdef DSP_DIS_LOAD15I
4119 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);
4121 #ifdef DSP_CORRECT_ALIGNMENT
4122 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4124 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4126 #ifdef DSP_DIS_LOAD15I
4128 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4132 static void DSP_load_r15_r(void)
4134 #ifdef DSP_DIS_LOAD15R
4136 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);
4138 #ifdef DSP_CORRECT_ALIGNMENT
4139 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4141 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4143 #ifdef DSP_DIS_LOAD15R
4145 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4149 static void DSP_mirror(void)
4152 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4156 static void DSP_mmult(void)
4158 int count = dsp_matrix_control&0x0f;
4159 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4163 if (!(dsp_matrix_control & 0x10))
4165 for (int i = 0; i < count; i++)
4169 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4171 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4172 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4179 for (int i = 0; i < count; i++)
4183 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4185 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4186 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4192 PRES = res = (int32_t)accum;
4194 //NOTE: The flags are set based upon the last add/multiply done...
4198 static void DSP_move(void)
4202 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);
4207 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);
4211 static void DSP_movefa(void)
4213 #ifdef DSP_DIS_MOVEFA
4215 // 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);
4216 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);
4218 // PRES = ALTERNATE_RM;
4219 PRES = dsp_alternate_reg[PIMM1];
4220 #ifdef DSP_DIS_MOVEFA
4222 // 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);
4223 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);
4227 static void DSP_movei(void)
4229 #ifdef DSP_DIS_MOVEI
4231 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);
4233 // // This instruction is followed by 32-bit value in LSW / MSW format...
4234 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4236 #ifdef DSP_DIS_MOVEI
4238 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4242 static void DSP_movepc(void)
4244 #ifdef DSP_DIS_MOVEPC
4246 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);
4248 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4249 // PRES = dsp_pc - 2;
4250 //Account for pipeline effects...
4251 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4252 #ifdef DSP_DIS_MOVEPC
4254 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4258 static void DSP_moveq(void)
4260 #ifdef DSP_DIS_MOVEQ
4262 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);
4265 #ifdef DSP_DIS_MOVEQ
4267 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4271 static void DSP_moveta(void)
4273 #ifdef DSP_DIS_MOVETA
4275 // 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);
4276 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]);
4278 // ALTERNATE_RN = PRM;
4279 dsp_alternate_reg[PIMM2] = PRM;
4281 #ifdef DSP_DIS_MOVETA
4283 // 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);
4284 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]);
4288 static void DSP_mtoi(void)
4290 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4294 static void DSP_mult(void)
4298 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);
4300 PRES = (uint16_t)PRM * (uint16_t)PRN;
4304 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);
4308 static void DSP_neg(void)
4312 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);
4314 uint32_t res = -PRN;
4315 SET_ZNC_SUB(0, PRN, res);
4319 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4323 static void DSP_nop(void)
4327 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4332 static void DSP_normi(void)
4339 while ((_Rm & 0xffc00000) == 0)
4344 while ((_Rm & 0xff800000) != 0)
4354 static void DSP_not(void)
4358 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);
4364 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4368 static void DSP_or(void)
4372 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);
4378 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);
4382 static void DSP_resmac(void)
4384 #ifdef DSP_DIS_RESMAC
4386 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));
4388 PRES = (uint32_t)dsp_acc;
4389 #ifdef DSP_DIS_RESMAC
4391 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4395 static void DSP_ror(void)
4399 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);
4401 uint32_t r1 = PRM & 0x1F;
4402 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4403 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4407 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);
4411 static void DSP_rorq(void)
4415 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);
4417 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4419 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4421 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4424 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4428 static void DSP_sat16s(void)
4431 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4436 static void DSP_sat32s(void)
4438 int32_t r2 = (uint32_t)PRN;
4439 int32_t temp = dsp_acc >> 32;
4440 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4445 static void DSP_sh(void)
4447 int32_t sRm = (int32_t)PRM;
4452 uint32_t shift = -sRm;
4457 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4467 uint32_t shift = sRm;
4472 dsp_flag_c = _Rn & 0x1;
4485 static void DSP_sha(void)
4487 int32_t sRm = (int32_t)PRM;
4492 uint32_t shift = -sRm;
4497 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4507 uint32_t shift = sRm;
4512 dsp_flag_c = _Rn & 0x1;
4516 _Rn = ((int32_t)_Rn) >> 1;
4525 static void DSP_sharq(void)
4527 #ifdef DSP_DIS_SHARQ
4529 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);
4531 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4532 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4534 #ifdef DSP_DIS_SHARQ
4536 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4540 static void DSP_shlq(void)
4544 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);
4546 int32_t r1 = 32 - PIMM1;
4547 uint32_t res = PRN << r1;
4548 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4552 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4556 static void DSP_shrq(void)
4560 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);
4562 int32_t r1 = dsp_convert_zero[PIMM1];
4563 uint32_t res = PRN >> r1;
4564 SET_ZN(res); dsp_flag_c = PRN & 1;
4568 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4572 static void DSP_store(void)
4574 #ifdef DSP_DIS_STORE
4576 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);
4578 // DSPWriteLong(PRM, PRN, DSP);
4580 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4581 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4583 pipeline[plPtrExec].address = PRM;
4585 pipeline[plPtrExec].value = PRN;
4586 pipeline[plPtrExec].type = TYPE_DWORD;
4590 static void DSP_storeb(void)
4592 #ifdef DSP_DIS_STOREB
4594 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);
4596 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4597 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4599 // JaguarWriteByte(PRM, PRN, DSP);
4602 pipeline[plPtrExec].address = PRM;
4604 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4606 pipeline[plPtrExec].value = PRN & 0xFF;
4607 pipeline[plPtrExec].type = TYPE_DWORD;
4611 pipeline[plPtrExec].value = PRN;
4612 pipeline[plPtrExec].type = TYPE_BYTE;
4618 static void DSP_storew(void)
4620 #ifdef DSP_DIS_STOREW
4622 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);
4624 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4625 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4627 // JaguarWriteWord(PRM, PRN, DSP);
4630 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4631 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4633 pipeline[plPtrExec].address = PRM;
4636 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4638 pipeline[plPtrExec].value = PRN & 0xFFFF;
4639 pipeline[plPtrExec].type = TYPE_DWORD;
4643 pipeline[plPtrExec].value = PRN;
4644 pipeline[plPtrExec].type = TYPE_WORD;
4649 static void DSP_store_r14_i(void)
4651 #ifdef DSP_DIS_STORE14I
4653 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));
4655 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4657 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4658 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4660 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4662 pipeline[plPtrExec].value = PRN;
4663 pipeline[plPtrExec].type = TYPE_DWORD;
4667 static void DSP_store_r14_r(void)
4669 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4671 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4672 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4674 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4676 pipeline[plPtrExec].value = PRN;
4677 pipeline[plPtrExec].type = TYPE_DWORD;
4681 static void DSP_store_r15_i(void)
4683 #ifdef DSP_DIS_STORE15I
4685 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));
4687 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4689 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4690 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4692 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4694 pipeline[plPtrExec].value = PRN;
4695 pipeline[plPtrExec].type = TYPE_DWORD;
4699 static void DSP_store_r15_r(void)
4701 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4703 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4704 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4706 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4708 pipeline[plPtrExec].value = PRN;
4709 pipeline[plPtrExec].type = TYPE_DWORD;
4713 static void DSP_sub(void)
4717 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);
4719 uint32_t res = PRN - PRM;
4720 SET_ZNC_SUB(PRN, PRM, res);
4724 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);
4728 static void DSP_subc(void)
4732 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);
4734 uint32_t res = PRN - PRM - dsp_flag_c;
4735 uint32_t borrow = dsp_flag_c;
4736 SET_ZNC_SUB(PRN - borrow, PRM, res);
4740 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);
4744 static void DSP_subq(void)
4748 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);
4750 uint32_t r1 = dsp_convert_zero[PIMM1];
4751 uint32_t res = PRN - r1;
4752 SET_ZNC_SUB(PRN, r1, res);
4756 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4760 static void DSP_subqmod(void)
4762 uint32_t r1 = dsp_convert_zero[PIMM1];
4764 uint32_t res = r2 - r1;
4765 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4767 SET_ZNC_SUB(r2, r1, res);
4770 static void DSP_subqt(void)
4772 #ifdef DSP_DIS_SUBQT
4774 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);
4776 PRES = PRN - dsp_convert_zero[PIMM1];
4777 #ifdef DSP_DIS_SUBQT
4779 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4783 static void DSP_xor(void)
4787 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);
4793 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);