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;
461 void DSPReleaseTimeslice(void)
463 //This does absolutely nothing!!! !!! FIX !!!
464 dsp_releaseTimeSlice_flag = 1;
468 void dsp_build_branch_condition_table(void)
470 // Fill in the mirror table
471 for(int i=0; i<65536; i++)
473 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
474 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
475 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
476 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
477 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
478 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
479 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
480 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
483 // Fill in the condition table
484 for(int i=0; i<8; i++)
486 for(int j=0; j<32; j++)
490 if ((j & 1) && (i & ZERO_FLAG))
493 if ((j & 2) && (!(i & ZERO_FLAG)))
496 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
499 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
502 dsp_branch_condition_table[i * 32 + j] = result;
508 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
510 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
511 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
513 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
516 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
518 if (offset==0xF1CFE0)
521 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
522 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
524 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
526 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
528 if ((offset & 0x03) == 0)
530 else if ((offset & 0x03) == 1)
531 return ((data >> 16) & 0xFF);
532 else if ((offset & 0x03) == 2)
533 return ((data >> 8) & 0xFF);
534 else if ((offset & 0x03) == 3)
535 return (data & 0xFF);
538 return JaguarReadByte(offset, who);
542 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
544 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
545 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
547 offset &= 0xFFFFFFFE;
549 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
551 offset -= DSP_WORK_RAM_BASE;
552 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
554 return GET16(dsp_ram_8, offset);
556 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
558 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
561 return data & 0xFFFF;
566 return JaguarReadWord(offset, who);
570 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
572 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
573 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
576 offset &= 0xFFFFFFFC;
577 /*if (offset == 0xF1BCF4)
579 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));
580 DSPDumpDisassembly();
582 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
584 offset -= DSP_WORK_RAM_BASE;
585 return GET32(dsp_ram_8, offset);
587 //NOTE: Didn't return DSP_ACCUM!!!
588 //Mebbe it's not 'spose to! Yes, it is!
589 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
595 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
596 return dsp_flags & 0xFFFFC1FF;
597 case 0x04: return dsp_matrix_control;
598 case 0x08: return dsp_pointer_to_matrix;
599 case 0x0C: return dsp_data_organization;
600 case 0x10: return dsp_pc;
601 case 0x14: return dsp_control;
602 case 0x18: return dsp_modulo;
603 case 0x1C: return dsp_remain;
605 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
607 // unaligned long read-- !!! FIX !!!
611 return JaguarReadLong(offset, who);
615 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
617 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
618 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
620 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
622 offset -= DSP_WORK_RAM_BASE;
623 dsp_ram_8[offset] = data;
624 //This is rather stupid! !!! FIX !!!
625 /* if (dsp_in_exec == 0)
627 m68k_end_timeslice();
628 dsp_releaseTimeslice();
632 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
634 uint32_t reg = offset & 0x1C;
635 int bytenum = offset & 0x03;
637 if ((reg >= 0x1C) && (reg <= 0x1F))
638 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
641 //This looks funky. !!! FIX !!!
642 uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
643 bytenum = 3 - bytenum; // convention motorola !!!
644 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
645 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
649 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
650 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
651 // Well, yes, it can. There are 3 MMU users after all: 68K, GPU & DSP...!
652 JaguarWriteByte(offset, data, who);
656 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
658 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
659 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
660 offset &= 0xFFFFFFFE;
661 /*if (offset == 0xF1BCF4)
663 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
665 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
666 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
668 /*if (offset == 0xF1B2F4)
670 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
672 offset -= DSP_WORK_RAM_BASE;
673 dsp_ram_8[offset] = data >> 8;
674 dsp_ram_8[offset+1] = data & 0xFF;
675 //This is rather stupid! !!! FIX !!!
676 /* if (dsp_in_exec == 0)
678 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
679 m68k_end_timeslice();
680 dsp_releaseTimeslice();
684 SET16(ram1, offset, data),
685 SET16(ram2, offset, data);
690 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
692 if ((offset & 0x1C) == 0x1C)
695 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
697 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
701 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
704 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
706 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
708 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
714 JaguarWriteWord(offset, data, who);
718 //bool badWrite = false;
719 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
721 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
722 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
724 offset &= 0xFFFFFFFC;
725 /*if (offset == 0xF1BCF4)
727 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
729 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
730 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
732 /*if (offset == 0xF1BE2C)
734 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
736 offset -= DSP_WORK_RAM_BASE;
737 SET32(dsp_ram_8, offset, data);
740 SET32(ram1, offset, data),
741 SET32(ram2, offset, data);
746 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
754 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
756 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
757 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
758 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
759 // IRQ logic can set it. So we mask it out here to prevent problems...
760 dsp_flags = data & (~IMASK);
761 dsp_flag_z = dsp_flags & 0x01;
762 dsp_flag_c = (dsp_flags >> 1) & 0x01;
763 dsp_flag_n = (dsp_flags >> 2) & 0x01;
764 DSPUpdateRegisterBanks();
765 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
766 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
770 dsp_matrix_control = data;
773 // According to JTRM, only lines 2-11 are addressable, the rest being
774 // hardwired to $F1Bxxx.
775 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
778 dsp_data_organization = data;
783 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
788 ctrl1[0] = ctrl2[0] = data;
795 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
797 bool wasRunning = DSP_RUNNING;
798 // uint32_t dsp_was_running = DSP_RUNNING;
799 // Check for DSP -> CPU interrupt
803 WriteLog("DSP: DSP -> CPU interrupt\n");
806 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
807 if (JERRYIRQEnabled(IRQ2_DSP))
809 JERRYSetPendingIRQ(IRQ2_DSP);
810 DSPReleaseTimeslice();
811 m68k_set_irq(2); // Set 68000 IPL 2...
815 // Check for CPU -> DSP interrupt
819 WriteLog("DSP: CPU -> DSP interrupt\n");
821 m68k_end_timeslice();
822 DSPReleaseTimeslice();
823 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
827 if (data & SINGLE_STEP)
829 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
832 // Protect writes to VERSION and the interrupt latches...
833 uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
834 dsp_control = (dsp_control & mask) | (data & ~mask);
838 ctrl1[8] = ctrl2[8] = dsp_control;
842 // if dsp wasn't running but is now running
843 // execute a few cycles
844 //This is just plain wrong, wrong, WRONG!
845 #ifndef DSP_SINGLE_STEPPING
846 /* if (!dsp_was_running && DSP_RUNNING)
851 //This is WRONG! !!! FIX !!!
852 if (dsp_control & 0x18)
857 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
859 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
862 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
863 // !!! FIX !!! [DONE]
867 m68k_end_timeslice();
869 DSPReleaseTimeslice();
873 //DSPDumpDisassembly();
878 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
882 dsp_div_control = data;
884 // default: // unaligned long read
890 //We don't have to break this up like this! We CAN do 32 bit writes!
891 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
892 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
893 //if (offset > 0xF1FFFF)
895 JaguarWriteLong(offset, data, who);
900 // Update the DSP register file pointers depending on REGPAGE bit
902 void DSPUpdateRegisterBanks(void)
904 int bank = (dsp_flags & REGPAGE);
906 if (dsp_flags & IMASK)
907 bank = 0; // IMASK forces main bank to be bank 0
910 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
912 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
915 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
921 // Check for and handle any asserted DSP IRQs
923 void DSPHandleIRQs(void)
925 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
928 // Get the active interrupt bits (latches) & interrupt mask (enables)
929 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
930 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
932 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
935 if (!bits) // Bail if nothing is enabled
938 int which = 0; // Determine which interrupt
954 WriteLog("DSP: Generating interrupt #%i...", which);
957 //if (which == 0) doDSPDis = true;
959 // NOTE: Since the actual Jaguar hardware injects the code sequence below
960 // directly into the pipeline, it has the side effect of ensuring that the
961 // instruction interrupted also gets to do its writeback. We simulate that
963 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
965 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
966 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
968 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
969 scoreboard[pipeline[plPtrWrite].operand2] = false;
971 //This should be execute (or should it?--not sure now!)
972 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
973 //and what just executed is now in the Write position...). So why didn't it do the
974 //writeback into register 0?
976 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
977 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]);
978 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]);
979 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]);
981 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
983 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
985 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
986 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
989 if (pipeline[plPtrWrite].type == TYPE_BYTE)
990 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
991 else if (pipeline[plPtrWrite].type == TYPE_WORD)
992 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
994 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
998 #ifndef NEW_SCOREBOARD
999 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1000 scoreboard[pipeline[plPtrWrite].operand2] = false;
1002 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1003 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1004 if (scoreboard[pipeline[plPtrWrite].operand2])
1005 scoreboard[pipeline[plPtrWrite].operand2]--;
1012 ctrl2[4] = dsp_flags;
1015 DSPUpdateRegisterBanks();
1016 #ifdef DSP_DEBUG_IRQ
1017 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1018 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]);
1021 // subqt #4,r31 ; pre-decrement stack pointer
1022 // move pc,r30 ; address of interrupted code
1023 // store r30,(r31) ; store return address
1030 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1031 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1032 //It missed the place that it was supposed to come back to, so this is WRONG!
1034 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1036 // R -> baz (<- PC points here)
1037 // E -> bar (when it should point here!)
1040 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1041 // which means (assuming they're all 2 bytes long) that the code below will come back on
1042 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1043 // instruction stream...
1045 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1046 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1049 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1053 // movei #service_address,r30 ; pointer to ISR entry
1054 // jump (r30) ; jump to ISR
1056 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1059 ctrl2[0] = regs2[30] = dsp_pc;
1067 // Non-pipelined version...
1069 void DSPHandleIRQsNP(void)
1073 memcpy(dsp_ram_8, ram1, 0x2000);
1074 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1075 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1078 dsp_remain = ctrl1[2];
1079 dsp_modulo = ctrl1[3];
1080 dsp_flags = ctrl1[4];
1081 dsp_matrix_control = ctrl1[5];
1082 dsp_pointer_to_matrix = ctrl1[6];
1083 dsp_data_organization = ctrl1[7];
1084 dsp_control = ctrl1[8];
1085 dsp_div_control = ctrl1[9];
1086 IMASKCleared = ctrl1[10];
1087 dsp_flag_z = ctrl1[11];
1088 dsp_flag_n = ctrl1[12];
1089 dsp_flag_c = ctrl1[13];
1090 DSPUpdateRegisterBanks();
1093 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1096 // Get the active interrupt bits (latches) & interrupt mask (enables)
1097 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1098 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1100 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1103 if (!bits) // Bail if nothing is enabled
1106 int which = 0; // Determine which interrupt
1120 dsp_flags |= IMASK; // Force Bank #0
1123 ctrl1[4] = dsp_flags;
1126 #ifdef DSP_DEBUG_IRQ
1127 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1128 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1130 DSPUpdateRegisterBanks();
1131 #ifdef DSP_DEBUG_IRQ
1132 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1133 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1136 #ifdef DSP_DEBUG_IRQ
1137 WriteLog("DSP: Generating interrupt #%i...", which);
1138 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1141 // subqt #4,r31 ; pre-decrement stack pointer
1142 // move pc,r30 ; address of interrupted code
1143 // store r30,(r31) ; store return address
1145 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1152 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1153 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1156 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1160 // movei #service_address,r30 ; pointer to ISR entry
1161 // jump (r30) ; jump to ISR
1163 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1166 ctrl1[0] = regs1[30] = dsp_pc;
1173 // Set the specified DSP IRQ line to a given state
1175 void DSPSetIRQLine(int irqline, int state)
1177 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1178 uint32_t mask = INT_LAT0 << irqline;
1179 dsp_control &= ~mask; // Clear the latch bit
1182 ctrl1[8] = ctrl2[8] = dsp_control;
1188 dsp_control |= mask; // Set the latch bit
1189 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1194 ctrl1[8] = ctrl2[8] = dsp_control;
1200 // Not sure if this is correct behavior, but according to JTRM,
1201 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1202 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1203 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1207 bool DSPIsRunning(void)
1209 return (DSP_RUNNING ? true : false);
1215 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1216 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1217 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1219 dsp_build_branch_condition_table();
1226 dsp_pc = 0x00F1B000;
1227 dsp_acc = 0x00000000;
1228 dsp_remain = 0x00000000;
1229 dsp_modulo = 0xFFFFFFFF;
1230 dsp_flags = 0x00040000;
1231 dsp_matrix_control = 0x00000000;
1232 dsp_pointer_to_matrix = 0x00000000;
1233 dsp_data_organization = 0xFFFFFFFF;
1234 dsp_control = 0x00002000; // Report DSP version 2
1235 dsp_div_control = 0x00000000;
1238 dsp_reg = dsp_reg_bank_0;
1239 dsp_alternate_reg = dsp_reg_bank_1;
1241 for(int i=0; i<32; i++)
1242 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1245 IMASKCleared = false;
1249 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1250 for(uint32_t i=0; i<8192; i+=4)
1251 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1255 void DSPDumpDisassembly(void)
1259 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1260 uint32_t j = 0xF1B000;
1262 while (j <= 0xF1CFFF)
1265 j += dasmjag(JAGUAR_DSP, buffer, j);
1266 WriteLog("\t%08X: %s\n", oldj, buffer);
1271 void DSPDumpRegisters(void)
1273 //Shoud add modulus, etc to dump here...
1274 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1275 WriteLog("\nRegisters bank 0\n");
1277 for(int j=0; j<8; j++)
1279 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1280 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1281 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1282 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1283 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1286 WriteLog("Registers bank 1\n");
1288 for(int j=0; j<8; j++)
1290 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1291 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1292 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1293 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1294 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1302 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1303 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1305 // get the active interrupt bits
1306 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1307 // get the interrupt mask
1308 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1310 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1311 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1312 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1313 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1314 WriteLog("\nRegisters bank 0\n");
1316 for(int j=0; j<8; j++)
1318 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1319 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1320 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1321 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1322 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1325 WriteLog("\nRegisters bank 1\n");
1329 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1330 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1331 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1332 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1333 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1338 static char buffer[512];
1339 j = DSP_WORK_RAM_BASE;
1341 while (j <= 0xF1CFFF)
1344 j += dasmjag(JAGUAR_DSP, buffer, j);
1345 WriteLog("\t%08X: %s\n", oldj, buffer);
1348 WriteLog("DSP opcodes use:\n");
1352 if (dsp_opcode_use[i])
1353 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1360 // DSP comparison core...
1363 static uint16_t lastExec;
1364 void DSPExecComp(int32_t cycles)
1366 while (cycles > 0 && DSP_RUNNING)
1368 // Load up vars for non-pipelined core
1369 memcpy(dsp_ram_8, ram1, 0x2000);
1370 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1371 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1374 dsp_remain = ctrl1[2];
1375 dsp_modulo = ctrl1[3];
1376 dsp_flags = ctrl1[4];
1377 dsp_matrix_control = ctrl1[5];
1378 dsp_pointer_to_matrix = ctrl1[6];
1379 dsp_data_organization = ctrl1[7];
1380 dsp_control = ctrl1[8];
1381 dsp_div_control = ctrl1[9];
1382 IMASKCleared = ctrl1[10];
1383 dsp_flag_z = ctrl1[11];
1384 dsp_flag_n = ctrl1[12];
1385 dsp_flag_c = ctrl1[13];
1386 DSPUpdateRegisterBanks();
1388 // Decrement cycles based on non-pipelined core...
1389 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1390 cycles -= dsp_opcode_cycles[instr1 >> 10];
1392 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1393 DSPExec(1); // Do *one* instruction
1396 memcpy(ram1, dsp_ram_8, 0x2000);
1397 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1398 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1401 ctrl1[2] = dsp_remain;
1402 ctrl1[3] = dsp_modulo;
1403 ctrl1[4] = dsp_flags;
1404 ctrl1[5] = dsp_matrix_control;
1405 ctrl1[6] = dsp_pointer_to_matrix;
1406 ctrl1[7] = dsp_data_organization;
1407 ctrl1[8] = dsp_control;
1408 ctrl1[9] = dsp_div_control;
1409 ctrl1[10] = IMASKCleared;
1410 ctrl1[11] = dsp_flag_z;
1411 ctrl1[12] = dsp_flag_n;
1412 ctrl1[13] = dsp_flag_c;
1414 // Load up vars for pipelined core
1415 memcpy(dsp_ram_8, ram2, 0x2000);
1416 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1417 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1420 dsp_remain = ctrl2[2];
1421 dsp_modulo = ctrl2[3];
1422 dsp_flags = ctrl2[4];
1423 dsp_matrix_control = ctrl2[5];
1424 dsp_pointer_to_matrix = ctrl2[6];
1425 dsp_data_organization = ctrl2[7];
1426 dsp_control = ctrl2[8];
1427 dsp_div_control = ctrl2[9];
1428 IMASKCleared = ctrl2[10];
1429 dsp_flag_z = ctrl2[11];
1430 dsp_flag_n = ctrl2[12];
1431 dsp_flag_c = ctrl2[13];
1432 DSPUpdateRegisterBanks();
1434 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1435 DSPExecP2(1); // Do *one* instruction
1438 memcpy(ram2, dsp_ram_8, 0x2000);
1439 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1440 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1443 ctrl2[2] = dsp_remain;
1444 ctrl2[3] = dsp_modulo;
1445 ctrl2[4] = dsp_flags;
1446 ctrl2[5] = dsp_matrix_control;
1447 ctrl2[6] = dsp_pointer_to_matrix;
1448 ctrl2[7] = dsp_data_organization;
1449 ctrl2[8] = dsp_control;
1450 ctrl2[9] = dsp_div_control;
1451 ctrl2[10] = IMASKCleared;
1452 ctrl2[11] = dsp_flag_z;
1453 ctrl2[12] = dsp_flag_n;
1454 ctrl2[13] = dsp_flag_c;
1456 if (instr1 != lastExec)
1458 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1460 // 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));
1461 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1462 // if (ctrl1[0] < ppc) // P ran ahead of NP
1463 //How to test this crap???
1466 DSPExecP2(1); // Do one more instruction
1469 memcpy(ram2, dsp_ram_8, 0x2000);
1470 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1471 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1474 ctrl2[2] = dsp_remain;
1475 ctrl2[3] = dsp_modulo;
1476 ctrl2[4] = dsp_flags;
1477 ctrl2[5] = dsp_matrix_control;
1478 ctrl2[6] = dsp_pointer_to_matrix;
1479 ctrl2[7] = dsp_data_organization;
1480 ctrl2[8] = dsp_control;
1481 ctrl2[9] = dsp_div_control;
1482 ctrl2[10] = IMASKCleared;
1483 ctrl2[11] = dsp_flag_z;
1484 ctrl2[12] = dsp_flag_n;
1485 ctrl2[13] = dsp_flag_c;
1487 // else // NP ran ahead of P
1488 if (instr1 != lastExec) // Must be the other way...
1491 // Load up vars for non-pipelined core
1492 memcpy(dsp_ram_8, ram1, 0x2000);
1493 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1494 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1497 dsp_remain = ctrl1[2];
1498 dsp_modulo = ctrl1[3];
1499 dsp_flags = ctrl1[4];
1500 dsp_matrix_control = ctrl1[5];
1501 dsp_pointer_to_matrix = ctrl1[6];
1502 dsp_data_organization = ctrl1[7];
1503 dsp_control = ctrl1[8];
1504 dsp_div_control = ctrl1[9];
1505 IMASKCleared = ctrl1[10];
1506 dsp_flag_z = ctrl1[11];
1507 dsp_flag_n = ctrl1[12];
1508 dsp_flag_c = ctrl1[13];
1509 DSPUpdateRegisterBanks();
1511 for(int k=0; k<2; k++)
1513 // Decrement cycles based on non-pipelined core...
1514 instr1 = DSPReadWord(dsp_pc, DSP);
1515 cycles -= dsp_opcode_cycles[instr1 >> 10];
1517 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1518 DSPExec(1); // Do *one* instruction
1522 memcpy(ram1, dsp_ram_8, 0x2000);
1523 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1524 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1527 ctrl1[2] = dsp_remain;
1528 ctrl1[3] = dsp_modulo;
1529 ctrl1[4] = dsp_flags;
1530 ctrl1[5] = dsp_matrix_control;
1531 ctrl1[6] = dsp_pointer_to_matrix;
1532 ctrl1[7] = dsp_data_organization;
1533 ctrl1[8] = dsp_control;
1534 ctrl1[9] = dsp_div_control;
1535 ctrl1[10] = IMASKCleared;
1536 ctrl1[11] = dsp_flag_z;
1537 ctrl1[12] = dsp_flag_n;
1538 ctrl1[13] = dsp_flag_c;
1542 if (instr1 != lastExec)
1544 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1546 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1547 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1560 // DSP execution core
1562 //static bool R20Set = false, tripwire = false;
1563 //static uint32_t pcQueue[32], ptrPCQ = 0;
1564 void DSPExec(int32_t cycles)
1566 #ifdef DSP_SINGLE_STEPPING
1567 if (dsp_control & 0x18)
1570 dsp_control &= ~0x10;
1573 //There is *no* good reason to do this here!
1575 dsp_releaseTimeSlice_flag = 0;
1578 while (cycles > 0 && DSP_RUNNING)
1580 /*extern uint32_t totalFrames;
1581 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1582 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1583 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1585 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1588 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1590 if (dsp_pc == 0xF1B092)
1591 doDSPDis = false;//*/
1592 /*if (dsp_pc == 0xF1B140)
1593 doDSPDis = true;//*/
1595 if (IMASKCleared) // If IMASK was cleared,
1597 #ifdef DSP_DEBUG_IRQ
1598 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1600 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1601 IMASKCleared = false;
1606 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1607 for(int i=0; i<80; i+=4)
1608 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1611 /*if (dsp_pc == 0xF1B55E)
1613 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1615 /*if (dsp_pc == 0xF1B7D2) // Start here???
1617 pcQueue[ptrPCQ++] = dsp_pc;
1619 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1620 uint32_t index = opcode >> 10;
1621 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1622 dsp_opcode_second_parameter = opcode & 0x1F;
1624 dsp_opcode[index]();
1625 dsp_opcode_use[index]++;
1626 cycles -= dsp_opcode_cycles[index];
1627 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1629 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1632 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1634 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1636 DSPDumpDisassembly();
1639 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1642 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1645 WriteLog("\nBacktrace:\n");
1646 for(int i=0; i<32; i++)
1648 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1649 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1660 // DSP opcode handlers
1663 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1664 // can cause trouble because an interrupt can occur *before* the instruction following the
1665 // jump can execute... !!! FIX !!!
1666 static void dsp_opcode_jump(void)
1669 const char * condition[32] =
1670 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1671 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1672 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1673 "???", "???", "???", "F" };
1675 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);
1678 /* dsp_flag_c=dsp_flag_c?1:0;
1679 dsp_flag_z=dsp_flag_z?1:0;
1680 dsp_flag_n=dsp_flag_n?1:0;*/
1681 // KLUDGE: Used by BRANCH_CONDITION
1682 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1684 if (BRANCH_CONDITION(IMM_2))
1688 WriteLog("Branched!\n");
1690 uint32_t delayed_pc = RM;
1692 dsp_pc = delayed_pc;
1697 WriteLog("Branch NOT taken.\n");
1702 static void dsp_opcode_jr(void)
1705 const char * condition[32] =
1706 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1707 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1708 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1709 "???", "???", "???", "F" };
1711 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);
1714 /* dsp_flag_c=dsp_flag_c?1:0;
1715 dsp_flag_z=dsp_flag_z?1:0;
1716 dsp_flag_n=dsp_flag_n?1:0;*/
1717 // KLUDGE: Used by BRANCH_CONDITION
1718 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1720 if (BRANCH_CONDITION(IMM_2))
1724 WriteLog("Branched!\n");
1726 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1727 int32_t delayed_pc = dsp_pc + (offset * 2);
1729 dsp_pc = delayed_pc;
1734 WriteLog("Branch NOT taken.\n");
1739 static void dsp_opcode_add(void)
1743 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);
1745 uint32_t res = RN + RM;
1746 SET_ZNC_ADD(RN, RM, res);
1750 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);
1755 static void dsp_opcode_addc(void)
1759 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);
1761 uint32_t res = RN + RM + dsp_flag_c;
1762 uint32_t carry = dsp_flag_c;
1763 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1764 SET_ZNC_ADD(RN + carry, RM, res);
1765 // SET_ZNC_ADD(RN, RM + carry, res);
1769 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);
1774 static void dsp_opcode_addq(void)
1778 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);
1780 uint32_t r1 = dsp_convert_zero[IMM_1];
1781 uint32_t res = RN + r1;
1782 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1786 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1791 static void dsp_opcode_sub(void)
1795 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);
1797 uint32_t res = RN - RM;
1798 SET_ZNC_SUB(RN, RM, res);
1802 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);
1807 static void dsp_opcode_subc(void)
1811 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);
1813 // This is how the DSP ALU does it--Two's complement with inverted carry
1814 uint64_t res = (uint64_t)RN + (uint64_t)(RM ^ 0xFFFFFFFF) + (dsp_flag_c ^ 1);
1815 // Carry out of the result is inverted too
1816 dsp_flag_c = ((res >> 32) & 0x01) ^ 1;
1817 RN = (res & 0xFFFFFFFF);
1821 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);
1826 static void dsp_opcode_subq(void)
1830 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);
1832 uint32_t r1 = dsp_convert_zero[IMM_1];
1833 uint32_t res = RN - r1;
1834 SET_ZNC_SUB(RN, r1, res);
1838 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1843 static void dsp_opcode_cmp(void)
1847 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);
1849 uint32_t res = RN - RM;
1850 SET_ZNC_SUB(RN, RM, res);
1853 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1858 static void dsp_opcode_cmpq(void)
1860 static int32_t sqtable[32] =
1861 { 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 };
1864 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);
1866 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1867 uint32_t res = RN - r1;
1868 SET_ZNC_SUB(RN, r1, res);
1871 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1876 static void dsp_opcode_and(void)
1880 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);
1886 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);
1891 static void dsp_opcode_or(void)
1895 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);
1901 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);
1906 static void dsp_opcode_xor(void)
1910 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);
1916 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);
1921 static void dsp_opcode_not(void)
1925 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);
1931 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1936 static void dsp_opcode_move_pc(void)
1942 static void dsp_opcode_store_r14_indexed(void)
1944 #ifdef DSP_DIS_STORE14I
1946 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));
1948 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1949 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1951 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1956 static void dsp_opcode_store_r15_indexed(void)
1958 #ifdef DSP_DIS_STORE15I
1960 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));
1962 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1963 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1965 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1970 static void dsp_opcode_load_r14_ri(void)
1972 #ifdef DSP_DIS_LOAD14R
1974 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);
1976 #ifdef DSP_CORRECT_ALIGNMENT
1977 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1979 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1981 #ifdef DSP_DIS_LOAD14R
1983 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1988 static void dsp_opcode_load_r15_ri(void)
1990 #ifdef DSP_DIS_LOAD15R
1992 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);
1994 #ifdef DSP_CORRECT_ALIGNMENT
1995 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1997 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
1999 #ifdef DSP_DIS_LOAD15R
2001 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2006 static void dsp_opcode_store_r14_ri(void)
2008 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2012 static void dsp_opcode_store_r15_ri(void)
2014 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2018 static void dsp_opcode_nop(void)
2022 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2027 static void dsp_opcode_storeb(void)
2029 #ifdef DSP_DIS_STOREB
2031 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);
2033 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2034 DSPWriteLong(RM, RN & 0xFF, DSP);
2036 JaguarWriteByte(RM, RN, DSP);
2040 static void dsp_opcode_storew(void)
2042 #ifdef DSP_DIS_STOREW
2044 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);
2046 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2047 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2048 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2050 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2052 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2053 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2055 JaguarWriteWord(RM, RN, DSP);
2060 static void dsp_opcode_store(void)
2062 #ifdef DSP_DIS_STORE
2064 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);
2066 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2067 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2069 DSPWriteLong(RM, RN, DSP);
2074 static void dsp_opcode_loadb(void)
2076 #ifdef DSP_DIS_LOADB
2078 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);
2080 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2081 RN = DSPReadLong(RM, DSP) & 0xFF;
2083 RN = JaguarReadByte(RM, DSP);
2084 #ifdef DSP_DIS_LOADB
2086 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2091 static void dsp_opcode_loadw(void)
2093 #ifdef DSP_DIS_LOADW
2095 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);
2097 #ifdef DSP_CORRECT_ALIGNMENT
2098 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2099 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2101 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2103 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2104 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2106 RN = JaguarReadWord(RM, DSP);
2108 #ifdef DSP_DIS_LOADW
2110 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2115 static void dsp_opcode_load(void)
2119 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);
2121 #ifdef DSP_CORRECT_ALIGNMENT
2122 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2124 RN = DSPReadLong(RM, DSP);
2128 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2133 static void dsp_opcode_load_r14_indexed(void)
2135 #ifdef DSP_DIS_LOAD14I
2137 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);
2139 #ifdef DSP_CORRECT_ALIGNMENT
2140 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2142 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2144 #ifdef DSP_DIS_LOAD14I
2146 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2151 static void dsp_opcode_load_r15_indexed(void)
2153 #ifdef DSP_DIS_LOAD15I
2155 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);
2157 #ifdef DSP_CORRECT_ALIGNMENT
2158 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2160 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2162 #ifdef DSP_DIS_LOAD15I
2164 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2169 static void dsp_opcode_movei(void)
2171 #ifdef DSP_DIS_MOVEI
2173 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);
2175 // This instruction is followed by 32-bit value in LSW / MSW format...
2176 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2178 #ifdef DSP_DIS_MOVEI
2180 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2185 static void dsp_opcode_moveta(void)
2187 #ifdef DSP_DIS_MOVETA
2189 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);
2192 #ifdef DSP_DIS_MOVETA
2194 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);
2199 static void dsp_opcode_movefa(void)
2201 #ifdef DSP_DIS_MOVEFA
2203 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);
2206 #ifdef DSP_DIS_MOVEFA
2208 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);
2213 static void dsp_opcode_move(void)
2217 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);
2222 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);
2227 static void dsp_opcode_moveq(void)
2229 #ifdef DSP_DIS_MOVEQ
2231 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);
2234 #ifdef DSP_DIS_MOVEQ
2236 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2241 static void dsp_opcode_resmac(void)
2243 #ifdef DSP_DIS_RESMAC
2245 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));
2247 RN = (uint32_t)dsp_acc;
2248 #ifdef DSP_DIS_RESMAC
2250 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2255 static void dsp_opcode_imult(void)
2257 #ifdef DSP_DIS_IMULT
2259 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);
2261 RN = (int16_t)RN * (int16_t)RM;
2263 #ifdef DSP_DIS_IMULT
2265 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);
2270 static void dsp_opcode_mult(void)
2274 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);
2276 RN = (uint16_t)RM * (uint16_t)RN;
2280 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);
2285 static void dsp_opcode_bclr(void)
2289 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);
2291 uint32_t res = RN & ~(1 << IMM_1);
2296 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2301 static void dsp_opcode_btst(void)
2305 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);
2307 dsp_flag_z = (~RN >> IMM_1) & 1;
2310 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2315 static void dsp_opcode_bset(void)
2319 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);
2321 uint32_t res = RN | (1 << IMM_1);
2326 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2331 static void dsp_opcode_subqt(void)
2333 #ifdef DSP_DIS_SUBQT
2335 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);
2337 RN -= dsp_convert_zero[IMM_1];
2338 #ifdef DSP_DIS_SUBQT
2340 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2345 static void dsp_opcode_addqt(void)
2347 #ifdef DSP_DIS_ADDQT
2349 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);
2351 RN += dsp_convert_zero[IMM_1];
2352 #ifdef DSP_DIS_ADDQT
2354 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2359 static void dsp_opcode_imacn(void)
2361 #ifdef DSP_DIS_IMACN
2363 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);
2365 int32_t res = (int16_t)RM * (int16_t)RN;
2366 dsp_acc += (int64_t)res;
2367 //Should we AND the result to fit into 40 bits here???
2368 #ifdef DSP_DIS_IMACN
2370 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));
2375 static void dsp_opcode_mtoi(void)
2377 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2382 static void dsp_opcode_normi(void)
2389 while ((_Rm & 0xffc00000) == 0)
2394 while ((_Rm & 0xff800000) != 0)
2405 static void dsp_opcode_mmult(void)
2407 int count = dsp_matrix_control&0x0f;
2408 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2412 if (!(dsp_matrix_control & 0x10))
2414 for (int i = 0; i < count; i++)
2418 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2420 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2421 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2428 for (int i = 0; i < count; i++)
2432 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2434 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2435 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2440 RN = res = (int32_t)accum;
2442 //NOTE: The flags are set based upon the last add/multiply done...
2447 static void dsp_opcode_abs(void)
2451 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);
2456 if (_Rn == 0x80000000)
2460 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2461 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2466 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2471 static void dsp_opcode_div(void)
2476 if (dsp_div_control & 0x01) // 16.16 division
2478 dsp_remain = ((uint64_t)RN << 16) % RM;
2479 RN = ((uint64_t)RN << 16) / RM;
2483 // We calculate the remainder first because we destroy RN after
2484 // this by assigning it to itself.
2485 dsp_remain = RN % RM;
2492 // This is what happens according to SCPCD. NYAN!
2497 // Real algorithm, courtesy of SCPCD: NYAN!
2501 // If 16.16 division, stuff top 16 bits of RN into remainder and put the
2502 // bottom 16 of RN in top 16 of quotient
2503 if (dsp_div_control & 0x01)
2504 q <<= 16, r = RN >> 16;
2506 for(int i=0; i<32; i++)
2508 // uint32_t sign = (r >> 31) & 0x01;
2509 uint32_t sign = r & 0x80000000;
2510 r = (r << 1) | ((q >> 31) & 0x01);
2511 r += (sign ? RM : -RM);
2512 q = (q << 1) | (((~r) >> 31) & 0x01);
2521 static void dsp_opcode_imultn(void)
2523 #ifdef DSP_DIS_IMULTN
2525 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);
2527 // This is OK, since this multiply won't overflow 32 bits...
2528 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2529 dsp_acc = (int64_t)res;
2531 #ifdef DSP_DIS_IMULTN
2533 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));
2538 static void dsp_opcode_neg(void)
2542 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);
2545 SET_ZNC_SUB(0, RN, res);
2549 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_shlq(void)
2558 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);
2560 // NB: This instruction is the *only* one that does (32 - immediate data).
2561 int32_t r1 = 32 - IMM_1;
2562 uint32_t res = RN << r1;
2563 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2572 static void dsp_opcode_shrq(void)
2576 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);
2578 int32_t r1 = dsp_convert_zero[IMM_1];
2579 uint32_t res = RN >> r1;
2580 SET_ZN(res); dsp_flag_c = RN & 1;
2584 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2589 static void dsp_opcode_ror(void)
2593 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);
2595 uint32_t r1 = RM & 0x1F;
2596 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2597 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2601 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);
2606 static void dsp_opcode_rorq(void)
2610 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);
2612 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2614 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2616 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2619 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2624 static void dsp_opcode_sha(void)
2626 int32_t sRm=(int32_t)RM;
2631 uint32_t shift=-sRm;
2632 if (shift>=32) shift=32;
2633 dsp_flag_c=(_Rn&0x80000000)>>31;
2643 if (shift>=32) shift=32;
2647 _Rn=((int32_t)_Rn)>>1;
2656 static void dsp_opcode_sharq(void)
2658 #ifdef DSP_DIS_SHARQ
2660 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);
2662 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2663 SET_ZN(res); dsp_flag_c = RN & 0x01;
2665 #ifdef DSP_DIS_SHARQ
2667 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2672 static void dsp_opcode_sh(void)
2674 int32_t sRm=(int32_t)RM;
2679 uint32_t shift=(-sRm);
2680 if (shift>=32) shift=32;
2681 dsp_flag_c=(_Rn&0x80000000)>>31;
2691 if (shift>=32) shift=32;
2703 void dsp_opcode_addqmod(void)
2705 #ifdef DSP_DIS_ADDQMOD
2707 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);
2709 uint32_t r1 = dsp_convert_zero[IMM_1];
2711 uint32_t res = r2 + r1;
2712 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2714 SET_ZNC_ADD(r2, r1, res);
2715 #ifdef DSP_DIS_ADDQMOD
2717 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2721 void dsp_opcode_subqmod(void)
2723 uint32_t r1 = dsp_convert_zero[IMM_1];
2725 uint32_t res = r2 - r1;
2726 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2729 SET_ZNC_SUB(r2, r1, res);
2732 void dsp_opcode_mirror(void)
2735 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2739 void dsp_opcode_sat32s(void)
2741 int32_t r2 = (uint32_t)RN;
2742 int32_t temp = dsp_acc >> 32;
2743 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2748 void dsp_opcode_sat16s(void)
2751 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2756 void dsp_opcode_illegal(void)
2758 // Don't know what it does, but it does *something*...
2759 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);
2763 // New pipelined DSP core
2766 static void DSP_abs(void);
2767 static void DSP_add(void);
2768 static void DSP_addc(void);
2769 static void DSP_addq(void);
2770 static void DSP_addqmod(void);
2771 static void DSP_addqt(void);
2772 static void DSP_and(void);
2773 static void DSP_bclr(void);
2774 static void DSP_bset(void);
2775 static void DSP_btst(void);
2776 static void DSP_cmp(void);
2777 static void DSP_cmpq(void);
2778 static void DSP_div(void);
2779 static void DSP_imacn(void);
2780 static void DSP_imult(void);
2781 static void DSP_imultn(void);
2782 static void DSP_illegal(void);
2783 static void DSP_jr(void);
2784 static void DSP_jump(void);
2785 static void DSP_load(void);
2786 static void DSP_loadb(void);
2787 static void DSP_loadw(void);
2788 static void DSP_load_r14_i(void);
2789 static void DSP_load_r14_r(void);
2790 static void DSP_load_r15_i(void);
2791 static void DSP_load_r15_r(void);
2792 static void DSP_mirror(void);
2793 static void DSP_mmult(void);
2794 static void DSP_move(void);
2795 static void DSP_movefa(void);
2796 static void DSP_movei(void);
2797 static void DSP_movepc(void);
2798 static void DSP_moveq(void);
2799 static void DSP_moveta(void);
2800 static void DSP_mtoi(void);
2801 static void DSP_mult(void);
2802 static void DSP_neg(void);
2803 static void DSP_nop(void);
2804 static void DSP_normi(void);
2805 static void DSP_not(void);
2806 static void DSP_or(void);
2807 static void DSP_resmac(void);
2808 static void DSP_ror(void);
2809 static void DSP_rorq(void);
2810 static void DSP_sat16s(void);
2811 static void DSP_sat32s(void);
2812 static void DSP_sh(void);
2813 static void DSP_sha(void);
2814 static void DSP_sharq(void);
2815 static void DSP_shlq(void);
2816 static void DSP_shrq(void);
2817 static void DSP_store(void);
2818 static void DSP_storeb(void);
2819 static void DSP_storew(void);
2820 static void DSP_store_r14_i(void);
2821 static void DSP_store_r14_r(void);
2822 static void DSP_store_r15_i(void);
2823 static void DSP_store_r15_r(void);
2824 static void DSP_sub(void);
2825 static void DSP_subc(void);
2826 static void DSP_subq(void);
2827 static void DSP_subqmod(void);
2828 static void DSP_subqt(void);
2829 static void DSP_xor(void);
2831 void (* DSPOpcode[64])() =
2833 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2834 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2835 DSP_neg, DSP_and, DSP_or, DSP_xor,
2836 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2838 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2839 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2840 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2841 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2843 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2844 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2845 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2846 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2848 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2849 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2850 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2851 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2854 bool readAffected[64][2] =
2856 { true, true}, { true, true}, {false, true}, {false, true},
2857 { true, true}, { true, true}, {false, true}, {false, true},
2858 {false, true}, { true, true}, { true, true}, { true, true},
2859 {false, true}, {false, true}, {false, true}, {false, true},
2861 { true, true}, { true, true}, { true, true}, {false, true},
2862 { true, true}, { true, true}, {false, true}, { true, true},
2863 {false, true}, {false, true}, { true, true}, {false, true},
2864 { true, true}, {false, true}, { true, true}, {false, true},
2866 {false, true}, {false, true}, { true, false}, {false, false},
2867 { true, false}, {false, false}, {false, false}, { true, false},
2868 { true, false}, { true, false}, {false, true}, { true, false},
2869 { true, false}, { true, true}, { true, true}, { true, true},
2871 {false, true}, { true, true}, { true, true}, {false, true},
2872 { true, false}, { true, false}, { true, true}, { true, false},
2873 { true, false}, {false, false}, { true, false}, { true, false},
2874 { true, true}, { true, true}, {false, false}, {false, true}
2877 bool isLoadStore[65] =
2879 false, false, false, false, false, false, false, false,
2880 false, false, false, false, false, false, false, false,
2882 false, false, false, false, false, false, false, false,
2883 false, false, false, false, false, false, false, false,
2885 false, false, false, false, false, false, false, true,
2886 true, true, false, true, true, true, true, true,
2888 false, true, true, false, false, false, false, false,
2889 false, false, true, true, true, true, false, false, false
2892 void FlushDSPPipeline(void)
2894 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2896 for(int i=0; i<4; i++)
2897 pipeline[i].opcode = PIPELINE_STALL;
2899 for(int i=0; i<32; i++)
2904 // New pipelined DSP execution core
2906 /*void DSPExecP(int32_t cycles)
2908 // bool inhibitFetch = false;
2910 dsp_releaseTimeSlice_flag = 0;
2913 while (cycles > 0 && DSP_RUNNING)
2915 WriteLog("DSPExecP: Pipeline status...\n");
2916 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);
2917 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);
2918 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);
2919 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);
2920 WriteLog(" --> Scoreboard: ");
2921 for(int i=0; i<32; i++)
2922 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2924 // Stage 1: Instruction fetch
2925 // if (!inhibitFetch)
2927 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2928 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2929 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2930 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2931 if (pipeline[plPtrFetch].opcode == 38)
2932 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2933 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2936 // inhibitFetch = false;
2937 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2939 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2940 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);
2941 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);
2942 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);
2943 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);
2944 // Stage 2: Read registers
2945 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2946 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2947 if (scoreboard[pipeline[plPtrRead].operand2])
2948 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2949 // We have a hit in the scoreboard, so we have to stall the pipeline...
2951 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2952 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2953 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2954 pipeline[plPtrFetch] = pipeline[plPtrRead];
2955 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2959 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2960 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2961 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2963 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2964 // Shouldn't we be more selective with the register scoreboarding?
2965 // Yes, we should. !!! FIX !!!
2966 scoreboard[pipeline[plPtrRead].operand2] = true;
2967 //Advance PC here??? Yes.
2968 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2969 //This is a mangling of the pipeline stages, but what else to do???
2970 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2973 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2974 WriteLog("\tF -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrFetch].opcode, pipeline[plPtrFetch].operand1, pipeline[plPtrFetch].operand2, pipeline[plPtrFetch].reg1, pipeline[plPtrFetch].reg2, pipeline[plPtrFetch].result, pipeline[plPtrFetch].writebackRegister);
2975 WriteLog("\tR -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister);
2976 WriteLog("\tE -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister);
2977 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2979 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2981 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2982 DSPOpcode[pipeline[plPtrExec].opcode]();
2983 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2984 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2989 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2990 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);
2991 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);
2992 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);
2993 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);
2994 // Stage 4: Write back register
2995 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2997 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2998 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3000 scoreboard[pipeline[plPtrWrite].operand1]
3001 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3004 // Push instructions through the pipeline...
3005 plPtrFetch = (++plPtrFetch) & 0x03;
3006 plPtrRead = (++plPtrRead) & 0x03;
3007 plPtrExec = (++plPtrExec) & 0x03;
3008 plPtrWrite = (++plPtrWrite) & 0x03;
3015 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3017 // Should be fixed now. Another problem is figuring how to do the sequence following
3018 // a branch followed with the JR & JUMP instructions...
3020 // There are two conflicting problems:
3023 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3024 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3025 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3026 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3027 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3028 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3029 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3030 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3031 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3032 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3033 DSP: Finished interrupt.
3034 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3035 ; bank 0 (where is was prepared)!
3036 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3037 F1B252: NOP [NCZ:001]
3040 // The other is when you see this at the end of an IRQ:
3043 JUMP T, (R29) ; R29 = Previous stack + 2
3044 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3046 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3047 ; 1) The STORE goes through the pipeline and is executed/written back
3048 ; 2) The pipeline is flushed
3049 ; 3) The DSP_PC is set to the new address
3050 ; 4) Execution resumes
3052 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3053 ; bank 0 instead of the current bank 1 and so goes astray!
3056 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3057 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3061 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3062 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3063 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3064 If it were done properly, the STORE write back would occur *after* (well, technically,
3065 during) the execution of the the JUMP that follows it.
3069 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3070 F1B08A: NOP [NCZ:001]
3072 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3075 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3078 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3079 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3080 F1B08A: NOP [NCZ:001]
3082 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3085 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3086 DSP: CPU -> DSP interrupt
3087 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3088 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3090 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3093 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3094 F1B006: NOP [NCZ:001]
3096 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3099 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3100 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3103 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3104 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3107 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3108 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3111 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3112 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3115 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3118 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3121 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3122 F1B0FE: NOP [NCZ:000]
3124 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3127 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3130 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3131 F1B138: NOP [NCZ:000]
3133 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3136 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3137 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3138 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3141 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3142 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3145 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3146 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3147 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3149 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3150 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3153 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3154 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3155 DSP: Finished interrupt.
3156 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3158 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3161 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3162 F1B016: NOP [NCZ:001]
3164 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3167 uint32_t pcQueue1[0x400];
3168 uint32_t pcQPtr1 = 0;
3169 static uint32_t prevR1;
3170 //Let's try a 3 stage pipeline....
3171 //Looks like 3 stage is correct, otherwise bad things happen...
3172 void DSPExecP2(int32_t cycles)
3174 dsp_releaseTimeSlice_flag = 0;
3177 while (cycles > 0 && DSP_RUNNING)
3179 /*extern uint32_t totalFrames;
3180 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3181 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3182 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3184 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3187 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3189 if (dsp_pc == 0xF1B092)
3190 doDSPDis = false;//*/
3191 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3192 doDSPDis = true;//*/
3193 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3194 doDSPDis = true;//*/
3195 /*if (dsp_pc == 0xF1B0A0)
3196 doDSPDis = true;//*/
3197 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3198 doDSPDis = true;//*/
3199 //Two parter... (not sure how to write this)
3200 //if (dsp_pc == 0xF1B0D2)
3201 // prevR1 = dsp_reg[1];
3203 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3204 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3207 pcQueue1[pcQPtr1++] = dsp_pc;
3210 #ifdef DSP_DEBUG_PL2
3211 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3213 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3218 for(int i=0; i<0x400; i++)
3220 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3221 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3227 if (IMASKCleared) // If IMASK was cleared,
3229 #ifdef DSP_DEBUG_IRQ
3230 WriteLog("DSP: Finished interrupt.\n");
3232 DSPHandleIRQs(); // See if any other interrupts are pending!
3233 IMASKCleared = false;
3236 //if (dsp_flags & REGPAGE)
3237 // WriteLog(" --> REGPAGE has just been set!\n");
3238 #ifdef DSP_DEBUG_PL2
3241 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3242 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]);
3243 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]);
3244 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]);
3245 WriteLog(" --> Scoreboard: ");
3246 for(int i=0; i<32; i++)
3247 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3251 // Stage 1a: Instruction fetch
3252 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3253 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3254 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3255 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3256 if (pipeline[plPtrRead].opcode == 38)
3257 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3258 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3259 #ifdef DSP_DEBUG_PL2
3262 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3263 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3264 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]);
3265 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]);
3266 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]);
3269 // Stage 1b: Read registers
3270 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3271 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3273 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3274 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3275 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3276 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3277 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3278 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3279 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3281 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3282 // We have a hit in the scoreboard, so we have to stall the pipeline...
3283 #ifdef DSP_DEBUG_PL2
3287 WriteLog(" --> Stalling pipeline: ");
3288 if (readAffected[pipeline[plPtrRead].opcode][0])
3289 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3290 if (readAffected[pipeline[plPtrRead].opcode][1])
3291 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3295 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3296 #ifdef DSP_DEBUG_PL2
3301 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3302 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3303 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3305 // Shouldn't we be more selective with the register scoreboarding?
3306 // Yes, we should. !!! FIX !!! Kinda [DONE]
3307 #ifndef NEW_SCOREBOARD
3308 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3310 //Hopefully this will fix the dual MOVEQ # problem...
3311 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3314 //Advance PC here??? Yes.
3315 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3318 #ifdef DSP_DEBUG_PL2
3321 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3322 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]);
3323 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]);
3324 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]);
3328 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3330 #ifdef DSP_DEBUG_PL2
3332 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"));
3336 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3341 lastExec = pipeline[plPtrExec].instruction;
3342 //WriteLog("[lastExec = %04X]\n", lastExec);
3344 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3345 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3346 DSPOpcode[pipeline[plPtrExec].opcode]();
3347 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3351 //Let's not, until we do the stalling correctly...
3352 //But, we gotta while we're doing the comparison core...!
3353 //Or do we? cycles--;
3354 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3355 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3356 //to model this clock cycle behavior correctly...
3357 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3358 //don't affect the reads at stage 1...
3359 #ifdef DSP_DEBUG_STALL
3361 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3365 #ifdef DSP_DEBUG_PL2
3368 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3369 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]);
3370 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]);
3371 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]);
3375 // Stage 3: Write back register/memory address
3376 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3378 /*if (pipeline[plPtrWrite].writebackRegister == 3
3379 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3382 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3385 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3387 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3388 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3391 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3392 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3393 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3394 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3396 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3400 #ifndef NEW_SCOREBOARD
3401 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3402 scoreboard[pipeline[plPtrWrite].operand2] = false;
3404 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3405 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3406 if (scoreboard[pipeline[plPtrWrite].operand2])
3407 scoreboard[pipeline[plPtrWrite].operand2]--;
3411 // Push instructions through the pipeline...
3412 plPtrRead = (++plPtrRead) & 0x03;
3413 plPtrExec = (++plPtrExec) & 0x03;
3414 plPtrWrite = (++plPtrWrite) & 0x03;
3423 //#define DSP_DEBUG_PL3
3424 //Let's try a 2 stage pipeline....
3425 void DSPExecP3(int32_t cycles)
3427 dsp_releaseTimeSlice_flag = 0;
3430 while (cycles > 0 && DSP_RUNNING)
3432 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3434 #ifdef DSP_DEBUG_PL3
3435 WriteLog("DSPExecP: Pipeline status...\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]);
3438 WriteLog(" --> Scoreboard: ");
3439 for(int i=0; i<32; i++)
3440 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3443 // Stage 1a: Instruction fetch
3444 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3445 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3446 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3447 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3448 if (pipeline[plPtrRead].opcode == 38)
3449 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3450 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3451 #ifdef DSP_DEBUG_PL3
3452 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3453 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3454 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]);
3455 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]);
3457 // Stage 1b: Read registers
3458 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3459 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3460 // We have a hit in the scoreboard, so we have to stall the pipeline...
3461 #ifdef DSP_DEBUG_PL3
3463 WriteLog(" --> Stalling pipeline: ");
3464 if (readAffected[pipeline[plPtrRead].opcode][0])
3465 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3466 if (readAffected[pipeline[plPtrRead].opcode][1])
3467 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3470 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3471 #ifdef DSP_DEBUG_PL3
3476 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3477 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3478 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3480 // Shouldn't we be more selective with the register scoreboarding?
3481 // Yes, we should. !!! FIX !!! [Kinda DONE]
3482 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3484 //Advance PC here??? Yes.
3485 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3488 #ifdef DSP_DEBUG_PL3
3489 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3490 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]);
3491 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]);
3493 // Stage 2a: Execute
3494 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3496 #ifdef DSP_DEBUG_PL3
3497 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3499 DSPOpcode[pipeline[plPtrExec].opcode]();
3500 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3501 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3506 #ifdef DSP_DEBUG_PL3
3507 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3508 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]);
3509 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]);
3512 // Stage 2b: Write back register
3513 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3515 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3516 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3518 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3519 scoreboard[pipeline[plPtrExec].operand2] = false;
3522 // Push instructions through the pipeline...
3523 plPtrRead = (++plPtrRead) & 0x03;
3524 plPtrExec = (++plPtrExec) & 0x03;
3531 // DSP pipelined opcode handlers
3534 #define PRM pipeline[plPtrExec].reg1
3535 #define PRN pipeline[plPtrExec].reg2
3536 #define PIMM1 pipeline[plPtrExec].operand1
3537 #define PIMM2 pipeline[plPtrExec].operand2
3538 #define PRES pipeline[plPtrExec].result
3539 #define PWBR pipeline[plPtrExec].writebackRegister
3540 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3541 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3542 #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))
3543 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3545 static void DSP_abs(void)
3549 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);
3553 if (_Rn == 0x80000000)
3557 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3558 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3559 CLR_ZN; SET_Z(PRES);
3563 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3567 static void DSP_add(void)
3571 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);
3573 uint32_t res = PRN + PRM;
3574 SET_ZNC_ADD(PRN, PRM, res);
3578 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);
3582 static void DSP_addc(void)
3586 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);
3588 uint32_t res = PRN + PRM + dsp_flag_c;
3589 uint32_t carry = dsp_flag_c;
3590 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3591 SET_ZNC_ADD(PRN + carry, PRM, res);
3592 // SET_ZNC_ADD(PRN, PRM + carry, res);
3596 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);
3600 static void DSP_addq(void)
3604 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);
3606 uint32_t r1 = dsp_convert_zero[PIMM1];
3607 uint32_t res = PRN + r1;
3608 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3612 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3616 static void DSP_addqmod(void)
3618 #ifdef DSP_DIS_ADDQMOD
3620 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);
3622 uint32_t r1 = dsp_convert_zero[PIMM1];
3624 uint32_t res = r2 + r1;
3625 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3627 SET_ZNC_ADD(r2, r1, res);
3628 #ifdef DSP_DIS_ADDQMOD
3630 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3634 static void DSP_addqt(void)
3636 #ifdef DSP_DIS_ADDQT
3638 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);
3640 PRES = PRN + dsp_convert_zero[PIMM1];
3641 #ifdef DSP_DIS_ADDQT
3643 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3647 static void DSP_and(void)
3651 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);
3657 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);
3661 static void DSP_bclr(void)
3665 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);
3667 PRES = PRN & ~(1 << PIMM1);
3671 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3675 static void DSP_bset(void)
3679 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);
3681 PRES = PRN | (1 << PIMM1);
3685 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3689 static void DSP_btst(void)
3693 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);
3695 dsp_flag_z = (~PRN >> PIMM1) & 1;
3699 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3703 static void DSP_cmp(void)
3707 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);
3709 uint32_t res = PRN - PRM;
3710 SET_ZNC_SUB(PRN, PRM, res);
3714 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3718 static void DSP_cmpq(void)
3720 static int32_t sqtable[32] =
3721 { 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 };
3724 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);
3726 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3727 uint32_t res = PRN - r1;
3728 SET_ZNC_SUB(PRN, r1, res);
3732 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3736 static void DSP_div(void)
3738 uint32_t _Rm = PRM, _Rn = PRN;
3742 if (dsp_div_control & 1)
3744 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3745 if (dsp_remain & 0x80000000)
3747 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3751 dsp_remain = _Rn % _Rm;
3752 if (dsp_remain & 0x80000000)
3761 static void DSP_imacn(void)
3763 #ifdef DSP_DIS_IMACN
3765 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);
3767 int32_t res = (int16_t)PRM * (int16_t)PRN;
3768 dsp_acc += (int64_t)res;
3769 //Should we AND the result to fit into 40 bits here???
3771 #ifdef DSP_DIS_IMACN
3773 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));
3777 static void DSP_imult(void)
3779 #ifdef DSP_DIS_IMULT
3781 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);
3783 PRES = (int16_t)PRN * (int16_t)PRM;
3785 #ifdef DSP_DIS_IMULT
3787 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);
3791 static void DSP_imultn(void)
3793 #ifdef DSP_DIS_IMULTN
3795 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);
3797 // This is OK, since this multiply won't overflow 32 bits...
3798 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3799 dsp_acc = (int64_t)res;
3802 #ifdef DSP_DIS_IMULTN
3804 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));
3808 static void DSP_illegal(void)
3810 #ifdef DSP_DIS_ILLEGAL
3812 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3817 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3818 // can cause trouble because an interrupt can occur *before* the instruction following the
3819 // jump can execute... !!! FIX !!!
3820 // This can probably be solved by judicious coding in the pipeline execution core...
3821 // And should be fixed now...
3822 static void DSP_jr(void)
3825 const char * condition[32] =
3826 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3827 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3828 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3829 "???", "???", "???", "F" };
3831 //How come this is always off by 2???
3832 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);
3834 // KLUDGE: Used by BRANCH_CONDITION macro
3835 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3837 if (BRANCH_CONDITION(PIMM2))
3841 WriteLog("Branched!\n");
3843 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3844 //Account for pipeline effects...
3845 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3846 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3848 // Now that we've branched, we have to make sure that the following instruction
3849 // is executed atomically with this one and then flush the pipeline before setting
3852 // Step 1: Handle writebacks at stage 3 of pipeline
3853 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3855 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3856 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3858 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3859 scoreboard[pipeline[plPtrWrite].operand2] = false;
3861 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3863 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3865 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3866 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3869 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3870 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3871 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3872 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3874 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3878 #ifndef NEW_SCOREBOARD
3879 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3880 scoreboard[pipeline[plPtrWrite].operand2] = false;
3882 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3883 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3884 if (scoreboard[pipeline[plPtrWrite].operand2])
3885 scoreboard[pipeline[plPtrWrite].operand2]--;
3889 // Step 2: Push instruction through pipeline & execute following instruction
3890 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3891 // we effectively handle the final push of the instruction through the
3892 // pipeline when the new PC takes effect (since when we return, the
3893 // pipeline code will be executing the writeback stage. If we reverse
3894 // the execution order of the pipeline stages, this will no longer be
3896 pipeline[plPtrExec] = pipeline[plPtrRead];
3897 //This is BAD. We need to get that next opcode and execute it!
3898 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3899 // remove this crap.
3900 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3902 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3903 pipeline[plPtrExec].opcode = instruction >> 10;
3904 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3905 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3906 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3907 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3908 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3910 dsp_pc += 2; // For DSP_DIS_* accuracy
3911 DSPOpcode[pipeline[plPtrExec].opcode]();
3912 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3913 pipeline[plPtrWrite] = pipeline[plPtrExec];
3915 // Step 3: Flush pipeline & set new PC
3916 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3923 WriteLog("Branch NOT taken.\n");
3929 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3932 static void DSP_jump(void)
3935 const char * condition[32] =
3936 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3937 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3938 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3939 "???", "???", "???", "F" };
3941 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);
3943 // KLUDGE: Used by BRANCH_CONDITION macro
3944 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3946 if (BRANCH_CONDITION(PIMM2))
3950 WriteLog("Branched!\n");
3952 uint32_t PCSave = PRM;
3953 // Now that we've branched, we have to make sure that the following instruction
3954 // is executed atomically with this one and then flush the pipeline before setting
3957 // Step 1: Handle writebacks at stage 3 of pipeline
3958 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3960 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3961 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3963 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3964 scoreboard[pipeline[plPtrWrite].operand2] = false;
3966 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3968 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3970 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3971 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3974 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3975 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3976 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3977 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3979 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3983 #ifndef NEW_SCOREBOARD
3984 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3985 scoreboard[pipeline[plPtrWrite].operand2] = false;
3987 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3988 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3989 if (scoreboard[pipeline[plPtrWrite].operand2])
3990 scoreboard[pipeline[plPtrWrite].operand2]--;
3994 // Step 2: Push instruction through pipeline & execute following instruction
3995 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3996 // we effectively handle the final push of the instruction through the
3997 // pipeline when the new PC takes effect (since when we return, the
3998 // pipeline code will be executing the writeback stage. If we reverse
3999 // the execution order of the pipeline stages, this will no longer be
4001 pipeline[plPtrExec] = pipeline[plPtrRead];
4002 //This is BAD. We need to get that next opcode and execute it!
4003 //Also, same problem in JR!
4004 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4005 // remove this crap.
4006 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
4008 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
4009 pipeline[plPtrExec].opcode = instruction >> 10;
4010 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
4011 pipeline[plPtrExec].operand2 = instruction & 0x1F;
4012 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
4013 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
4014 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
4016 dsp_pc += 2; // For DSP_DIS_* accuracy
4017 DSPOpcode[pipeline[plPtrExec].opcode]();
4018 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
4019 pipeline[plPtrWrite] = pipeline[plPtrExec];
4021 // Step 3: Flush pipeline & set new PC
4022 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4029 WriteLog("Branch NOT taken.\n");
4037 static void DSP_load(void)
4041 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);
4043 #ifdef DSP_CORRECT_ALIGNMENT
4044 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4046 PRES = DSPReadLong(PRM, DSP);
4050 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4054 static void DSP_loadb(void)
4056 #ifdef DSP_DIS_LOADB
4058 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);
4060 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4061 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4063 PRES = JaguarReadByte(PRM, DSP);
4064 #ifdef DSP_DIS_LOADB
4066 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4070 static void DSP_loadw(void)
4072 #ifdef DSP_DIS_LOADW
4074 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);
4076 #ifdef DSP_CORRECT_ALIGNMENT
4077 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4078 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4080 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4082 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4083 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4085 PRES = JaguarReadWord(PRM, DSP);
4087 #ifdef DSP_DIS_LOADW
4089 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4093 static void DSP_load_r14_i(void)
4095 #ifdef DSP_DIS_LOAD14I
4097 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);
4099 #ifdef DSP_CORRECT_ALIGNMENT
4100 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4102 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4104 #ifdef DSP_DIS_LOAD14I
4106 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4110 static void DSP_load_r14_r(void)
4112 #ifdef DSP_DIS_LOAD14R
4114 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);
4116 #ifdef DSP_CORRECT_ALIGNMENT
4117 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4119 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4121 #ifdef DSP_DIS_LOAD14R
4123 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4127 static void DSP_load_r15_i(void)
4129 #ifdef DSP_DIS_LOAD15I
4131 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);
4133 #ifdef DSP_CORRECT_ALIGNMENT
4134 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4136 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4138 #ifdef DSP_DIS_LOAD15I
4140 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4144 static void DSP_load_r15_r(void)
4146 #ifdef DSP_DIS_LOAD15R
4148 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);
4150 #ifdef DSP_CORRECT_ALIGNMENT
4151 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4153 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4155 #ifdef DSP_DIS_LOAD15R
4157 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4161 static void DSP_mirror(void)
4164 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4168 static void DSP_mmult(void)
4170 int count = dsp_matrix_control&0x0f;
4171 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4175 if (!(dsp_matrix_control & 0x10))
4177 for (int i = 0; i < count; i++)
4181 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4183 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4184 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4191 for (int i = 0; i < count; i++)
4195 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4197 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4198 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4204 PRES = res = (int32_t)accum;
4206 //NOTE: The flags are set based upon the last add/multiply done...
4210 static void DSP_move(void)
4214 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);
4219 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);
4223 static void DSP_movefa(void)
4225 #ifdef DSP_DIS_MOVEFA
4227 // 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);
4228 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);
4230 // PRES = ALTERNATE_RM;
4231 PRES = dsp_alternate_reg[PIMM1];
4232 #ifdef DSP_DIS_MOVEFA
4234 // 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);
4235 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);
4239 static void DSP_movei(void)
4241 #ifdef DSP_DIS_MOVEI
4243 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);
4245 // // This instruction is followed by 32-bit value in LSW / MSW format...
4246 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4248 #ifdef DSP_DIS_MOVEI
4250 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4254 static void DSP_movepc(void)
4256 #ifdef DSP_DIS_MOVEPC
4258 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);
4260 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4261 // PRES = dsp_pc - 2;
4262 //Account for pipeline effects...
4263 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4264 #ifdef DSP_DIS_MOVEPC
4266 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4270 static void DSP_moveq(void)
4272 #ifdef DSP_DIS_MOVEQ
4274 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);
4277 #ifdef DSP_DIS_MOVEQ
4279 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4283 static void DSP_moveta(void)
4285 #ifdef DSP_DIS_MOVETA
4287 // 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);
4288 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]);
4290 // ALTERNATE_RN = PRM;
4291 dsp_alternate_reg[PIMM2] = PRM;
4293 #ifdef DSP_DIS_MOVETA
4295 // 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);
4296 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]);
4300 static void DSP_mtoi(void)
4302 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4306 static void DSP_mult(void)
4310 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);
4312 PRES = (uint16_t)PRM * (uint16_t)PRN;
4316 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);
4320 static void DSP_neg(void)
4324 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);
4326 uint32_t res = -PRN;
4327 SET_ZNC_SUB(0, PRN, res);
4331 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4335 static void DSP_nop(void)
4339 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4344 static void DSP_normi(void)
4351 while ((_Rm & 0xffc00000) == 0)
4356 while ((_Rm & 0xff800000) != 0)
4366 static void DSP_not(void)
4370 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);
4376 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4380 static void DSP_or(void)
4384 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);
4390 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);
4394 static void DSP_resmac(void)
4396 #ifdef DSP_DIS_RESMAC
4398 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));
4400 PRES = (uint32_t)dsp_acc;
4401 #ifdef DSP_DIS_RESMAC
4403 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4407 static void DSP_ror(void)
4411 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);
4413 uint32_t r1 = PRM & 0x1F;
4414 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4415 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4419 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);
4423 static void DSP_rorq(void)
4427 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);
4429 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4431 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4433 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4436 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4440 static void DSP_sat16s(void)
4443 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4448 static void DSP_sat32s(void)
4450 int32_t r2 = (uint32_t)PRN;
4451 int32_t temp = dsp_acc >> 32;
4452 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4457 static void DSP_sh(void)
4459 int32_t sRm = (int32_t)PRM;
4464 uint32_t shift = -sRm;
4469 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4479 uint32_t shift = sRm;
4484 dsp_flag_c = _Rn & 0x1;
4497 static void DSP_sha(void)
4499 int32_t sRm = (int32_t)PRM;
4504 uint32_t shift = -sRm;
4509 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4519 uint32_t shift = sRm;
4524 dsp_flag_c = _Rn & 0x1;
4528 _Rn = ((int32_t)_Rn) >> 1;
4537 static void DSP_sharq(void)
4539 #ifdef DSP_DIS_SHARQ
4541 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);
4543 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4544 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4546 #ifdef DSP_DIS_SHARQ
4548 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4552 static void DSP_shlq(void)
4556 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);
4558 int32_t r1 = 32 - PIMM1;
4559 uint32_t res = PRN << r1;
4560 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4564 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4568 static void DSP_shrq(void)
4572 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);
4574 int32_t r1 = dsp_convert_zero[PIMM1];
4575 uint32_t res = PRN >> r1;
4576 SET_ZN(res); dsp_flag_c = PRN & 1;
4580 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4584 static void DSP_store(void)
4586 #ifdef DSP_DIS_STORE
4588 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);
4590 // DSPWriteLong(PRM, PRN, DSP);
4592 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4593 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4595 pipeline[plPtrExec].address = PRM;
4597 pipeline[plPtrExec].value = PRN;
4598 pipeline[plPtrExec].type = TYPE_DWORD;
4602 static void DSP_storeb(void)
4604 #ifdef DSP_DIS_STOREB
4606 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);
4608 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4609 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4611 // JaguarWriteByte(PRM, PRN, DSP);
4614 pipeline[plPtrExec].address = PRM;
4616 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4618 pipeline[plPtrExec].value = PRN & 0xFF;
4619 pipeline[plPtrExec].type = TYPE_DWORD;
4623 pipeline[plPtrExec].value = PRN;
4624 pipeline[plPtrExec].type = TYPE_BYTE;
4630 static void DSP_storew(void)
4632 #ifdef DSP_DIS_STOREW
4634 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);
4636 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4637 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4639 // JaguarWriteWord(PRM, PRN, DSP);
4642 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4643 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4645 pipeline[plPtrExec].address = PRM;
4648 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4650 pipeline[plPtrExec].value = PRN & 0xFFFF;
4651 pipeline[plPtrExec].type = TYPE_DWORD;
4655 pipeline[plPtrExec].value = PRN;
4656 pipeline[plPtrExec].type = TYPE_WORD;
4661 static void DSP_store_r14_i(void)
4663 #ifdef DSP_DIS_STORE14I
4665 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));
4667 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4669 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4670 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4672 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4674 pipeline[plPtrExec].value = PRN;
4675 pipeline[plPtrExec].type = TYPE_DWORD;
4679 static void DSP_store_r14_r(void)
4681 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4683 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4684 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4686 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4688 pipeline[plPtrExec].value = PRN;
4689 pipeline[plPtrExec].type = TYPE_DWORD;
4693 static void DSP_store_r15_i(void)
4695 #ifdef DSP_DIS_STORE15I
4697 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));
4699 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4701 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4702 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4704 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4706 pipeline[plPtrExec].value = PRN;
4707 pipeline[plPtrExec].type = TYPE_DWORD;
4711 static void DSP_store_r15_r(void)
4713 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4715 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4716 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4718 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4720 pipeline[plPtrExec].value = PRN;
4721 pipeline[plPtrExec].type = TYPE_DWORD;
4725 static void DSP_sub(void)
4729 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);
4731 uint32_t res = PRN - PRM;
4732 SET_ZNC_SUB(PRN, PRM, res);
4736 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM1, PRM, PIMM2, PRES);
4740 static void DSP_subc(void)
4744 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);
4746 uint32_t res = PRN - PRM - dsp_flag_c;
4747 uint32_t borrow = dsp_flag_c;
4748 SET_ZNC_SUB(PRN - borrow, PRM, res);
4752 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);
4756 static void DSP_subq(void)
4760 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);
4762 uint32_t r1 = dsp_convert_zero[PIMM1];
4763 uint32_t res = PRN - r1;
4764 SET_ZNC_SUB(PRN, r1, res);
4768 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4772 static void DSP_subqmod(void)
4774 uint32_t r1 = dsp_convert_zero[PIMM1];
4776 uint32_t res = r2 - r1;
4777 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4779 SET_ZNC_SUB(r2, r1, res);
4782 static void DSP_subqt(void)
4784 #ifdef DSP_DIS_SUBQT
4786 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);
4788 PRES = PRN - dsp_convert_zero[PIMM1];
4789 #ifdef DSP_DIS_SUBQT
4791 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4795 static void DSP_xor(void)
4799 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);
4805 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);