4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive cleanups/rewrites by James Hammons
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
12 // --- ---------- -------------------------------------------------------------
13 // JLH 01/16/2010 Created this log ;-)
14 // JLH 11/26/2011 Added fixes for LOAD/STORE alignment issues
19 #include <SDL.h> // Used only for SDL_GetTicks...
27 #include "m68000/m68kinterface.h"
31 // Seems alignment in loads & stores was off...
32 #define DSP_CORRECT_ALIGNMENT
33 //#define DSP_CORRECT_ALIGNMENT_STORE
36 //#define DSP_DEBUG_IRQ
37 //#define DSP_DEBUG_PL2
38 //#define DSP_DEBUG_STALL
39 //#define DSP_DEBUG_CC
40 #define NEW_SCOREBOARD
42 // Disassembly definitions
49 #define DSP_DIS_ADDQMOD
59 #define DSP_DIS_IMULTN
60 #define DSP_DIS_ILLEGAL
64 #define DSP_DIS_LOAD14I
65 #define DSP_DIS_LOAD14R
66 #define DSP_DIS_LOAD15I
67 #define DSP_DIS_LOAD15R
73 #define DSP_DIS_MOVEFA
74 #define DSP_DIS_MOVEPC // Pipeline only!
75 #define DSP_DIS_MOVETA
81 #define DSP_DIS_RESMAC
88 #define DSP_DIS_STORE14I
89 #define DSP_DIS_STORE15I
90 #define DSP_DIS_STOREB
91 #define DSP_DIS_STOREW
98 bool doDSPDis = false;
99 //bool doDSPDis = true;
101 bool doDSPDis = false;
103 //#define DSP_DIS_JUMP
137 + load_r15_indexed 284500
139 + store_r15_indexed 47416
143 + load_r14_ri 1229448
146 // Pipeline structures
148 const bool affectsScoreboard[64] =
150 true, true, true, true,
151 true, true, true, true,
152 true, true, true, true,
153 true, false, true, true,
155 true, true, false, true,
156 false, true, true, true,
157 true, true, true, true,
158 true, true, false, false,
160 true, true, true, true,
161 false, true, true, true,
162 true, true, true, true,
163 true, false, false, false,
165 true, false, false, true,
166 false, false, true, true,
167 true, false, true, true,
168 false, false, false, true
173 uint16_t instruction;
174 uint8_t opcode, operand1, operand2;
175 uint32_t reg1, reg2, areg1, areg2;
177 uint8_t writebackRegister;
178 // General memory store...
187 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
188 #ifndef NEW_SCOREBOARD
191 uint8_t scoreboard[32];
193 uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
194 PipelineStage pipeline[4];
195 bool IMASKCleared = false;
197 // DSP flags (old--have to get rid of this crap)
199 #define CINT0FLAG 0x00200
200 #define CINT1FLAG 0x00400
201 #define CINT2FLAG 0x00800
202 #define CINT3FLAG 0x01000
203 #define CINT4FLAG 0x02000
204 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
205 #define CINT5FLAG 0x20000 /* DSP only */
209 #define ZERO_FLAG 0x00001
210 #define CARRY_FLAG 0x00002
211 #define NEGA_FLAG 0x00004
212 #define IMASK 0x00008
213 #define INT_ENA0 0x00010
214 #define INT_ENA1 0x00020
215 #define INT_ENA2 0x00040
216 #define INT_ENA3 0x00080
217 #define INT_ENA4 0x00100
218 #define INT_CLR0 0x00200
219 #define INT_CLR1 0x00400
220 #define INT_CLR2 0x00800
221 #define INT_CLR3 0x01000
222 #define INT_CLR4 0x02000
223 #define REGPAGE 0x04000
224 #define DMAEN 0x08000
225 #define INT_ENA5 0x10000
226 #define INT_CLR5 0x20000
230 #define DSPGO 0x00001
231 #define CPUINT 0x00002
232 #define DSPINT0 0x00004
233 #define SINGLE_STEP 0x00008
234 #define SINGLE_GO 0x00010
236 #define INT_LAT0 0x00040
237 #define INT_LAT1 0x00080
238 #define INT_LAT2 0x00100
239 #define INT_LAT3 0x00200
240 #define INT_LAT4 0x00400
241 #define BUS_HOG 0x00800
242 #define VERSION 0x0F000
243 #define INT_LAT5 0x10000
245 extern uint32_t jaguar_mainRom_crc32;
247 // Is opcode 62 *really* a NOP? Seems like it...
248 static void dsp_opcode_abs(void);
249 static void dsp_opcode_add(void);
250 static void dsp_opcode_addc(void);
251 static void dsp_opcode_addq(void);
252 static void dsp_opcode_addqmod(void);
253 static void dsp_opcode_addqt(void);
254 static void dsp_opcode_and(void);
255 static void dsp_opcode_bclr(void);
256 static void dsp_opcode_bset(void);
257 static void dsp_opcode_btst(void);
258 static void dsp_opcode_cmp(void);
259 static void dsp_opcode_cmpq(void);
260 static void dsp_opcode_div(void);
261 static void dsp_opcode_imacn(void);
262 static void dsp_opcode_imult(void);
263 static void dsp_opcode_imultn(void);
264 static void dsp_opcode_jr(void);
265 static void dsp_opcode_jump(void);
266 static void dsp_opcode_load(void);
267 static void dsp_opcode_loadb(void);
268 static void dsp_opcode_loadw(void);
269 static void dsp_opcode_load_r14_indexed(void);
270 static void dsp_opcode_load_r14_ri(void);
271 static void dsp_opcode_load_r15_indexed(void);
272 static void dsp_opcode_load_r15_ri(void);
273 static void dsp_opcode_mirror(void);
274 static void dsp_opcode_mmult(void);
275 static void dsp_opcode_move(void);
276 static void dsp_opcode_movei(void);
277 static void dsp_opcode_movefa(void);
278 static void dsp_opcode_move_pc(void);
279 static void dsp_opcode_moveq(void);
280 static void dsp_opcode_moveta(void);
281 static void dsp_opcode_mtoi(void);
282 static void dsp_opcode_mult(void);
283 static void dsp_opcode_neg(void);
284 static void dsp_opcode_nop(void);
285 static void dsp_opcode_normi(void);
286 static void dsp_opcode_not(void);
287 static void dsp_opcode_or(void);
288 static void dsp_opcode_resmac(void);
289 static void dsp_opcode_ror(void);
290 static void dsp_opcode_rorq(void);
291 static void dsp_opcode_xor(void);
292 static void dsp_opcode_sat16s(void);
293 static void dsp_opcode_sat32s(void);
294 static void dsp_opcode_sh(void);
295 static void dsp_opcode_sha(void);
296 static void dsp_opcode_sharq(void);
297 static void dsp_opcode_shlq(void);
298 static void dsp_opcode_shrq(void);
299 static void dsp_opcode_store(void);
300 static void dsp_opcode_storeb(void);
301 static void dsp_opcode_storew(void);
302 static void dsp_opcode_store_r14_indexed(void);
303 static void dsp_opcode_store_r14_ri(void);
304 static void dsp_opcode_store_r15_indexed(void);
305 static void dsp_opcode_store_r15_ri(void);
306 static void dsp_opcode_sub(void);
307 static void dsp_opcode_subc(void);
308 static void dsp_opcode_subq(void);
309 static void dsp_opcode_subqmod(void);
310 static void dsp_opcode_subqt(void);
311 static void dsp_opcode_illegal(void);
313 /*uint8_t dsp_opcode_cycles[64] =
315 3, 3, 3, 3, 3, 3, 3, 3,
316 3, 3, 3, 3, 3, 3, 3, 3,
317 3, 3, 1, 3, 1, 18, 3, 3,
318 3, 3, 3, 3, 3, 3, 3, 3,
319 3, 3, 2, 2, 2, 2, 3, 4,
320 5, 4, 5, 6, 6, 1, 1, 1,
321 1, 2, 2, 2, 1, 1, 9, 3,
322 3, 1, 6, 6, 2, 2, 3, 3
324 //Here's a QnD kludge...
325 //This is wrong, wrong, WRONG, but it seems to work for the time being...
326 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
327 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
328 // Yup, without cheating like this, the sound in things like Rayman, FACTS, &
329 // Tripper Getem get starved for time and sounds like crap. So we have to figure
330 // out how to fix that. :-/
331 uint8_t dsp_opcode_cycles[64] =
333 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 9, 1, 1,
336 1, 1, 1, 1, 1, 1, 1, 1,
337 1, 1, 1, 1, 1, 1, 1, 2,
338 2, 2, 2, 3, 3, 1, 1, 1,
339 1, 1, 1, 1, 1, 1, 4, 1,
340 1, 1, 3, 3, 1, 1, 1, 1
343 void (* dsp_opcode[64])() =
345 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
346 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
347 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
348 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
349 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
350 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
351 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
352 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
353 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
354 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
355 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
356 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
357 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
358 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
359 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
360 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod,
363 uint32_t dsp_opcode_use[65];
365 const char * dsp_opcode_str[65]=
367 "add", "addc", "addq", "addqt",
368 "sub", "subc", "subq", "subqt",
369 "neg", "and", "or", "xor",
370 "not", "btst", "bset", "bclr",
371 "mult", "imult", "imultn", "resmac",
372 "imacn", "div", "abs", "sh",
373 "shlq", "shrq", "sha", "sharq",
374 "ror", "rorq", "cmp", "cmpq",
375 "subqmod", "sat16s", "move", "moveq",
376 "moveta", "movefa", "movei", "loadb",
377 "loadw", "load", "sat32s", "load_r14_indexed",
378 "load_r15_indexed", "storeb", "storew", "store",
379 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
380 "jump", "jr", "mmult", "mtoi",
381 "normi", "nop", "load_r14_ri", "load_r15_ri",
382 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
387 static uint64_t dsp_acc; // 40 bit register, NOT 32!
388 static uint32_t dsp_remain;
389 static uint32_t dsp_modulo;
390 static uint32_t dsp_flags;
391 static uint32_t dsp_matrix_control;
392 static uint32_t dsp_pointer_to_matrix;
393 static uint32_t dsp_data_organization;
394 uint32_t dsp_control;
395 static uint32_t dsp_div_control;
396 static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
397 static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
398 uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
400 static uint32_t dsp_opcode_first_parameter;
401 static uint32_t dsp_opcode_second_parameter;
403 #define DSP_RUNNING (dsp_control & 0x01)
405 #define RM dsp_reg[dsp_opcode_first_parameter]
406 #define RN dsp_reg[dsp_opcode_second_parameter]
407 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
408 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
409 #define IMM_1 dsp_opcode_first_parameter
410 #define IMM_2 dsp_opcode_second_parameter
412 #define CLR_Z (dsp_flag_z = 0)
413 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
414 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
415 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
416 #define SET_N(r) (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
417 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
418 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
419 #define SET_ZN(r) SET_N(r); SET_Z(r)
420 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
421 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
423 uint32_t dsp_convert_zero[32] = {
424 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
425 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
428 uint8_t dsp_branch_condition_table[32 * 8];
429 static uint16_t mirror_table[65536];
430 static uint8_t dsp_ram_8[0x2000];
432 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
434 static uint32_t dsp_in_exec = 0;
435 static uint32_t dsp_releaseTimeSlice_flag = 0;
440 // Comparison core vars (used only for core comparison! :-)
441 static uint64_t count = 0;
442 static uint8_t ram1[0x2000], ram2[0x2000];
443 static uint32_t regs1[64], regs2[64];
444 static uint32_t ctrl1[14], ctrl2[14];
447 // Private function prototypes
449 void DSPDumpRegisters(void);
450 void DSPDumpDisassembly(void);
451 void FlushDSPPipeline(void);
454 void dsp_reset_stats(void)
456 for(int i=0; i<65; i++)
457 dsp_opcode_use[i] = 0;
460 void DSPReleaseTimeslice(void)
462 //This does absolutely nothing!!! !!! FIX !!!
463 dsp_releaseTimeSlice_flag = 1;
466 void dsp_build_branch_condition_table(void)
468 // Fill in the mirror table
469 for(int i=0; i<65536; i++)
471 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
472 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
473 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
474 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
475 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
476 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
477 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
478 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
481 // Fill in the condition table
482 for(int i=0; i<8; i++)
484 for(int j=0; j<32; j++)
488 if ((j & 1) && (i & ZERO_FLAG))
491 if ((j & 2) && (!(i & ZERO_FLAG)))
494 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
497 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
500 dsp_branch_condition_table[i * 32 + j] = result;
505 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
507 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
508 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
510 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
513 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
515 if (offset==0xF1CFE0)
518 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
519 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
521 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
523 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
525 if ((offset&0x03)==0)
528 if ((offset&0x03)==1)
529 return((data>>16)&0xff);
531 if ((offset&0x03)==2)
532 return((data>>8)&0xff);
534 if ((offset&0x03)==3)
538 return JaguarReadByte(offset, who);
541 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
543 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
544 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
546 offset &= 0xFFFFFFFE;
548 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
550 offset -= DSP_WORK_RAM_BASE;
551 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
553 return GET16(dsp_ram_8, offset);
555 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
557 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
560 return data & 0xFFFF;
565 return JaguarReadWord(offset, who);
568 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
570 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
571 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
574 offset &= 0xFFFFFFFC;
575 /*if (offset == 0xF1BCF4)
577 WriteLog("DSPReadLong: Reading from 0xF1BCF4... -> %08X [%02X %02X %02X %02X][%04X %04X]\n", GET32(dsp_ram_8, 0x0CF4), dsp_ram_8[0x0CF4], dsp_ram_8[0x0CF5], dsp_ram_8[0x0CF6], dsp_ram_8[0x0CF7], JaguarReadWord(0xF1BCF4, DSP), JaguarReadWord(0xF1BCF6, DSP));
578 DSPDumpDisassembly();
580 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
582 offset -= DSP_WORK_RAM_BASE;
583 return GET32(dsp_ram_8, offset);
585 //NOTE: Didn't return DSP_ACCUM!!!
586 //Mebbe it's not 'spose to! Yes, it is!
587 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
593 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
594 return dsp_flags & 0xFFFFC1FF;
595 case 0x04: return dsp_matrix_control;
596 case 0x08: return dsp_pointer_to_matrix;
597 case 0x0C: return dsp_data_organization;
598 case 0x10: return dsp_pc;
599 case 0x14: return dsp_control;
600 case 0x18: return dsp_modulo;
601 case 0x1C: return dsp_remain;
603 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
605 // unaligned long read-- !!! FIX !!!
609 return JaguarReadLong(offset, who);
612 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
614 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
615 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
617 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
619 offset -= DSP_WORK_RAM_BASE;
620 dsp_ram_8[offset] = data;
621 //This is rather stupid! !!! FIX !!!
622 /* if (dsp_in_exec == 0)
624 m68k_end_timeslice();
625 dsp_releaseTimeslice();
629 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
631 uint32_t reg = offset & 0x1C;
632 int bytenum = offset & 0x03;
634 if ((reg >= 0x1C) && (reg <= 0x1F))
635 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
638 //This looks funky. !!! FIX !!!
639 uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
640 bytenum = 3 - bytenum; // convention motorola !!!
641 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
642 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
646 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
647 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
648 JaguarWriteByte(offset, data, who);
651 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
653 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
654 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
655 offset &= 0xFFFFFFFE;
656 /*if (offset == 0xF1BCF4)
658 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
660 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
661 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
663 /*if (offset == 0xF1B2F4)
665 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
667 offset -= DSP_WORK_RAM_BASE;
668 dsp_ram_8[offset] = data >> 8;
669 dsp_ram_8[offset+1] = data & 0xFF;
670 //This is rather stupid! !!! FIX !!!
671 /* if (dsp_in_exec == 0)
673 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
674 m68k_end_timeslice();
675 dsp_releaseTimeslice();
679 SET16(ram1, offset, data),
680 SET16(ram2, offset, data);
685 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
687 if ((offset & 0x1C) == 0x1C)
690 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
692 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
696 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
699 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
701 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
703 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
709 JaguarWriteWord(offset, data, who);
712 //bool badWrite = false;
713 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
715 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
716 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
718 offset &= 0xFFFFFFFC;
719 /*if (offset == 0xF1BCF4)
721 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
723 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
724 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
726 /*if (offset == 0xF1BE2C)
728 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
730 offset -= DSP_WORK_RAM_BASE;
731 SET32(dsp_ram_8, offset, data);
734 SET32(ram1, offset, data),
735 SET32(ram2, offset, data);
740 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
748 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
750 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
751 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
752 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
753 // IRQ logic can set it. So we mask it out here to prevent problems...
754 dsp_flags = data & (~IMASK);
755 dsp_flag_z = dsp_flags & 0x01;
756 dsp_flag_c = (dsp_flags >> 1) & 0x01;
757 dsp_flag_n = (dsp_flags >> 2) & 0x01;
758 DSPUpdateRegisterBanks();
759 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
760 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
764 dsp_matrix_control = data;
767 // According to JTRM, only lines 2-11 are addressable, the rest being
768 // hardwired to $F1Bxxx.
769 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
772 dsp_data_organization = data;
777 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
782 ctrl1[0] = ctrl2[0] = data;
789 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
791 bool wasRunning = DSP_RUNNING;
792 // uint32_t dsp_was_running = DSP_RUNNING;
793 // Check for DSP -> CPU interrupt
797 WriteLog("DSP: DSP -> CPU interrupt\n");
800 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
801 if (JERRYIRQEnabled(IRQ2_DSP))
803 JERRYSetPendingIRQ(IRQ2_DSP);
804 DSPReleaseTimeslice();
805 m68k_set_irq(2); // Set 68000 IPL 2...
809 // Check for CPU -> DSP interrupt
813 WriteLog("DSP: CPU -> DSP interrupt\n");
815 m68k_end_timeslice();
816 DSPReleaseTimeslice();
817 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
821 if (data & SINGLE_STEP)
823 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
826 // Protect writes to VERSION and the interrupt latches...
827 uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
828 dsp_control = (dsp_control & mask) | (data & ~mask);
832 ctrl1[8] = ctrl2[8] = dsp_control;
836 // if dsp wasn't running but is now running
837 // execute a few cycles
838 //This is just plain wrong, wrong, WRONG!
839 #ifndef DSP_SINGLE_STEPPING
840 /* if (!dsp_was_running && DSP_RUNNING)
845 //This is WRONG! !!! FIX !!!
846 if (dsp_control & 0x18)
851 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
853 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
856 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
857 // !!! FIX !!! [DONE]
861 m68k_end_timeslice();
863 DSPReleaseTimeslice();
867 //DSPDumpDisassembly();
872 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
876 dsp_div_control = data;
878 // default: // unaligned long read
884 //We don't have to break this up like this! We CAN do 32 bit writes!
885 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
886 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
887 //if (offset > 0xF1FFFF)
889 JaguarWriteLong(offset, data, who);
893 // Update the DSP register file pointers depending on REGPAGE bit
895 void DSPUpdateRegisterBanks(void)
897 int bank = (dsp_flags & REGPAGE);
899 if (dsp_flags & IMASK)
900 bank = 0; // IMASK forces main bank to be bank 0
903 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
905 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
908 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
913 // Check for and handle any asserted DSP IRQs
915 void DSPHandleIRQs(void)
917 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
920 // Get the active interrupt bits (latches) & interrupt mask (enables)
921 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
922 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
924 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
927 if (!bits) // Bail if nothing is enabled
930 int which = 0; // Determine which interrupt
946 WriteLog("DSP: Generating interrupt #%i...", which);
949 //if (which == 0) doDSPDis = true;
951 // NOTE: Since the actual Jaguar hardware injects the code sequence below
952 // directly into the pipeline, it has the side effect of ensuring that the
953 // instruction interrupted also gets to do its writeback. We simulate that
955 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
957 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
958 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
960 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
961 scoreboard[pipeline[plPtrWrite].operand2] = false;
963 //This should be execute (or should it?--not sure now!)
964 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
965 //and what just executed is now in the Write position...). So why didn't it do the
966 //writeback into register 0?
968 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
969 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
970 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
971 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
973 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
975 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
977 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
978 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
981 if (pipeline[plPtrWrite].type == TYPE_BYTE)
982 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
983 else if (pipeline[plPtrWrite].type == TYPE_WORD)
984 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
986 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
990 #ifndef NEW_SCOREBOARD
991 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
992 scoreboard[pipeline[plPtrWrite].operand2] = false;
994 //Yup, sequential MOVEQ # problem fixing (I hope!)...
995 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
996 if (scoreboard[pipeline[plPtrWrite].operand2])
997 scoreboard[pipeline[plPtrWrite].operand2]--;
1004 ctrl2[4] = dsp_flags;
1007 DSPUpdateRegisterBanks();
1008 #ifdef DSP_DEBUG_IRQ
1009 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1010 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), dsp_reg[31]);
1013 // subqt #4,r31 ; pre-decrement stack pointer
1014 // move pc,r30 ; address of interrupted code
1015 // store r30,(r31) ; store return address
1022 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1023 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1024 //It missed the place that it was supposed to come back to, so this is WRONG!
1026 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1028 // R -> baz (<- PC points here)
1029 // E -> bar (when it should point here!)
1032 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1033 // which means (assuming they're all 2 bytes long) that the code below will come back on
1034 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1035 // instruction stream...
1037 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1038 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1041 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1045 // movei #service_address,r30 ; pointer to ISR entry
1046 // jump (r30) ; jump to ISR
1048 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1051 ctrl2[0] = regs2[30] = dsp_pc;
1058 // Non-pipelined version...
1060 void DSPHandleIRQsNP(void)
1064 memcpy(dsp_ram_8, ram1, 0x2000);
1065 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1066 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1069 dsp_remain = ctrl1[2];
1070 dsp_modulo = ctrl1[3];
1071 dsp_flags = ctrl1[4];
1072 dsp_matrix_control = ctrl1[5];
1073 dsp_pointer_to_matrix = ctrl1[6];
1074 dsp_data_organization = ctrl1[7];
1075 dsp_control = ctrl1[8];
1076 dsp_div_control = ctrl1[9];
1077 IMASKCleared = ctrl1[10];
1078 dsp_flag_z = ctrl1[11];
1079 dsp_flag_n = ctrl1[12];
1080 dsp_flag_c = ctrl1[13];
1081 DSPUpdateRegisterBanks();
1084 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1087 // Get the active interrupt bits (latches) & interrupt mask (enables)
1088 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1089 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1091 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1094 if (!bits) // Bail if nothing is enabled
1097 int which = 0; // Determine which interrupt
1111 dsp_flags |= IMASK; // Force Bank #0
1114 ctrl1[4] = dsp_flags;
1117 #ifdef DSP_DEBUG_IRQ
1118 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1119 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1121 DSPUpdateRegisterBanks();
1122 #ifdef DSP_DEBUG_IRQ
1123 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1124 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1127 #ifdef DSP_DEBUG_IRQ
1128 WriteLog("DSP: Generating interrupt #%i...", which);
1129 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1132 // subqt #4,r31 ; pre-decrement stack pointer
1133 // move pc,r30 ; address of interrupted code
1134 // store r30,(r31) ; store return address
1136 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1143 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1144 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1147 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1151 // movei #service_address,r30 ; pointer to ISR entry
1152 // jump (r30) ; jump to ISR
1154 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1157 ctrl1[0] = regs1[30] = dsp_pc;
1163 // Set the specified DSP IRQ line to a given state
1165 void DSPSetIRQLine(int irqline, int state)
1167 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1168 uint32_t mask = INT_LAT0 << irqline;
1169 dsp_control &= ~mask; // Clear the latch bit
1172 ctrl1[8] = ctrl2[8] = dsp_control;
1178 dsp_control |= mask; // Set the latch bit
1179 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1184 ctrl1[8] = ctrl2[8] = dsp_control;
1190 // Not sure if this is correct behavior, but according to JTRM,
1191 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1192 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1193 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1196 bool DSPIsRunning(void)
1198 return (DSP_RUNNING ? true : false);
1203 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1204 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1205 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1207 dsp_build_branch_condition_table();
1213 dsp_pc = 0x00F1B000;
1214 dsp_acc = 0x00000000;
1215 dsp_remain = 0x00000000;
1216 dsp_modulo = 0xFFFFFFFF;
1217 dsp_flags = 0x00040000;
1218 dsp_matrix_control = 0x00000000;
1219 dsp_pointer_to_matrix = 0x00000000;
1220 dsp_data_organization = 0xFFFFFFFF;
1221 dsp_control = 0x00002000; // Report DSP version 2
1222 dsp_div_control = 0x00000000;
1225 dsp_reg = dsp_reg_bank_0;
1226 dsp_alternate_reg = dsp_reg_bank_1;
1228 for(int i=0; i<32; i++)
1229 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1232 IMASKCleared = false;
1236 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1237 for(uint32_t i=0; i<8192; i+=4)
1238 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1241 void DSPDumpDisassembly(void)
1245 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1246 uint32_t j = 0xF1B000;
1248 while (j <= 0xF1CFFF)
1251 j += dasmjag(JAGUAR_DSP, buffer, j);
1252 WriteLog("\t%08X: %s\n", oldj, buffer);
1256 void DSPDumpRegisters(void)
1258 //Shoud add modulus, etc to dump here...
1259 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1260 WriteLog("\nRegisters bank 0\n");
1262 for(int j=0; j<8; j++)
1264 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1265 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1266 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1267 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1268 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1271 WriteLog("Registers bank 1\n");
1273 for(int j=0; j<8; j++)
1275 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1276 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1277 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1278 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1279 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1286 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1287 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1289 // get the active interrupt bits
1290 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1291 // get the interrupt mask
1292 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1294 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1295 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1296 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1297 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1298 WriteLog("\nRegisters bank 0\n");
1300 for(int j=0; j<8; j++)
1302 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1303 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1304 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1305 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1306 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1309 WriteLog("\nRegisters bank 1\n");
1313 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1314 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1315 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1316 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1317 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1322 static char buffer[512];
1323 j = DSP_WORK_RAM_BASE;
1325 while (j <= 0xF1CFFF)
1328 j += dasmjag(JAGUAR_DSP, buffer, j);
1329 WriteLog("\t%08X: %s\n", oldj, buffer);
1332 WriteLog("DSP opcodes use:\n");
1336 if (dsp_opcode_use[i])
1337 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1344 // DSP comparison core...
1347 static uint16_t lastExec;
1348 void DSPExecComp(int32_t cycles)
1350 while (cycles > 0 && DSP_RUNNING)
1352 // Load up vars for non-pipelined core
1353 memcpy(dsp_ram_8, ram1, 0x2000);
1354 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1355 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1358 dsp_remain = ctrl1[2];
1359 dsp_modulo = ctrl1[3];
1360 dsp_flags = ctrl1[4];
1361 dsp_matrix_control = ctrl1[5];
1362 dsp_pointer_to_matrix = ctrl1[6];
1363 dsp_data_organization = ctrl1[7];
1364 dsp_control = ctrl1[8];
1365 dsp_div_control = ctrl1[9];
1366 IMASKCleared = ctrl1[10];
1367 dsp_flag_z = ctrl1[11];
1368 dsp_flag_n = ctrl1[12];
1369 dsp_flag_c = ctrl1[13];
1370 DSPUpdateRegisterBanks();
1372 // Decrement cycles based on non-pipelined core...
1373 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1374 cycles -= dsp_opcode_cycles[instr1 >> 10];
1376 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1377 DSPExec(1); // Do *one* instruction
1380 memcpy(ram1, dsp_ram_8, 0x2000);
1381 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1382 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1385 ctrl1[2] = dsp_remain;
1386 ctrl1[3] = dsp_modulo;
1387 ctrl1[4] = dsp_flags;
1388 ctrl1[5] = dsp_matrix_control;
1389 ctrl1[6] = dsp_pointer_to_matrix;
1390 ctrl1[7] = dsp_data_organization;
1391 ctrl1[8] = dsp_control;
1392 ctrl1[9] = dsp_div_control;
1393 ctrl1[10] = IMASKCleared;
1394 ctrl1[11] = dsp_flag_z;
1395 ctrl1[12] = dsp_flag_n;
1396 ctrl1[13] = dsp_flag_c;
1398 // Load up vars for pipelined core
1399 memcpy(dsp_ram_8, ram2, 0x2000);
1400 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1401 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1404 dsp_remain = ctrl2[2];
1405 dsp_modulo = ctrl2[3];
1406 dsp_flags = ctrl2[4];
1407 dsp_matrix_control = ctrl2[5];
1408 dsp_pointer_to_matrix = ctrl2[6];
1409 dsp_data_organization = ctrl2[7];
1410 dsp_control = ctrl2[8];
1411 dsp_div_control = ctrl2[9];
1412 IMASKCleared = ctrl2[10];
1413 dsp_flag_z = ctrl2[11];
1414 dsp_flag_n = ctrl2[12];
1415 dsp_flag_c = ctrl2[13];
1416 DSPUpdateRegisterBanks();
1418 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1419 DSPExecP2(1); // Do *one* instruction
1422 memcpy(ram2, dsp_ram_8, 0x2000);
1423 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1424 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1427 ctrl2[2] = dsp_remain;
1428 ctrl2[3] = dsp_modulo;
1429 ctrl2[4] = dsp_flags;
1430 ctrl2[5] = dsp_matrix_control;
1431 ctrl2[6] = dsp_pointer_to_matrix;
1432 ctrl2[7] = dsp_data_organization;
1433 ctrl2[8] = dsp_control;
1434 ctrl2[9] = dsp_div_control;
1435 ctrl2[10] = IMASKCleared;
1436 ctrl2[11] = dsp_flag_z;
1437 ctrl2[12] = dsp_flag_n;
1438 ctrl2[13] = dsp_flag_c;
1440 if (instr1 != lastExec)
1442 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1444 // uint32_t ppc = ctrl2[0] - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)) - (pipeline[plPtrWrite].opcode == 38 ? 6 : (pipeline[plPtrWrite].opcode == PIPELINE_STALL ? 0 : 2));
1445 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1446 // if (ctrl1[0] < ppc) // P ran ahead of NP
1447 //How to test this crap???
1450 DSPExecP2(1); // Do one more instruction
1453 memcpy(ram2, dsp_ram_8, 0x2000);
1454 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1455 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1458 ctrl2[2] = dsp_remain;
1459 ctrl2[3] = dsp_modulo;
1460 ctrl2[4] = dsp_flags;
1461 ctrl2[5] = dsp_matrix_control;
1462 ctrl2[6] = dsp_pointer_to_matrix;
1463 ctrl2[7] = dsp_data_organization;
1464 ctrl2[8] = dsp_control;
1465 ctrl2[9] = dsp_div_control;
1466 ctrl2[10] = IMASKCleared;
1467 ctrl2[11] = dsp_flag_z;
1468 ctrl2[12] = dsp_flag_n;
1469 ctrl2[13] = dsp_flag_c;
1471 // else // NP ran ahead of P
1472 if (instr1 != lastExec) // Must be the other way...
1475 // Load up vars for non-pipelined core
1476 memcpy(dsp_ram_8, ram1, 0x2000);
1477 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1478 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1481 dsp_remain = ctrl1[2];
1482 dsp_modulo = ctrl1[3];
1483 dsp_flags = ctrl1[4];
1484 dsp_matrix_control = ctrl1[5];
1485 dsp_pointer_to_matrix = ctrl1[6];
1486 dsp_data_organization = ctrl1[7];
1487 dsp_control = ctrl1[8];
1488 dsp_div_control = ctrl1[9];
1489 IMASKCleared = ctrl1[10];
1490 dsp_flag_z = ctrl1[11];
1491 dsp_flag_n = ctrl1[12];
1492 dsp_flag_c = ctrl1[13];
1493 DSPUpdateRegisterBanks();
1495 for(int k=0; k<2; k++)
1497 // Decrement cycles based on non-pipelined core...
1498 instr1 = DSPReadWord(dsp_pc, DSP);
1499 cycles -= dsp_opcode_cycles[instr1 >> 10];
1501 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1502 DSPExec(1); // Do *one* instruction
1506 memcpy(ram1, dsp_ram_8, 0x2000);
1507 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1508 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1511 ctrl1[2] = dsp_remain;
1512 ctrl1[3] = dsp_modulo;
1513 ctrl1[4] = dsp_flags;
1514 ctrl1[5] = dsp_matrix_control;
1515 ctrl1[6] = dsp_pointer_to_matrix;
1516 ctrl1[7] = dsp_data_organization;
1517 ctrl1[8] = dsp_control;
1518 ctrl1[9] = dsp_div_control;
1519 ctrl1[10] = IMASKCleared;
1520 ctrl1[11] = dsp_flag_z;
1521 ctrl1[12] = dsp_flag_n;
1522 ctrl1[13] = dsp_flag_c;
1526 if (instr1 != lastExec)
1528 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1530 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1531 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1544 // DSP execution core
1546 //static bool R20Set = false, tripwire = false;
1547 //static uint32_t pcQueue[32], ptrPCQ = 0;
1548 void DSPExec(int32_t cycles)
1550 #ifdef DSP_SINGLE_STEPPING
1551 if (dsp_control & 0x18)
1554 dsp_control &= ~0x10;
1557 //There is *no* good reason to do this here!
1559 dsp_releaseTimeSlice_flag = 0;
1562 while (cycles > 0 && DSP_RUNNING)
1564 /*extern uint32_t totalFrames;
1565 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1566 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1567 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1569 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1572 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1574 if (dsp_pc == 0xF1B092)
1575 doDSPDis = false;//*/
1576 /*if (dsp_pc == 0xF1B140)
1577 doDSPDis = true;//*/
1579 if (IMASKCleared) // If IMASK was cleared,
1581 #ifdef DSP_DEBUG_IRQ
1582 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1584 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1585 IMASKCleared = false;
1590 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1591 for(int i=0; i<80; i+=4)
1592 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1595 /*if (dsp_pc == 0xF1B55E)
1597 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1599 /*if (dsp_pc == 0xF1B7D2) // Start here???
1601 pcQueue[ptrPCQ++] = dsp_pc;
1603 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1604 uint32_t index = opcode >> 10;
1605 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1606 dsp_opcode_second_parameter = opcode & 0x1F;
1608 dsp_opcode[index]();
1609 dsp_opcode_use[index]++;
1610 cycles -= dsp_opcode_cycles[index];
1611 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1613 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1616 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1618 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1620 DSPDumpDisassembly();
1623 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1626 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1629 WriteLog("\nBacktrace:\n");
1630 for(int i=0; i<32; i++)
1632 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1633 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1643 // DSP opcode handlers
1646 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1647 // can cause trouble because an interrupt can occur *before* the instruction following the
1648 // jump can execute... !!! FIX !!!
1649 static void dsp_opcode_jump(void)
1652 const char * condition[32] =
1653 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1654 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1655 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1656 "???", "???", "???", "F" };
1658 WriteLog("%06X: JUMP %s, (R%02u) [NCZ:%u%u%u, R%02u=%08X] ", dsp_pc-2, condition[IMM_2], IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM);
1661 /* dsp_flag_c=dsp_flag_c?1:0;
1662 dsp_flag_z=dsp_flag_z?1:0;
1663 dsp_flag_n=dsp_flag_n?1:0;*/
1664 // KLUDGE: Used by BRANCH_CONDITION
1665 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1667 if (BRANCH_CONDITION(IMM_2))
1671 WriteLog("Branched!\n");
1673 uint32_t delayed_pc = RM;
1675 dsp_pc = delayed_pc;
1680 WriteLog("Branch NOT taken.\n");
1684 static void dsp_opcode_jr(void)
1687 const char * condition[32] =
1688 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1689 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1690 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1691 "???", "???", "???", "F" };
1693 WriteLog("%06X: JR %s, %06X [NCZ:%u%u%u] ", dsp_pc-2, condition[IMM_2], dsp_pc+((IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1) * 2), dsp_flag_n, dsp_flag_c, dsp_flag_z);
1696 /* dsp_flag_c=dsp_flag_c?1:0;
1697 dsp_flag_z=dsp_flag_z?1:0;
1698 dsp_flag_n=dsp_flag_n?1:0;*/
1699 // KLUDGE: Used by BRANCH_CONDITION
1700 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1702 if (BRANCH_CONDITION(IMM_2))
1706 WriteLog("Branched!\n");
1708 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1709 int32_t delayed_pc = dsp_pc + (offset * 2);
1711 dsp_pc = delayed_pc;
1716 WriteLog("Branch NOT taken.\n");
1720 static void dsp_opcode_add(void)
1724 WriteLog("%06X: ADD R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1726 uint32_t res = RN + RM;
1727 SET_ZNC_ADD(RN, RM, res);
1731 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1735 static void dsp_opcode_addc(void)
1739 WriteLog("%06X: ADDC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1741 uint32_t res = RN + RM + dsp_flag_c;
1742 uint32_t carry = dsp_flag_c;
1743 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1744 SET_ZNC_ADD(RN + carry, RM, res);
1745 // SET_ZNC_ADD(RN, RM + carry, res);
1749 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1753 static void dsp_opcode_addq(void)
1757 WriteLog("%06X: ADDQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1759 uint32_t r1 = dsp_convert_zero[IMM_1];
1760 uint32_t res = RN + r1;
1761 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1765 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1769 static void dsp_opcode_sub(void)
1773 WriteLog("%06X: SUB R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1775 uint32_t res = RN - RM;
1776 SET_ZNC_SUB(RN, RM, res);
1780 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1784 static void dsp_opcode_subc(void)
1788 WriteLog("%06X: SUBC R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1790 uint32_t res = RN - RM - dsp_flag_c;
1791 uint32_t borrow = dsp_flag_c;
1792 SET_ZNC_SUB(RN - borrow, RM, res);
1796 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1800 static void dsp_opcode_subq(void)
1804 WriteLog("%06X: SUBQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1806 uint32_t r1 = dsp_convert_zero[IMM_1];
1807 uint32_t res = RN - r1;
1808 SET_ZNC_SUB(RN, r1, res);
1812 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1816 static void dsp_opcode_cmp(void)
1820 WriteLog("%06X: CMP R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1822 uint32_t res = RN - RM;
1823 SET_ZNC_SUB(RN, RM, res);
1826 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1830 static void dsp_opcode_cmpq(void)
1832 static int32_t sqtable[32] =
1833 { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1 };
1836 WriteLog("%06X: CMPQ #%d, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, sqtable[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1838 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1839 uint32_t res = RN - r1;
1840 SET_ZNC_SUB(RN, r1, res);
1843 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1847 static void dsp_opcode_and(void)
1851 WriteLog("%06X: AND R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1857 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1861 static void dsp_opcode_or(void)
1865 WriteLog("%06X: OR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1871 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1875 static void dsp_opcode_xor(void)
1879 WriteLog("%06X: XOR R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1885 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
1889 static void dsp_opcode_not(void)
1893 WriteLog("%06X: NOT R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1899 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1903 static void dsp_opcode_move_pc(void)
1908 static void dsp_opcode_store_r14_indexed(void)
1910 #ifdef DSP_DIS_STORE14I
1912 WriteLog("%06X: STORE R%02u, (R14+$%02X) [NCZ:%u%u%u, R%02u=%08X, R14+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2));
1914 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1915 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1917 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1921 static void dsp_opcode_store_r15_indexed(void)
1923 #ifdef DSP_DIS_STORE15I
1925 WriteLog("%06X: STORE R%02u, (R15+$%02X) [NCZ:%u%u%u, R%02u=%08X, R15+$%02X=%08X]\n", dsp_pc-2, IMM_2, dsp_convert_zero[IMM_1] << 2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2));
1927 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1928 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1930 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1934 static void dsp_opcode_load_r14_ri(void)
1936 #ifdef DSP_DIS_LOAD14R
1938 WriteLog("%06X: LOAD (R14+R%02u), R%02u [NCZ:%u%u%u, R14+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[14], IMM_2, RN);
1940 #ifdef DSP_CORRECT_ALIGNMENT
1941 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1943 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1945 #ifdef DSP_DIS_LOAD14R
1947 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1951 static void dsp_opcode_load_r15_ri(void)
1953 #ifdef DSP_DIS_LOAD15R
1955 WriteLog("%06X: LOAD (R15+R%02u), R%02u [NCZ:%u%u%u, R15+R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM+dsp_reg[15], IMM_2, RN);
1957 #ifdef DSP_CORRECT_ALIGNMENT
1958 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1960 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1962 #ifdef DSP_DIS_LOAD15R
1964 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1968 static void dsp_opcode_store_r14_ri(void)
1970 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
1973 static void dsp_opcode_store_r15_ri(void)
1975 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
1978 static void dsp_opcode_nop(void)
1982 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
1986 static void dsp_opcode_storeb(void)
1988 #ifdef DSP_DIS_STOREB
1990 WriteLog("%06X: STOREB R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
1992 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
1993 DSPWriteLong(RM, RN & 0xFF, DSP);
1995 JaguarWriteByte(RM, RN, DSP);
1998 static void dsp_opcode_storew(void)
2000 #ifdef DSP_DIS_STOREW
2002 WriteLog("%06X: STOREW R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
2004 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2005 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2006 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2008 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2010 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2011 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2013 JaguarWriteWord(RM, RN, DSP);
2017 static void dsp_opcode_store(void)
2019 #ifdef DSP_DIS_STORE
2021 WriteLog("%06X: STORE R%02u, (R%02u) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_pc-2, IMM_2, IMM_1, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, IMM_1, RM);
2023 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2024 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2026 DSPWriteLong(RM, RN, DSP);
2030 static void dsp_opcode_loadb(void)
2032 #ifdef DSP_DIS_LOADB
2034 WriteLog("%06X: LOADB (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2036 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037 RN = DSPReadLong(RM, DSP) & 0xFF;
2039 RN = JaguarReadByte(RM, DSP);
2040 #ifdef DSP_DIS_LOADB
2042 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2046 static void dsp_opcode_loadw(void)
2048 #ifdef DSP_DIS_LOADW
2050 WriteLog("%06X: LOADW (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2052 #ifdef DSP_CORRECT_ALIGNMENT
2053 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2054 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2056 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2058 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2059 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2061 RN = JaguarReadWord(RM, DSP);
2063 #ifdef DSP_DIS_LOADW
2065 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2069 static void dsp_opcode_load(void)
2073 WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2075 #ifdef DSP_CORRECT_ALIGNMENT
2076 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2078 RN = DSPReadLong(RM, DSP);
2082 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2086 static void dsp_opcode_load_r14_indexed(void)
2088 #ifdef DSP_DIS_LOAD14I
2090 WriteLog("%06X: LOAD (R14+$%02X), R%02u [NCZ:%u%u%u, R14+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[14]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN);
2092 #ifdef DSP_CORRECT_ALIGNMENT
2093 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2095 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2097 #ifdef DSP_DIS_LOAD14I
2099 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2103 static void dsp_opcode_load_r15_indexed(void)
2105 #ifdef DSP_DIS_LOAD15I
2107 WriteLog("%06X: LOAD (R15+$%02X), R%02u [NCZ:%u%u%u, R15+$%02X=%08X, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1] << 2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_convert_zero[IMM_1] << 2, dsp_reg[15]+(dsp_convert_zero[IMM_1] << 2), IMM_2, RN);
2109 #ifdef DSP_CORRECT_ALIGNMENT
2110 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2112 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2114 #ifdef DSP_DIS_LOAD15I
2116 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2120 static void dsp_opcode_movei(void)
2122 #ifdef DSP_DIS_MOVEI
2124 WriteLog("%06X: MOVEI #$%08X, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, (uint32_t)DSPReadWord(dsp_pc) | ((uint32_t)DSPReadWord(dsp_pc + 2) << 16), IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2126 // This instruction is followed by 32-bit value in LSW / MSW format...
2127 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2129 #ifdef DSP_DIS_MOVEI
2131 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2135 static void dsp_opcode_moveta(void)
2137 #ifdef DSP_DIS_MOVETA
2139 WriteLog("%06X: MOVETA R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2142 #ifdef DSP_DIS_MOVETA
2144 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u(alt)=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, ALTERNATE_RN);
2148 static void dsp_opcode_movefa(void)
2150 #ifdef DSP_DIS_MOVEFA
2152 WriteLog("%06X: MOVEFA R%02u, R%02u [NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2155 #ifdef DSP_DIS_MOVEFA
2157 WriteLog("[NCZ:%u%u%u, R%02u(alt)=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, ALTERNATE_RM, IMM_2, RN);
2161 static void dsp_opcode_move(void)
2165 WriteLog("%06X: MOVE R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2170 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2174 static void dsp_opcode_moveq(void)
2176 #ifdef DSP_DIS_MOVEQ
2178 WriteLog("%06X: MOVEQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2181 #ifdef DSP_DIS_MOVEQ
2183 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2187 static void dsp_opcode_resmac(void)
2189 #ifdef DSP_DIS_RESMAC
2191 WriteLog("%06X: RESMAC R%02u [NCZ:%u%u%u, R%02u=%08X, DSP_ACC=%02X%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2193 RN = (uint32_t)dsp_acc;
2194 #ifdef DSP_DIS_RESMAC
2196 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2200 static void dsp_opcode_imult(void)
2202 #ifdef DSP_DIS_IMULT
2204 WriteLog("%06X: IMULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2206 RN = (int16_t)RN * (int16_t)RM;
2208 #ifdef DSP_DIS_IMULT
2210 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2214 static void dsp_opcode_mult(void)
2218 WriteLog("%06X: MULT R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2220 RN = (uint16_t)RM * (uint16_t)RN;
2224 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2228 static void dsp_opcode_bclr(void)
2232 WriteLog("%06X: BCLR #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2234 uint32_t res = RN & ~(1 << IMM_1);
2239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2243 static void dsp_opcode_btst(void)
2247 WriteLog("%06X: BTST #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2249 dsp_flag_z = (~RN >> IMM_1) & 1;
2252 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2256 static void dsp_opcode_bset(void)
2260 WriteLog("%06X: BSET #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2262 uint32_t res = RN | (1 << IMM_1);
2267 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2271 static void dsp_opcode_subqt(void)
2273 #ifdef DSP_DIS_SUBQT
2275 WriteLog("%06X: SUBQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2277 RN -= dsp_convert_zero[IMM_1];
2278 #ifdef DSP_DIS_SUBQT
2280 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2284 static void dsp_opcode_addqt(void)
2286 #ifdef DSP_DIS_ADDQT
2288 WriteLog("%06X: ADDQT #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, dsp_convert_zero[IMM_1], IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2290 RN += dsp_convert_zero[IMM_1];
2291 #ifdef DSP_DIS_ADDQT
2293 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2297 static void dsp_opcode_imacn(void)
2299 #ifdef DSP_DIS_IMACN
2301 WriteLog("%06X: IMACN R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
2303 int32_t res = (int16_t)RM * (int16_t)RN;
2304 dsp_acc += (int64_t)res;
2305 //Should we AND the result to fit into 40 bits here???
2306 #ifdef DSP_DIS_IMACN
2308 WriteLog("[NCZ:%u%u%u, DSP_ACC=%02X%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, (uint8_t)(dsp_acc >> 32), (uint32_t)(dsp_acc & 0xFFFFFFFF));
2312 static void dsp_opcode_mtoi(void)
2314 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2318 static void dsp_opcode_normi(void)
2325 while ((_Rm & 0xffc00000) == 0)
2330 while ((_Rm & 0xff800000) != 0)
2340 static void dsp_opcode_mmult(void)
2342 int count = dsp_matrix_control&0x0f;
2343 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2347 if (!(dsp_matrix_control & 0x10))
2349 for (int i = 0; i < count; i++)
2353 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2355 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2356 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2363 for (int i = 0; i < count; i++)
2367 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2369 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2370 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2375 RN = res = (int32_t)accum;
2377 //NOTE: The flags are set based upon the last add/multiply done...
2381 static void dsp_opcode_abs(void)
2385 WriteLog("%06X: ABS R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2390 if (_Rn == 0x80000000)
2394 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2395 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2400 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2404 static void dsp_opcode_div(void)
2412 if (dsp_div_control & 1)
2414 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2415 if (dsp_remain&0x80000000)
2417 RN = (((uint64_t)_Rn) << 16) / _Rm;
2421 dsp_remain = _Rn % _Rm;
2422 if (dsp_remain&0x80000000)
2432 if (dsp_div_control & 0x01) // 16.16 division
2434 dsp_remain = ((uint64_t)RN << 16) % RM;
2435 RN = ((uint64_t)RN << 16) / RM;
2439 // We calculate the remainder first because we destroy RN after
2440 // this by assigning it to itself.
2441 dsp_remain = RN % RM;
2445 // What we really should do here is figure out why this condition
2446 // happens in the real divide unit and emulate *that* behavior.
2448 if ((gpu_remain - RM) & 0x80000000) // If the result would have been negative...
2449 gpu_remain -= RM; // Then make it negative!
2457 static void dsp_opcode_imultn(void)
2459 #ifdef DSP_DIS_IMULTN
2461 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);
2463 // This is OK, since this multiply won't overflow 32 bits...
2464 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2465 dsp_acc = (int64_t)res;
2467 #ifdef DSP_DIS_IMULTN
2469 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));
2473 static void dsp_opcode_neg(void)
2477 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);
2480 SET_ZNC_SUB(0, RN, res);
2484 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2488 static void dsp_opcode_shlq(void)
2492 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);
2494 // NB: This instruction is the *only* one that does (32 - immediate data).
2495 int32_t r1 = 32 - IMM_1;
2496 uint32_t res = RN << r1;
2497 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2501 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2505 static void dsp_opcode_shrq(void)
2509 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);
2511 int32_t r1 = dsp_convert_zero[IMM_1];
2512 uint32_t res = RN >> r1;
2513 SET_ZN(res); dsp_flag_c = RN & 1;
2517 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2521 static void dsp_opcode_ror(void)
2525 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);
2527 uint32_t r1 = RM & 0x1F;
2528 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2529 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2533 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);
2537 static void dsp_opcode_rorq(void)
2541 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);
2543 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2545 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2547 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2550 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2554 static void dsp_opcode_sha(void)
2556 int32_t sRm=(int32_t)RM;
2561 uint32_t shift=-sRm;
2562 if (shift>=32) shift=32;
2563 dsp_flag_c=(_Rn&0x80000000)>>31;
2573 if (shift>=32) shift=32;
2577 _Rn=((int32_t)_Rn)>>1;
2585 static void dsp_opcode_sharq(void)
2587 #ifdef DSP_DIS_SHARQ
2589 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);
2591 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2592 SET_ZN(res); dsp_flag_c = RN & 0x01;
2594 #ifdef DSP_DIS_SHARQ
2596 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2600 static void dsp_opcode_sh(void)
2602 int32_t sRm=(int32_t)RM;
2607 uint32_t shift=(-sRm);
2608 if (shift>=32) shift=32;
2609 dsp_flag_c=(_Rn&0x80000000)>>31;
2619 if (shift>=32) shift=32;
2631 void dsp_opcode_addqmod(void)
2633 #ifdef DSP_DIS_ADDQMOD
2635 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);
2637 uint32_t r1 = dsp_convert_zero[IMM_1];
2639 uint32_t res = r2 + r1;
2640 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2642 SET_ZNC_ADD(r2, r1, res);
2643 #ifdef DSP_DIS_ADDQMOD
2645 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2649 void dsp_opcode_subqmod(void)
2651 uint32_t r1 = dsp_convert_zero[IMM_1];
2653 uint32_t res = r2 - r1;
2654 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2657 SET_ZNC_SUB(r2, r1, res);
2660 void dsp_opcode_mirror(void)
2663 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2667 void dsp_opcode_sat32s(void)
2669 int32_t r2 = (uint32_t)RN;
2670 int32_t temp = dsp_acc >> 32;
2671 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2676 void dsp_opcode_sat16s(void)
2679 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2684 void dsp_opcode_illegal(void)
2686 // Don't know what it does, but it does *something*...
2687 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);
2691 // New pipelined DSP core
2694 static void DSP_abs(void);
2695 static void DSP_add(void);
2696 static void DSP_addc(void);
2697 static void DSP_addq(void);
2698 static void DSP_addqmod(void);
2699 static void DSP_addqt(void);
2700 static void DSP_and(void);
2701 static void DSP_bclr(void);
2702 static void DSP_bset(void);
2703 static void DSP_btst(void);
2704 static void DSP_cmp(void);
2705 static void DSP_cmpq(void);
2706 static void DSP_div(void);
2707 static void DSP_imacn(void);
2708 static void DSP_imult(void);
2709 static void DSP_imultn(void);
2710 static void DSP_illegal(void);
2711 static void DSP_jr(void);
2712 static void DSP_jump(void);
2713 static void DSP_load(void);
2714 static void DSP_loadb(void);
2715 static void DSP_loadw(void);
2716 static void DSP_load_r14_i(void);
2717 static void DSP_load_r14_r(void);
2718 static void DSP_load_r15_i(void);
2719 static void DSP_load_r15_r(void);
2720 static void DSP_mirror(void);
2721 static void DSP_mmult(void);
2722 static void DSP_move(void);
2723 static void DSP_movefa(void);
2724 static void DSP_movei(void);
2725 static void DSP_movepc(void);
2726 static void DSP_moveq(void);
2727 static void DSP_moveta(void);
2728 static void DSP_mtoi(void);
2729 static void DSP_mult(void);
2730 static void DSP_neg(void);
2731 static void DSP_nop(void);
2732 static void DSP_normi(void);
2733 static void DSP_not(void);
2734 static void DSP_or(void);
2735 static void DSP_resmac(void);
2736 static void DSP_ror(void);
2737 static void DSP_rorq(void);
2738 static void DSP_sat16s(void);
2739 static void DSP_sat32s(void);
2740 static void DSP_sh(void);
2741 static void DSP_sha(void);
2742 static void DSP_sharq(void);
2743 static void DSP_shlq(void);
2744 static void DSP_shrq(void);
2745 static void DSP_store(void);
2746 static void DSP_storeb(void);
2747 static void DSP_storew(void);
2748 static void DSP_store_r14_i(void);
2749 static void DSP_store_r14_r(void);
2750 static void DSP_store_r15_i(void);
2751 static void DSP_store_r15_r(void);
2752 static void DSP_sub(void);
2753 static void DSP_subc(void);
2754 static void DSP_subq(void);
2755 static void DSP_subqmod(void);
2756 static void DSP_subqt(void);
2757 static void DSP_xor(void);
2759 void (* DSPOpcode[64])() =
2761 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2762 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2763 DSP_neg, DSP_and, DSP_or, DSP_xor,
2764 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2766 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2767 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2768 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2769 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2771 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2772 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2773 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2774 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2776 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2777 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2778 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2779 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2782 bool readAffected[64][2] =
2784 { true, true}, { true, true}, {false, true}, {false, true},
2785 { true, true}, { true, true}, {false, true}, {false, true},
2786 {false, true}, { true, true}, { true, true}, { true, true},
2787 {false, true}, {false, true}, {false, true}, {false, true},
2789 { true, true}, { true, true}, { true, true}, {false, true},
2790 { true, true}, { true, true}, {false, true}, { true, true},
2791 {false, true}, {false, true}, { true, true}, {false, true},
2792 { true, true}, {false, true}, { true, true}, {false, true},
2794 {false, true}, {false, true}, { true, false}, {false, false},
2795 { true, false}, {false, false}, {false, false}, { true, false},
2796 { true, false}, { true, false}, {false, true}, { true, false},
2797 { true, false}, { true, true}, { true, true}, { true, true},
2799 {false, true}, { true, true}, { true, true}, {false, true},
2800 { true, false}, { true, false}, { true, true}, { true, false},
2801 { true, false}, {false, false}, { true, false}, { true, false},
2802 { true, true}, { true, true}, {false, false}, {false, true}
2805 bool isLoadStore[65] =
2807 false, false, false, false, false, false, false, false,
2808 false, false, false, false, false, false, false, false,
2810 false, false, false, false, false, false, false, false,
2811 false, false, false, false, false, false, false, false,
2813 false, false, false, false, false, false, false, true,
2814 true, true, false, true, true, true, true, true,
2816 false, true, true, false, false, false, false, false,
2817 false, false, true, true, true, true, false, false, false
2820 void FlushDSPPipeline(void)
2822 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2824 for(int i=0; i<4; i++)
2825 pipeline[i].opcode = PIPELINE_STALL;
2827 for(int i=0; i<32; i++)
2832 // New pipelined DSP execution core
2834 /*void DSPExecP(int32_t cycles)
2836 // bool inhibitFetch = false;
2838 dsp_releaseTimeSlice_flag = 0;
2841 while (cycles > 0 && DSP_RUNNING)
2843 WriteLog("DSPExecP: Pipeline status...\n");
2844 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);
2845 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);
2846 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);
2847 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);
2848 WriteLog(" --> Scoreboard: ");
2849 for(int i=0; i<32; i++)
2850 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2852 // Stage 1: Instruction fetch
2853 // if (!inhibitFetch)
2855 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2856 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2857 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2858 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2859 if (pipeline[plPtrFetch].opcode == 38)
2860 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2861 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2864 // inhibitFetch = false;
2865 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2867 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2868 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);
2869 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);
2870 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);
2871 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);
2872 // Stage 2: Read registers
2873 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2874 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2875 if (scoreboard[pipeline[plPtrRead].operand2])
2876 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2877 // We have a hit in the scoreboard, so we have to stall the pipeline...
2879 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2880 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2881 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2882 pipeline[plPtrFetch] = pipeline[plPtrRead];
2883 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2887 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2888 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2889 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2891 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2892 // Shouldn't we be more selective with the register scoreboarding?
2893 // Yes, we should. !!! FIX !!!
2894 scoreboard[pipeline[plPtrRead].operand2] = true;
2895 //Advance PC here??? Yes.
2896 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2897 //This is a mangling of the pipeline stages, but what else to do???
2898 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2901 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2902 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);
2903 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);
2904 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);
2905 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);
2907 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2909 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2910 DSPOpcode[pipeline[plPtrExec].opcode]();
2911 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2912 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2917 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2918 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);
2919 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);
2920 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);
2921 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);
2922 // Stage 4: Write back register
2923 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2925 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2926 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2928 scoreboard[pipeline[plPtrWrite].operand1]
2929 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2932 // Push instructions through the pipeline...
2933 plPtrFetch = (++plPtrFetch) & 0x03;
2934 plPtrRead = (++plPtrRead) & 0x03;
2935 plPtrExec = (++plPtrExec) & 0x03;
2936 plPtrWrite = (++plPtrWrite) & 0x03;
2943 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2945 // Should be fixed now. Another problem is figuring how to do the sequence following
2946 // a branch followed with the JR & JUMP instructions...
2948 // There are two conflicting problems:
2951 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2952 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2953 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2954 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
2955 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
2956 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
2957 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
2958 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
2959 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
2960 DSP: Writing 00004431 to DSP_FLAGS by DSP...
2961 DSP: Finished interrupt.
2962 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
2963 ; bank 0 (where is was prepared)!
2964 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
2965 F1B252: NOP [NCZ:001]
2968 // The other is when you see this at the end of an IRQ:
2971 JUMP T, (R29) ; R29 = Previous stack + 2
2972 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
2974 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
2975 ; 1) The STORE goes through the pipeline and is executed/written back
2976 ; 2) The pipeline is flushed
2977 ; 3) The DSP_PC is set to the new address
2978 ; 4) Execution resumes
2980 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
2981 ; bank 0 instead of the current bank 1 and so goes astray!
2984 //One other thing: Since these stages are supposed to happen simulaneously, try executing
2985 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
2989 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
2990 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
2991 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
2992 If it were done properly, the STORE write back would occur *after* (well, technically,
2993 during) the execution of the the JUMP that follows it.
2997 F1B08A: JR z, F1B082 [NCZ:001] Branched!
2998 F1B08A: NOP [NCZ:001]
3000 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3003 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3006 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3007 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3008 F1B08A: NOP [NCZ:001]
3010 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3013 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3014 DSP: CPU -> DSP interrupt
3015 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3016 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3018 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3021 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3022 F1B006: NOP [NCZ:001]
3024 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3027 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3028 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3031 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3032 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3035 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3036 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3039 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3040 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3043 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3046 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3049 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3050 F1B0FE: NOP [NCZ:000]
3052 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3055 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3058 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3059 F1B138: NOP [NCZ:000]
3061 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3064 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3065 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3066 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3069 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3070 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3073 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3074 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3075 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3077 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3078 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3081 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3082 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3083 DSP: Finished interrupt.
3084 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3086 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3089 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3090 F1B016: NOP [NCZ:001]
3092 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3095 uint32_t pcQueue1[0x400];
3096 uint32_t pcQPtr1 = 0;
3097 static uint32_t prevR1;
3098 //Let's try a 3 stage pipeline....
3099 //Looks like 3 stage is correct, otherwise bad things happen...
3100 void DSPExecP2(int32_t cycles)
3102 dsp_releaseTimeSlice_flag = 0;
3105 while (cycles > 0 && DSP_RUNNING)
3107 /*extern uint32_t totalFrames;
3108 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3109 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3110 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3112 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3115 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3117 if (dsp_pc == 0xF1B092)
3118 doDSPDis = false;//*/
3119 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3120 doDSPDis = true;//*/
3121 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3122 doDSPDis = true;//*/
3123 /*if (dsp_pc == 0xF1B0A0)
3124 doDSPDis = true;//*/
3125 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3126 doDSPDis = true;//*/
3127 //Two parter... (not sure how to write this)
3128 //if (dsp_pc == 0xF1B0D2)
3129 // prevR1 = dsp_reg[1];
3131 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3132 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3135 pcQueue1[pcQPtr1++] = dsp_pc;
3138 #ifdef DSP_DEBUG_PL2
3139 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3141 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3146 for(int i=0; i<0x400; i++)
3148 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3149 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3155 if (IMASKCleared) // If IMASK was cleared,
3157 #ifdef DSP_DEBUG_IRQ
3158 WriteLog("DSP: Finished interrupt.\n");
3160 DSPHandleIRQs(); // See if any other interrupts are pending!
3161 IMASKCleared = false;
3164 //if (dsp_flags & REGPAGE)
3165 // WriteLog(" --> REGPAGE has just been set!\n");
3166 #ifdef DSP_DEBUG_PL2
3169 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3170 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]);
3171 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]);
3172 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]);
3173 WriteLog(" --> Scoreboard: ");
3174 for(int i=0; i<32; i++)
3175 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3179 // Stage 1a: Instruction fetch
3180 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3181 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3182 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3183 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3184 if (pipeline[plPtrRead].opcode == 38)
3185 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3186 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3187 #ifdef DSP_DEBUG_PL2
3190 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3191 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3192 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]);
3193 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]);
3194 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]);
3197 // Stage 1b: Read registers
3198 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3199 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3201 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3202 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3203 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3204 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3205 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3206 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3207 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3209 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3210 // We have a hit in the scoreboard, so we have to stall the pipeline...
3211 #ifdef DSP_DEBUG_PL2
3215 WriteLog(" --> Stalling pipeline: ");
3216 if (readAffected[pipeline[plPtrRead].opcode][0])
3217 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3218 if (readAffected[pipeline[plPtrRead].opcode][1])
3219 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3223 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3224 #ifdef DSP_DEBUG_PL2
3229 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3230 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3231 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3233 // Shouldn't we be more selective with the register scoreboarding?
3234 // Yes, we should. !!! FIX !!! Kinda [DONE]
3235 #ifndef NEW_SCOREBOARD
3236 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3238 //Hopefully this will fix the dual MOVEQ # problem...
3239 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3242 //Advance PC here??? Yes.
3243 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3246 #ifdef DSP_DEBUG_PL2
3249 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3250 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]);
3251 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]);
3252 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]);
3256 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3258 #ifdef DSP_DEBUG_PL2
3260 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"));
3264 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3269 lastExec = pipeline[plPtrExec].instruction;
3270 //WriteLog("[lastExec = %04X]\n", lastExec);
3272 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3273 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3274 DSPOpcode[pipeline[plPtrExec].opcode]();
3275 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3279 //Let's not, until we do the stalling correctly...
3280 //But, we gotta while we're doing the comparison core...!
3281 //Or do we? cycles--;
3282 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3283 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3284 //to model this clock cycle behavior correctly...
3285 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3286 //don't affect the reads at stage 1...
3287 #ifdef DSP_DEBUG_STALL
3289 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3293 #ifdef DSP_DEBUG_PL2
3296 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3297 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]);
3298 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]);
3299 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]);
3303 // Stage 3: Write back register/memory address
3304 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3306 /*if (pipeline[plPtrWrite].writebackRegister == 3
3307 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3310 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3313 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3315 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3316 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3319 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3320 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3321 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3322 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3324 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3328 #ifndef NEW_SCOREBOARD
3329 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3330 scoreboard[pipeline[plPtrWrite].operand2] = false;
3332 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3333 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3334 if (scoreboard[pipeline[plPtrWrite].operand2])
3335 scoreboard[pipeline[plPtrWrite].operand2]--;
3339 // Push instructions through the pipeline...
3340 plPtrRead = (++plPtrRead) & 0x03;
3341 plPtrExec = (++plPtrExec) & 0x03;
3342 plPtrWrite = (++plPtrWrite) & 0x03;
3351 //#define DSP_DEBUG_PL3
3352 //Let's try a 2 stage pipeline....
3353 void DSPExecP3(int32_t cycles)
3355 dsp_releaseTimeSlice_flag = 0;
3358 while (cycles > 0 && DSP_RUNNING)
3360 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3362 #ifdef DSP_DEBUG_PL3
3363 WriteLog("DSPExecP: Pipeline status...\n");
3364 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]);
3365 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]);
3366 WriteLog(" --> Scoreboard: ");
3367 for(int i=0; i<32; i++)
3368 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3371 // Stage 1a: Instruction fetch
3372 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3373 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3374 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3375 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3376 if (pipeline[plPtrRead].opcode == 38)
3377 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3378 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3379 #ifdef DSP_DEBUG_PL3
3380 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3381 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3382 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]);
3383 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]);
3385 // Stage 1b: Read registers
3386 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3387 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3388 // We have a hit in the scoreboard, so we have to stall the pipeline...
3389 #ifdef DSP_DEBUG_PL3
3391 WriteLog(" --> Stalling pipeline: ");
3392 if (readAffected[pipeline[plPtrRead].opcode][0])
3393 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3394 if (readAffected[pipeline[plPtrRead].opcode][1])
3395 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3398 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3399 #ifdef DSP_DEBUG_PL3
3404 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3405 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3406 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3408 // Shouldn't we be more selective with the register scoreboarding?
3409 // Yes, we should. !!! FIX !!! [Kinda DONE]
3410 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3412 //Advance PC here??? Yes.
3413 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3416 #ifdef DSP_DEBUG_PL3
3417 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3418 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]);
3419 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]);
3421 // Stage 2a: Execute
3422 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3424 #ifdef DSP_DEBUG_PL3
3425 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3427 DSPOpcode[pipeline[plPtrExec].opcode]();
3428 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3429 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3434 #ifdef DSP_DEBUG_PL3
3435 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3436 WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
3437 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3440 // Stage 2b: Write back register
3441 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3443 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3444 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3446 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3447 scoreboard[pipeline[plPtrExec].operand2] = false;
3450 // Push instructions through the pipeline...
3451 plPtrRead = (++plPtrRead) & 0x03;
3452 plPtrExec = (++plPtrExec) & 0x03;
3459 // DSP pipelined opcode handlers
3462 #define PRM pipeline[plPtrExec].reg1
3463 #define PRN pipeline[plPtrExec].reg2
3464 #define PIMM1 pipeline[plPtrExec].operand1
3465 #define PIMM2 pipeline[plPtrExec].operand2
3466 #define PRES pipeline[plPtrExec].result
3467 #define PWBR pipeline[plPtrExec].writebackRegister
3468 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3469 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3470 #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))
3471 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3473 static void DSP_abs(void)
3477 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);
3481 if (_Rn == 0x80000000)
3485 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3486 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3487 CLR_ZN; SET_Z(PRES);
3491 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3495 static void DSP_add(void)
3499 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);
3501 uint32_t res = PRN + PRM;
3502 SET_ZNC_ADD(PRN, PRM, res);
3506 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);
3510 static void DSP_addc(void)
3514 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);
3516 uint32_t res = PRN + PRM + dsp_flag_c;
3517 uint32_t carry = dsp_flag_c;
3518 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3519 SET_ZNC_ADD(PRN + carry, PRM, res);
3520 // SET_ZNC_ADD(PRN, PRM + carry, res);
3524 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);
3528 static void DSP_addq(void)
3532 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);
3534 uint32_t r1 = dsp_convert_zero[PIMM1];
3535 uint32_t res = PRN + r1;
3536 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3540 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3544 static void DSP_addqmod(void)
3546 #ifdef DSP_DIS_ADDQMOD
3548 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);
3550 uint32_t r1 = dsp_convert_zero[PIMM1];
3552 uint32_t res = r2 + r1;
3553 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3555 SET_ZNC_ADD(r2, r1, res);
3556 #ifdef DSP_DIS_ADDQMOD
3558 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3562 static void DSP_addqt(void)
3564 #ifdef DSP_DIS_ADDQT
3566 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);
3568 PRES = PRN + dsp_convert_zero[PIMM1];
3569 #ifdef DSP_DIS_ADDQT
3571 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3575 static void DSP_and(void)
3579 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);
3585 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);
3589 static void DSP_bclr(void)
3593 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);
3595 PRES = PRN & ~(1 << PIMM1);
3599 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3603 static void DSP_bset(void)
3607 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);
3609 PRES = PRN | (1 << PIMM1);
3613 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3617 static void DSP_btst(void)
3621 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);
3623 dsp_flag_z = (~PRN >> PIMM1) & 1;
3627 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3631 static void DSP_cmp(void)
3635 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);
3637 uint32_t res = PRN - PRM;
3638 SET_ZNC_SUB(PRN, PRM, res);
3642 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3646 static void DSP_cmpq(void)
3648 static int32_t sqtable[32] =
3649 { 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 };
3652 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);
3654 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3655 uint32_t res = PRN - r1;
3656 SET_ZNC_SUB(PRN, r1, res);
3660 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3664 static void DSP_div(void)
3666 uint32_t _Rm = PRM, _Rn = PRN;
3670 if (dsp_div_control & 1)
3672 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3673 if (dsp_remain & 0x80000000)
3675 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3679 dsp_remain = _Rn % _Rm;
3680 if (dsp_remain & 0x80000000)
3689 static void DSP_imacn(void)
3691 #ifdef DSP_DIS_IMACN
3693 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);
3695 int32_t res = (int16_t)PRM * (int16_t)PRN;
3696 dsp_acc += (int64_t)res;
3697 //Should we AND the result to fit into 40 bits here???
3699 #ifdef DSP_DIS_IMACN
3701 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));
3705 static void DSP_imult(void)
3707 #ifdef DSP_DIS_IMULT
3709 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);
3711 PRES = (int16_t)PRN * (int16_t)PRM;
3713 #ifdef DSP_DIS_IMULT
3715 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);
3719 static void DSP_imultn(void)
3721 #ifdef DSP_DIS_IMULTN
3723 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);
3725 // This is OK, since this multiply won't overflow 32 bits...
3726 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3727 dsp_acc = (int64_t)res;
3730 #ifdef DSP_DIS_IMULTN
3732 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));
3736 static void DSP_illegal(void)
3738 #ifdef DSP_DIS_ILLEGAL
3740 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3745 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3746 // can cause trouble because an interrupt can occur *before* the instruction following the
3747 // jump can execute... !!! FIX !!!
3748 // This can probably be solved by judicious coding in the pipeline execution core...
3749 // And should be fixed now...
3750 static void DSP_jr(void)
3753 const char * condition[32] =
3754 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3755 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3756 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3757 "???", "???", "???", "F" };
3759 //How come this is always off by 2???
3760 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);
3762 // KLUDGE: Used by BRANCH_CONDITION macro
3763 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3765 if (BRANCH_CONDITION(PIMM2))
3769 WriteLog("Branched!\n");
3771 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3772 //Account for pipeline effects...
3773 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3774 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3776 // Now that we've branched, we have to make sure that the following instruction
3777 // is executed atomically with this one and then flush the pipeline before setting
3780 // Step 1: Handle writebacks at stage 3 of pipeline
3781 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3783 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3784 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3786 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3787 scoreboard[pipeline[plPtrWrite].operand2] = false;
3789 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3791 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3793 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3794 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3797 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3798 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3799 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3800 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3802 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3806 #ifndef NEW_SCOREBOARD
3807 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3808 scoreboard[pipeline[plPtrWrite].operand2] = false;
3810 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3811 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3812 if (scoreboard[pipeline[plPtrWrite].operand2])
3813 scoreboard[pipeline[plPtrWrite].operand2]--;
3817 // Step 2: Push instruction through pipeline & execute following instruction
3818 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3819 // we effectively handle the final push of the instruction through the
3820 // pipeline when the new PC takes effect (since when we return, the
3821 // pipeline code will be executing the writeback stage. If we reverse
3822 // the execution order of the pipeline stages, this will no longer be
3824 pipeline[plPtrExec] = pipeline[plPtrRead];
3825 //This is BAD. We need to get that next opcode and execute it!
3826 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3827 // remove this crap.
3828 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3830 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3831 pipeline[plPtrExec].opcode = instruction >> 10;
3832 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3833 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3834 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3835 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3836 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3838 dsp_pc += 2; // For DSP_DIS_* accuracy
3839 DSPOpcode[pipeline[plPtrExec].opcode]();
3840 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3841 pipeline[plPtrWrite] = pipeline[plPtrExec];
3843 // Step 3: Flush pipeline & set new PC
3844 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3851 WriteLog("Branch NOT taken.\n");
3857 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3860 static void DSP_jump(void)
3863 const char * condition[32] =
3864 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3865 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3866 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3867 "???", "???", "???", "F" };
3869 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);
3871 // KLUDGE: Used by BRANCH_CONDITION macro
3872 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3874 if (BRANCH_CONDITION(PIMM2))
3878 WriteLog("Branched!\n");
3880 uint32_t PCSave = PRM;
3881 // Now that we've branched, we have to make sure that the following instruction
3882 // is executed atomically with this one and then flush the pipeline before setting
3885 // Step 1: Handle writebacks at stage 3 of pipeline
3886 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3888 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3889 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3891 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3892 scoreboard[pipeline[plPtrWrite].operand2] = false;
3894 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3896 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3898 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3899 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3902 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3903 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3904 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3905 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3907 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3911 #ifndef NEW_SCOREBOARD
3912 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3913 scoreboard[pipeline[plPtrWrite].operand2] = false;
3915 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3916 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3917 if (scoreboard[pipeline[plPtrWrite].operand2])
3918 scoreboard[pipeline[plPtrWrite].operand2]--;
3922 // Step 2: Push instruction through pipeline & execute following instruction
3923 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3924 // we effectively handle the final push of the instruction through the
3925 // pipeline when the new PC takes effect (since when we return, the
3926 // pipeline code will be executing the writeback stage. If we reverse
3927 // the execution order of the pipeline stages, this will no longer be
3929 pipeline[plPtrExec] = pipeline[plPtrRead];
3930 //This is BAD. We need to get that next opcode and execute it!
3931 //Also, same problem in JR!
3932 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3933 // remove this crap.
3934 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3936 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3937 pipeline[plPtrExec].opcode = instruction >> 10;
3938 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3939 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3940 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3941 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3942 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3944 dsp_pc += 2; // For DSP_DIS_* accuracy
3945 DSPOpcode[pipeline[plPtrExec].opcode]();
3946 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3947 pipeline[plPtrWrite] = pipeline[plPtrExec];
3949 // Step 3: Flush pipeline & set new PC
3950 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3957 WriteLog("Branch NOT taken.\n");
3965 static void DSP_load(void)
3969 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);
3971 #ifdef DSP_CORRECT_ALIGNMENT
3972 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
3974 PRES = DSPReadLong(PRM, DSP);
3978 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3982 static void DSP_loadb(void)
3984 #ifdef DSP_DIS_LOADB
3986 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);
3988 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
3989 PRES = DSPReadLong(PRM, DSP) & 0xFF;
3991 PRES = JaguarReadByte(PRM, DSP);
3992 #ifdef DSP_DIS_LOADB
3994 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3998 static void DSP_loadw(void)
4000 #ifdef DSP_DIS_LOADW
4002 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);
4004 #ifdef DSP_CORRECT_ALIGNMENT
4005 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4006 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4008 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4010 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4011 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4013 PRES = JaguarReadWord(PRM, DSP);
4015 #ifdef DSP_DIS_LOADW
4017 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4021 static void DSP_load_r14_i(void)
4023 #ifdef DSP_DIS_LOAD14I
4025 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);
4027 #ifdef DSP_CORRECT_ALIGNMENT
4028 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4030 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4032 #ifdef DSP_DIS_LOAD14I
4034 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4038 static void DSP_load_r14_r(void)
4040 #ifdef DSP_DIS_LOAD14R
4042 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);
4044 #ifdef DSP_CORRECT_ALIGNMENT
4045 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4047 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4049 #ifdef DSP_DIS_LOAD14R
4051 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4055 static void DSP_load_r15_i(void)
4057 #ifdef DSP_DIS_LOAD15I
4059 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);
4061 #ifdef DSP_CORRECT_ALIGNMENT
4062 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4064 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4066 #ifdef DSP_DIS_LOAD15I
4068 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4072 static void DSP_load_r15_r(void)
4074 #ifdef DSP_DIS_LOAD15R
4076 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);
4078 #ifdef DSP_CORRECT_ALIGNMENT
4079 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4081 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4083 #ifdef DSP_DIS_LOAD15R
4085 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4089 static void DSP_mirror(void)
4092 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4096 static void DSP_mmult(void)
4098 int count = dsp_matrix_control&0x0f;
4099 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4103 if (!(dsp_matrix_control & 0x10))
4105 for (int i = 0; i < count; i++)
4109 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4111 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4112 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4119 for (int i = 0; i < count; i++)
4123 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4125 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4126 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4132 PRES = res = (int32_t)accum;
4134 //NOTE: The flags are set based upon the last add/multiply done...
4138 static void DSP_move(void)
4142 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);
4147 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);
4151 static void DSP_movefa(void)
4153 #ifdef DSP_DIS_MOVEFA
4155 // 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);
4156 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);
4158 // PRES = ALTERNATE_RM;
4159 PRES = dsp_alternate_reg[PIMM1];
4160 #ifdef DSP_DIS_MOVEFA
4162 // 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);
4163 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);
4167 static void DSP_movei(void)
4169 #ifdef DSP_DIS_MOVEI
4171 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);
4173 // // This instruction is followed by 32-bit value in LSW / MSW format...
4174 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4176 #ifdef DSP_DIS_MOVEI
4178 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4182 static void DSP_movepc(void)
4184 #ifdef DSP_DIS_MOVEPC
4186 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);
4188 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4189 // PRES = dsp_pc - 2;
4190 //Account for pipeline effects...
4191 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4192 #ifdef DSP_DIS_MOVEPC
4194 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4198 static void DSP_moveq(void)
4200 #ifdef DSP_DIS_MOVEQ
4202 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);
4205 #ifdef DSP_DIS_MOVEQ
4207 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4211 static void DSP_moveta(void)
4213 #ifdef DSP_DIS_MOVETA
4215 // 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);
4216 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]);
4218 // ALTERNATE_RN = PRM;
4219 dsp_alternate_reg[PIMM2] = PRM;
4221 #ifdef DSP_DIS_MOVETA
4223 // 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);
4224 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]);
4228 static void DSP_mtoi(void)
4230 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4234 static void DSP_mult(void)
4238 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);
4240 PRES = (uint16_t)PRM * (uint16_t)PRN;
4244 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);
4248 static void DSP_neg(void)
4252 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);
4254 uint32_t res = -PRN;
4255 SET_ZNC_SUB(0, PRN, res);
4259 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4263 static void DSP_nop(void)
4267 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4272 static void DSP_normi(void)
4279 while ((_Rm & 0xffc00000) == 0)
4284 while ((_Rm & 0xff800000) != 0)
4294 static void DSP_not(void)
4298 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);
4304 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4308 static void DSP_or(void)
4312 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);
4318 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);
4322 static void DSP_resmac(void)
4324 #ifdef DSP_DIS_RESMAC
4326 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));
4328 PRES = (uint32_t)dsp_acc;
4329 #ifdef DSP_DIS_RESMAC
4331 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4335 static void DSP_ror(void)
4339 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);
4341 uint32_t r1 = PRM & 0x1F;
4342 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4343 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4347 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);
4351 static void DSP_rorq(void)
4355 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);
4357 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4359 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4361 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
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_sat16s(void)
4371 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4376 static void DSP_sat32s(void)
4378 int32_t r2 = (uint32_t)PRN;
4379 int32_t temp = dsp_acc >> 32;
4380 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4385 static void DSP_sh(void)
4387 int32_t sRm = (int32_t)PRM;
4392 uint32_t shift = -sRm;
4397 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4407 uint32_t shift = sRm;
4412 dsp_flag_c = _Rn & 0x1;
4425 static void DSP_sha(void)
4427 int32_t sRm = (int32_t)PRM;
4432 uint32_t shift = -sRm;
4437 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4447 uint32_t shift = sRm;
4452 dsp_flag_c = _Rn & 0x1;
4456 _Rn = ((int32_t)_Rn) >> 1;
4465 static void DSP_sharq(void)
4467 #ifdef DSP_DIS_SHARQ
4469 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);
4471 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4472 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4474 #ifdef DSP_DIS_SHARQ
4476 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4480 static void DSP_shlq(void)
4484 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);
4486 int32_t r1 = 32 - PIMM1;
4487 uint32_t res = PRN << r1;
4488 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4492 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4496 static void DSP_shrq(void)
4500 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);
4502 int32_t r1 = dsp_convert_zero[PIMM1];
4503 uint32_t res = PRN >> r1;
4504 SET_ZN(res); dsp_flag_c = PRN & 1;
4508 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4512 static void DSP_store(void)
4514 #ifdef DSP_DIS_STORE
4516 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);
4518 // DSPWriteLong(PRM, PRN, DSP);
4520 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4521 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4523 pipeline[plPtrExec].address = PRM;
4525 pipeline[plPtrExec].value = PRN;
4526 pipeline[plPtrExec].type = TYPE_DWORD;
4530 static void DSP_storeb(void)
4532 #ifdef DSP_DIS_STOREB
4534 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);
4536 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4537 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4539 // JaguarWriteByte(PRM, PRN, DSP);
4542 pipeline[plPtrExec].address = PRM;
4544 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4546 pipeline[plPtrExec].value = PRN & 0xFF;
4547 pipeline[plPtrExec].type = TYPE_DWORD;
4551 pipeline[plPtrExec].value = PRN;
4552 pipeline[plPtrExec].type = TYPE_BYTE;
4558 static void DSP_storew(void)
4560 #ifdef DSP_DIS_STOREW
4562 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);
4564 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4565 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4567 // JaguarWriteWord(PRM, PRN, DSP);
4570 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4571 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4573 pipeline[plPtrExec].address = PRM;
4576 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4578 pipeline[plPtrExec].value = PRN & 0xFFFF;
4579 pipeline[plPtrExec].type = TYPE_DWORD;
4583 pipeline[plPtrExec].value = PRN;
4584 pipeline[plPtrExec].type = TYPE_WORD;
4589 static void DSP_store_r14_i(void)
4591 #ifdef DSP_DIS_STORE14I
4593 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));
4595 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4597 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4598 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4600 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4602 pipeline[plPtrExec].value = PRN;
4603 pipeline[plPtrExec].type = TYPE_DWORD;
4607 static void DSP_store_r14_r(void)
4609 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4611 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4612 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4614 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4616 pipeline[plPtrExec].value = PRN;
4617 pipeline[plPtrExec].type = TYPE_DWORD;
4621 static void DSP_store_r15_i(void)
4623 #ifdef DSP_DIS_STORE15I
4625 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));
4627 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4629 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4630 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4632 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4634 pipeline[plPtrExec].value = PRN;
4635 pipeline[plPtrExec].type = TYPE_DWORD;
4639 static void DSP_store_r15_r(void)
4641 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4643 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4644 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4646 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4648 pipeline[plPtrExec].value = PRN;
4649 pipeline[plPtrExec].type = TYPE_DWORD;
4653 static void DSP_sub(void)
4657 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);
4659 uint32_t res = PRN - PRM;
4660 SET_ZNC_SUB(PRN, PRM, res);
4664 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);
4668 static void DSP_subc(void)
4672 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);
4674 uint32_t res = PRN - PRM - dsp_flag_c;
4675 uint32_t borrow = dsp_flag_c;
4676 SET_ZNC_SUB(PRN - borrow, PRM, res);
4680 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);
4684 static void DSP_subq(void)
4688 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);
4690 uint32_t r1 = dsp_convert_zero[PIMM1];
4691 uint32_t res = PRN - r1;
4692 SET_ZNC_SUB(PRN, r1, res);
4696 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4700 static void DSP_subqmod(void)
4702 uint32_t r1 = dsp_convert_zero[PIMM1];
4704 uint32_t res = r2 - r1;
4705 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4707 SET_ZNC_SUB(r2, r1, res);
4710 static void DSP_subqt(void)
4712 #ifdef DSP_DIS_SUBQT
4714 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);
4716 PRES = PRN - dsp_convert_zero[PIMM1];
4717 #ifdef DSP_DIS_SUBQT
4719 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4723 static void DSP_xor(void)
4727 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);
4733 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);