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 /*uint8_t dsp_opcode_cycles[64] =
330 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 1,
332 1, 1, 1, 1, 1, 9, 1, 1,
333 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 2,
335 2, 2, 2, 3, 3, 1, 1, 1,
336 1, 1, 1, 1, 1, 1, 4, 1,
337 1, 1, 3, 3, 1, 1, 1, 1
340 void (* dsp_opcode[64])() =
342 dsp_opcode_add, dsp_opcode_addc, dsp_opcode_addq, dsp_opcode_addqt,
343 dsp_opcode_sub, dsp_opcode_subc, dsp_opcode_subq, dsp_opcode_subqt,
344 dsp_opcode_neg, dsp_opcode_and, dsp_opcode_or, dsp_opcode_xor,
345 dsp_opcode_not, dsp_opcode_btst, dsp_opcode_bset, dsp_opcode_bclr,
346 dsp_opcode_mult, dsp_opcode_imult, dsp_opcode_imultn, dsp_opcode_resmac,
347 dsp_opcode_imacn, dsp_opcode_div, dsp_opcode_abs, dsp_opcode_sh,
348 dsp_opcode_shlq, dsp_opcode_shrq, dsp_opcode_sha, dsp_opcode_sharq,
349 dsp_opcode_ror, dsp_opcode_rorq, dsp_opcode_cmp, dsp_opcode_cmpq,
350 dsp_opcode_subqmod, dsp_opcode_sat16s, dsp_opcode_move, dsp_opcode_moveq,
351 dsp_opcode_moveta, dsp_opcode_movefa, dsp_opcode_movei, dsp_opcode_loadb,
352 dsp_opcode_loadw, dsp_opcode_load, dsp_opcode_sat32s, dsp_opcode_load_r14_indexed,
353 dsp_opcode_load_r15_indexed, dsp_opcode_storeb, dsp_opcode_storew, dsp_opcode_store,
354 dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc,
355 dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi,
356 dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri,
357 dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod,
360 uint32_t dsp_opcode_use[65];
362 const char * dsp_opcode_str[65]=
364 "add", "addc", "addq", "addqt",
365 "sub", "subc", "subq", "subqt",
366 "neg", "and", "or", "xor",
367 "not", "btst", "bset", "bclr",
368 "mult", "imult", "imultn", "resmac",
369 "imacn", "div", "abs", "sh",
370 "shlq", "shrq", "sha", "sharq",
371 "ror", "rorq", "cmp", "cmpq",
372 "subqmod", "sat16s", "move", "moveq",
373 "moveta", "movefa", "movei", "loadb",
374 "loadw", "load", "sat32s", "load_r14_indexed",
375 "load_r15_indexed", "storeb", "storew", "store",
376 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
377 "jump", "jr", "mmult", "mtoi",
378 "normi", "nop", "load_r14_ri", "load_r15_ri",
379 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
384 static uint64_t dsp_acc; // 40 bit register, NOT 32!
385 static uint32_t dsp_remain;
386 static uint32_t dsp_modulo;
387 static uint32_t dsp_flags;
388 static uint32_t dsp_matrix_control;
389 static uint32_t dsp_pointer_to_matrix;
390 static uint32_t dsp_data_organization;
391 uint32_t dsp_control;
392 static uint32_t dsp_div_control;
393 static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
394 static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
395 uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
397 static uint32_t dsp_opcode_first_parameter;
398 static uint32_t dsp_opcode_second_parameter;
400 #define DSP_RUNNING (dsp_control & 0x01)
402 #define RM dsp_reg[dsp_opcode_first_parameter]
403 #define RN dsp_reg[dsp_opcode_second_parameter]
404 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
405 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
406 #define IMM_1 dsp_opcode_first_parameter
407 #define IMM_2 dsp_opcode_second_parameter
409 #define CLR_Z (dsp_flag_z = 0)
410 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
411 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
412 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
413 #define SET_N(r) (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
414 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
415 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
416 #define SET_ZN(r) SET_N(r); SET_Z(r)
417 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
418 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
420 uint32_t dsp_convert_zero[32] = {
421 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
422 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
425 uint8_t dsp_branch_condition_table[32 * 8];
426 static uint16_t mirror_table[65536];
427 static uint8_t dsp_ram_8[0x2000];
429 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
431 static uint32_t dsp_in_exec = 0;
432 static uint32_t dsp_releaseTimeSlice_flag = 0;
437 // Comparison core vars (used only for core comparison! :-)
438 static uint64_t count = 0;
439 static uint8_t ram1[0x2000], ram2[0x2000];
440 static uint32_t regs1[64], regs2[64];
441 static uint32_t ctrl1[14], ctrl2[14];
444 // Private function prototypes
446 void DSPDumpRegisters(void);
447 void DSPDumpDisassembly(void);
448 void FlushDSPPipeline(void);
451 void dsp_reset_stats(void)
453 for(int i=0; i<65; i++)
454 dsp_opcode_use[i] = 0;
457 void DSPReleaseTimeslice(void)
459 //This does absolutely nothing!!! !!! FIX !!!
460 dsp_releaseTimeSlice_flag = 1;
463 void dsp_build_branch_condition_table(void)
465 // Fill in the mirror table
466 for(int i=0; i<65536; i++)
468 mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
469 | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
470 | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
471 | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
472 | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
473 | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
474 | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
475 | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
478 // Fill in the condition table
479 for(int i=0; i<8; i++)
481 for(int j=0; j<32; j++)
485 if ((j & 1) && (i & ZERO_FLAG))
488 if ((j & 2) && (!(i & ZERO_FLAG)))
491 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
494 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
497 dsp_branch_condition_table[i * 32 + j] = result;
502 uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
504 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
505 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
507 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
510 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
512 if (offset==0xF1CFE0)
515 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
516 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
518 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
520 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
522 if ((offset&0x03)==0)
525 if ((offset&0x03)==1)
526 return((data>>16)&0xff);
528 if ((offset&0x03)==2)
529 return((data>>8)&0xff);
531 if ((offset&0x03)==3)
535 return JaguarReadByte(offset, who);
538 uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
540 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
541 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
543 offset &= 0xFFFFFFFE;
545 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
547 offset -= DSP_WORK_RAM_BASE;
548 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
550 return GET16(dsp_ram_8, offset);
552 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
554 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
557 return data & 0xFFFF;
562 return JaguarReadWord(offset, who);
565 uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
567 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
568 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
571 offset &= 0xFFFFFFFC;
572 /*if (offset == 0xF1BCF4)
574 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));
575 DSPDumpDisassembly();
577 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
579 offset -= DSP_WORK_RAM_BASE;
580 return GET32(dsp_ram_8, offset);
582 //NOTE: Didn't return DSP_ACCUM!!!
583 //Mebbe it's not 'spose to! Yes, it is!
584 if (offset >= DSP_CONTROL_RAM_BASE && offset <= DSP_CONTROL_RAM_BASE + 0x23)
590 dsp_flags = (dsp_flags & 0xFFFFFFF8) | (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
591 return dsp_flags & 0xFFFFC1FF;
592 case 0x04: return dsp_matrix_control;
593 case 0x08: return dsp_pointer_to_matrix;
594 case 0x0C: return dsp_data_organization;
595 case 0x10: return dsp_pc;
596 case 0x14: return dsp_control;
597 case 0x18: return dsp_modulo;
598 case 0x1C: return dsp_remain;
600 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
602 // unaligned long read-- !!! FIX !!!
606 return JaguarReadLong(offset, who);
609 void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
611 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
612 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
614 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
616 offset -= DSP_WORK_RAM_BASE;
617 dsp_ram_8[offset] = data;
618 //This is rather stupid! !!! FIX !!!
619 /* if (dsp_in_exec == 0)
621 m68k_end_timeslice();
622 dsp_releaseTimeslice();
626 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
628 uint32_t reg = offset & 0x1C;
629 int bytenum = offset & 0x03;
631 if ((reg >= 0x1C) && (reg <= 0x1F))
632 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
635 //This looks funky. !!! FIX !!!
636 uint32_t old_data = DSPReadLong(offset&0xFFFFFFC, who);
637 bytenum = 3 - bytenum; // convention motorola !!!
638 old_data = (old_data & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
639 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
643 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
644 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
645 JaguarWriteByte(offset, data, who);
648 void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
650 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
651 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName[who]);
652 offset &= 0xFFFFFFFE;
653 /*if (offset == 0xF1BCF4)
655 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
657 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
658 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
660 /*if (offset == 0xF1B2F4)
662 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
664 offset -= DSP_WORK_RAM_BASE;
665 dsp_ram_8[offset] = data >> 8;
666 dsp_ram_8[offset+1] = data & 0xFF;
667 //This is rather stupid! !!! FIX !!!
668 /* if (dsp_in_exec == 0)
670 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
671 m68k_end_timeslice();
672 dsp_releaseTimeslice();
676 SET16(ram1, offset, data),
677 SET16(ram2, offset, data);
682 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
684 if ((offset & 0x1C) == 0x1C)
687 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
689 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
693 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
696 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
698 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
700 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
706 JaguarWriteWord(offset, data, who);
709 //bool badWrite = false;
710 void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
712 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
713 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
715 offset &= 0xFFFFFFFC;
716 /*if (offset == 0xF1BCF4)
718 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
720 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
721 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
723 /*if (offset == 0xF1BE2C)
725 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
727 offset -= DSP_WORK_RAM_BASE;
728 SET32(dsp_ram_8, offset, data);
731 SET32(ram1, offset, data),
732 SET32(ram2, offset, data);
737 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
745 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
747 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
748 IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
749 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
750 // IRQ logic can set it. So we mask it out here to prevent problems...
751 dsp_flags = data & (~IMASK);
752 dsp_flag_z = dsp_flags & 0x01;
753 dsp_flag_c = (dsp_flags >> 1) & 0x01;
754 dsp_flag_n = (dsp_flags >> 2) & 0x01;
755 DSPUpdateRegisterBanks();
756 dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
757 dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
759 // NB: This is just a wild hairy-assed guess as to what the playback frequency is.
760 // It can be timed to anything really, anything that writes to L/RTXD at a regular
761 // interval. Most things seem to use either the I2S interrupt or the TIMER 0
762 // interrupt, so that's what we check for here. Just know that this approach
763 // can be easily fooled!
764 // Note also that if both interrupts are enabled, the I2S freq will win. :-P
767 // The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
768 // audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
769 // So, while this works, it's a by-product of the lame way in which audio is currently
770 // handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
771 // go away of its own accord. :-P
772 // Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
773 // weird is going on here...
774 // Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
775 // So subsequent interrupts come into the chip, but they're never serviced but the
776 // I2S subsystem keeps going.
777 // After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
778 // IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
779 // It seems that it's only stable for values of SCLK <= 9.
781 // All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
782 // that we don't actually need this stuff anymore. :-D
784 if (data & INT_ENA1) // I2S interrupt
786 int freq = GetCalculatedFrequency();
787 //This happens too often to be useful...
788 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
789 DACSetNewFrequency(freq);
791 else if (data & INT_ENA2) // TIMER 0 interrupt
793 int freq = JERRYGetPIT1Frequency();
794 //This happens too often to be useful...
795 // WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
796 DACSetNewFrequency(freq);
800 /* if (IMASKCleared) // If IMASK was cleared,
803 WriteLog("DSP: Finished interrupt.\n");
805 DSPHandleIRQs(); // see if any other interrupts need servicing!
810 if (/*4-8, 16*/data & 0x101F0)
811 WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
812 (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
813 (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
814 (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
815 /*if (data & 0x00020) // CD BIOS DSP code...
817 //001AC1BA: movea.l #$1AC200, A0
818 //001AC1C0: move.l #$1AC68C, D0
821 WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
822 uint32_t j = 0xF1B97C;//0x1AC200;
823 while (j <= 0xF1BE08)//0x1AC68C)
826 j += dasmjag(JAGUAR_DSP, buffer, j);
827 // WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
828 WriteLog("\t%08X: %s\n", oldj, buffer);
835 dsp_matrix_control = data;
838 // According to JTRM, only lines 2-11 are addressable, the rest being
839 // hardwired to $F1Bxxx.
840 dsp_pointer_to_matrix = 0xF1B000 | (data & 0x000FFC);
843 dsp_data_organization = data;
848 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
853 ctrl1[0] = ctrl2[0] = data;
860 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
862 bool wasRunning = DSP_RUNNING;
863 // uint32_t dsp_was_running = DSP_RUNNING;
864 // Check for DSP -> CPU interrupt
868 WriteLog("DSP: DSP -> CPU interrupt\n");
871 // Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
872 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
873 if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
875 JERRYSetPendingIRQ(IRQ2_DSP);
876 DSPReleaseTimeslice();
877 m68k_set_irq(2); // Set 68000 IPL 2...
881 // Check for CPU -> DSP interrupt
885 WriteLog("DSP: CPU -> DSP interrupt\n");
887 m68k_end_timeslice();
888 DSPReleaseTimeslice();
889 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
893 if (data & SINGLE_STEP)
895 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
898 // Protect writes to VERSION and the interrupt latches...
899 uint32_t mask = VERSION | INT_LAT0 | INT_LAT1 | INT_LAT2 | INT_LAT3 | INT_LAT4 | INT_LAT5;
900 dsp_control = (dsp_control & mask) | (data & ~mask);
904 ctrl1[8] = ctrl2[8] = dsp_control;
908 // if dsp wasn't running but is now running
909 // execute a few cycles
910 //This is just plain wrong, wrong, WRONG!
911 #ifndef DSP_SINGLE_STEPPING
912 /* if (!dsp_was_running && DSP_RUNNING)
917 //This is WRONG! !!! FIX !!!
918 if (dsp_control & 0x18)
923 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
925 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
928 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
929 // !!! FIX !!! [DONE]
933 m68k_end_timeslice();
935 DSPReleaseTimeslice();
939 //DSPDumpDisassembly();
944 WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
948 dsp_div_control = data;
950 // default: // unaligned long read
956 //We don't have to break this up like this! We CAN do 32 bit writes!
957 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
958 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
959 //if (offset > 0xF1FFFF)
961 JaguarWriteLong(offset, data, who);
965 // Update the DSP register file pointers depending on REGPAGE bit
967 void DSPUpdateRegisterBanks(void)
969 int bank = (dsp_flags & REGPAGE);
971 if (dsp_flags & IMASK)
972 bank = 0; // IMASK forces main bank to be bank 0
975 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
977 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
980 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
985 // Check for and handle any asserted DSP IRQs
987 void DSPHandleIRQs(void)
989 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
992 // Get the active interrupt bits (latches) & interrupt mask (enables)
993 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
994 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
996 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
999 if (!bits) // Bail if nothing is enabled
1002 int which = 0; // Determine which interrupt
1017 #ifdef DSP_DEBUG_IRQ
1018 WriteLog("DSP: Generating interrupt #%i...", which);
1021 //if (which == 0) doDSPDis = true;
1023 // NOTE: Since the actual Jaguar hardware injects the code sequence below
1024 // directly into the pipeline, it has the side effect of ensuring that the
1025 // instruction interrupted also gets to do its writeback. We simulate that
1027 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1029 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1030 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1032 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1033 scoreboard[pipeline[plPtrWrite].operand2] = false;
1035 //This should be execute (or should it?--not sure now!)
1036 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
1037 //and what just executed is now in the Write position...). So why didn't it do the
1038 //writeback into register 0?
1039 #ifdef DSP_DEBUG_IRQ
1040 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
1041 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]);
1042 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]);
1043 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]);
1045 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
1047 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
1049 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
1050 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
1053 if (pipeline[plPtrWrite].type == TYPE_BYTE)
1054 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1055 else if (pipeline[plPtrWrite].type == TYPE_WORD)
1056 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1058 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1062 #ifndef NEW_SCOREBOARD
1063 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1064 scoreboard[pipeline[plPtrWrite].operand2] = false;
1066 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1067 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1068 if (scoreboard[pipeline[plPtrWrite].operand2])
1069 scoreboard[pipeline[plPtrWrite].operand2]--;
1076 ctrl2[4] = dsp_flags;
1079 DSPUpdateRegisterBanks();
1080 #ifdef DSP_DEBUG_IRQ
1081 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1082 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]);
1085 // subqt #4,r31 ; pre-decrement stack pointer
1086 // move pc,r30 ; address of interrupted code
1087 // store r30,(r31) ; store return address
1094 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1095 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1096 //It missed the place that it was supposed to come back to, so this is WRONG!
1098 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1100 // R -> baz (<- PC points here)
1101 // E -> bar (when it should point here!)
1104 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1105 // which means (assuming they're all 2 bytes long) that the code below will come back on
1106 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1107 // instruction stream...
1109 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1110 DSPWriteLong(dsp_reg[31], dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)), DSP);
1113 SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1117 // movei #service_address,r30 ; pointer to ISR entry
1118 // jump (r30) ; jump to ISR
1120 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1123 ctrl2[0] = regs2[30] = dsp_pc;
1130 // Non-pipelined version...
1132 void DSPHandleIRQsNP(void)
1136 memcpy(dsp_ram_8, ram1, 0x2000);
1137 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1138 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1141 dsp_remain = ctrl1[2];
1142 dsp_modulo = ctrl1[3];
1143 dsp_flags = ctrl1[4];
1144 dsp_matrix_control = ctrl1[5];
1145 dsp_pointer_to_matrix = ctrl1[6];
1146 dsp_data_organization = ctrl1[7];
1147 dsp_control = ctrl1[8];
1148 dsp_div_control = ctrl1[9];
1149 IMASKCleared = ctrl1[10];
1150 dsp_flag_z = ctrl1[11];
1151 dsp_flag_n = ctrl1[12];
1152 dsp_flag_c = ctrl1[13];
1153 DSPUpdateRegisterBanks();
1156 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1159 // Get the active interrupt bits (latches) & interrupt mask (enables)
1160 uint32_t bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F),
1161 mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1163 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1166 if (!bits) // Bail if nothing is enabled
1169 int which = 0; // Determine which interrupt
1183 dsp_flags |= IMASK; // Force Bank #0
1186 ctrl1[4] = dsp_flags;
1189 #ifdef DSP_DEBUG_IRQ
1190 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1191 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1193 DSPUpdateRegisterBanks();
1194 #ifdef DSP_DEBUG_IRQ
1195 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]);
1196 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]);
1199 #ifdef DSP_DEBUG_IRQ
1200 WriteLog("DSP: Generating interrupt #%i...", which);
1201 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1204 // subqt #4,r31 ; pre-decrement stack pointer
1205 // move pc,r30 ; address of interrupted code
1206 // store r30,(r31) ; store return address
1208 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1215 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1216 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1219 SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1223 // movei #service_address,r30 ; pointer to ISR entry
1224 // jump (r30) ; jump to ISR
1226 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1229 ctrl1[0] = regs1[30] = dsp_pc;
1235 // Set the specified DSP IRQ line to a given state
1237 void DSPSetIRQLine(int irqline, int state)
1239 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1240 uint32_t mask = INT_LAT0 << irqline;
1241 dsp_control &= ~mask; // Clear the latch bit
1244 ctrl1[8] = ctrl2[8] = dsp_control;
1250 dsp_control |= mask; // Set the latch bit
1251 #warning !!! No checking done to see if we're using pipelined DSP or not !!!
1256 ctrl1[8] = ctrl2[8] = dsp_control;
1262 // Not sure if this is correct behavior, but according to JTRM,
1263 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1264 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1265 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1268 bool DSPIsRunning(void)
1270 return (DSP_RUNNING ? true : false);
1275 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1276 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1277 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1279 dsp_build_branch_condition_table();
1285 dsp_pc = 0x00F1B000;
1286 dsp_acc = 0x00000000;
1287 dsp_remain = 0x00000000;
1288 dsp_modulo = 0xFFFFFFFF;
1289 dsp_flags = 0x00040000;
1290 dsp_matrix_control = 0x00000000;
1291 dsp_pointer_to_matrix = 0x00000000;
1292 dsp_data_organization = 0xFFFFFFFF;
1293 dsp_control = 0x00002000; // Report DSP version 2
1294 dsp_div_control = 0x00000000;
1297 dsp_reg = dsp_reg_bank_0;
1298 dsp_alternate_reg = dsp_reg_bank_1;
1300 for(int i=0; i<32; i++)
1301 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1304 IMASKCleared = false;
1308 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1309 for(uint32_t i=0; i<8192; i+=4)
1310 *((uint32_t *)(&dsp_ram_8[i])) = rand();
1313 void DSPDumpDisassembly(void)
1317 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1318 uint32_t j = 0xF1B000;
1320 while (j <= 0xF1CFFF)
1323 j += dasmjag(JAGUAR_DSP, buffer, j);
1324 WriteLog("\t%08X: %s\n", oldj, buffer);
1328 void DSPDumpRegisters(void)
1330 //Shoud add modulus, etc to dump here...
1331 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
1332 WriteLog("\nRegisters bank 0\n");
1334 for(int j=0; j<8; j++)
1336 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1337 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1338 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1339 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1340 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1343 WriteLog("Registers bank 1\n");
1345 for(int j=0; j<8; j++)
1347 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1348 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1349 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1350 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1351 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1358 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
1359 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
1361 // get the active interrupt bits
1362 int bits = ((dsp_control >> 10) & 0x20) | ((dsp_control >> 6) & 0x1F);
1363 // get the interrupt mask
1364 int mask = ((dsp_flags >> 11) & 0x20) | ((dsp_flags >> 4) & 0x1F);
1366 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits, mask,
1367 (mask & 0x01 ? "CPU " : ""), (mask & 0x02 ? "I2S " : ""),
1368 (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
1369 (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
1370 WriteLog("\nRegisters bank 0\n");
1372 for(int j=0; j<8; j++)
1374 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1375 (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0],
1376 (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1],
1377 (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
1378 (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
1381 WriteLog("\nRegisters bank 1\n");
1385 WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
1386 (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0],
1387 (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
1388 (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
1389 (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
1394 static char buffer[512];
1395 j = DSP_WORK_RAM_BASE;
1397 while (j <= 0xF1CFFF)
1400 j += dasmjag(JAGUAR_DSP, buffer, j);
1401 WriteLog("\t%08X: %s\n", oldj, buffer);
1404 WriteLog("DSP opcodes use:\n");
1408 if (dsp_opcode_use[i])
1409 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1416 // DSP comparison core...
1419 static uint16_t lastExec;
1420 void DSPExecComp(int32_t cycles)
1422 while (cycles > 0 && DSP_RUNNING)
1424 // Load up vars for non-pipelined core
1425 memcpy(dsp_ram_8, ram1, 0x2000);
1426 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1427 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1430 dsp_remain = ctrl1[2];
1431 dsp_modulo = ctrl1[3];
1432 dsp_flags = ctrl1[4];
1433 dsp_matrix_control = ctrl1[5];
1434 dsp_pointer_to_matrix = ctrl1[6];
1435 dsp_data_organization = ctrl1[7];
1436 dsp_control = ctrl1[8];
1437 dsp_div_control = ctrl1[9];
1438 IMASKCleared = ctrl1[10];
1439 dsp_flag_z = ctrl1[11];
1440 dsp_flag_n = ctrl1[12];
1441 dsp_flag_c = ctrl1[13];
1442 DSPUpdateRegisterBanks();
1444 // Decrement cycles based on non-pipelined core...
1445 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1446 cycles -= dsp_opcode_cycles[instr1 >> 10];
1448 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1449 DSPExec(1); // Do *one* instruction
1452 memcpy(ram1, dsp_ram_8, 0x2000);
1453 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1454 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1457 ctrl1[2] = dsp_remain;
1458 ctrl1[3] = dsp_modulo;
1459 ctrl1[4] = dsp_flags;
1460 ctrl1[5] = dsp_matrix_control;
1461 ctrl1[6] = dsp_pointer_to_matrix;
1462 ctrl1[7] = dsp_data_organization;
1463 ctrl1[8] = dsp_control;
1464 ctrl1[9] = dsp_div_control;
1465 ctrl1[10] = IMASKCleared;
1466 ctrl1[11] = dsp_flag_z;
1467 ctrl1[12] = dsp_flag_n;
1468 ctrl1[13] = dsp_flag_c;
1470 // Load up vars for pipelined core
1471 memcpy(dsp_ram_8, ram2, 0x2000);
1472 memcpy(dsp_reg_bank_0, regs2, 32 * 4);
1473 memcpy(dsp_reg_bank_1, ®s2[32], 32 * 4);
1476 dsp_remain = ctrl2[2];
1477 dsp_modulo = ctrl2[3];
1478 dsp_flags = ctrl2[4];
1479 dsp_matrix_control = ctrl2[5];
1480 dsp_pointer_to_matrix = ctrl2[6];
1481 dsp_data_organization = ctrl2[7];
1482 dsp_control = ctrl2[8];
1483 dsp_div_control = ctrl2[9];
1484 IMASKCleared = ctrl2[10];
1485 dsp_flag_z = ctrl2[11];
1486 dsp_flag_n = ctrl2[12];
1487 dsp_flag_c = ctrl2[13];
1488 DSPUpdateRegisterBanks();
1490 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1491 DSPExecP2(1); // Do *one* instruction
1494 memcpy(ram2, dsp_ram_8, 0x2000);
1495 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1496 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1499 ctrl2[2] = dsp_remain;
1500 ctrl2[3] = dsp_modulo;
1501 ctrl2[4] = dsp_flags;
1502 ctrl2[5] = dsp_matrix_control;
1503 ctrl2[6] = dsp_pointer_to_matrix;
1504 ctrl2[7] = dsp_data_organization;
1505 ctrl2[8] = dsp_control;
1506 ctrl2[9] = dsp_div_control;
1507 ctrl2[10] = IMASKCleared;
1508 ctrl2[11] = dsp_flag_z;
1509 ctrl2[12] = dsp_flag_n;
1510 ctrl2[13] = dsp_flag_c;
1512 if (instr1 != lastExec)
1514 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1516 // 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));
1517 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1518 // if (ctrl1[0] < ppc) // P ran ahead of NP
1519 //How to test this crap???
1522 DSPExecP2(1); // Do one more instruction
1525 memcpy(ram2, dsp_ram_8, 0x2000);
1526 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1527 memcpy(®s2[32], dsp_reg_bank_1, 32 * 4);
1530 ctrl2[2] = dsp_remain;
1531 ctrl2[3] = dsp_modulo;
1532 ctrl2[4] = dsp_flags;
1533 ctrl2[5] = dsp_matrix_control;
1534 ctrl2[6] = dsp_pointer_to_matrix;
1535 ctrl2[7] = dsp_data_organization;
1536 ctrl2[8] = dsp_control;
1537 ctrl2[9] = dsp_div_control;
1538 ctrl2[10] = IMASKCleared;
1539 ctrl2[11] = dsp_flag_z;
1540 ctrl2[12] = dsp_flag_n;
1541 ctrl2[13] = dsp_flag_c;
1543 // else // NP ran ahead of P
1544 if (instr1 != lastExec) // Must be the other way...
1547 // Load up vars for non-pipelined core
1548 memcpy(dsp_ram_8, ram1, 0x2000);
1549 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1550 memcpy(dsp_reg_bank_1, ®s1[32], 32 * 4);
1553 dsp_remain = ctrl1[2];
1554 dsp_modulo = ctrl1[3];
1555 dsp_flags = ctrl1[4];
1556 dsp_matrix_control = ctrl1[5];
1557 dsp_pointer_to_matrix = ctrl1[6];
1558 dsp_data_organization = ctrl1[7];
1559 dsp_control = ctrl1[8];
1560 dsp_div_control = ctrl1[9];
1561 IMASKCleared = ctrl1[10];
1562 dsp_flag_z = ctrl1[11];
1563 dsp_flag_n = ctrl1[12];
1564 dsp_flag_c = ctrl1[13];
1565 DSPUpdateRegisterBanks();
1567 for(int k=0; k<2; k++)
1569 // Decrement cycles based on non-pipelined core...
1570 instr1 = DSPReadWord(dsp_pc, DSP);
1571 cycles -= dsp_opcode_cycles[instr1 >> 10];
1573 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1574 DSPExec(1); // Do *one* instruction
1578 memcpy(ram1, dsp_ram_8, 0x2000);
1579 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1580 memcpy(®s1[32], dsp_reg_bank_1, 32 * 4);
1583 ctrl1[2] = dsp_remain;
1584 ctrl1[3] = dsp_modulo;
1585 ctrl1[4] = dsp_flags;
1586 ctrl1[5] = dsp_matrix_control;
1587 ctrl1[6] = dsp_pointer_to_matrix;
1588 ctrl1[7] = dsp_data_organization;
1589 ctrl1[8] = dsp_control;
1590 ctrl1[9] = dsp_div_control;
1591 ctrl1[10] = IMASKCleared;
1592 ctrl1[11] = dsp_flag_z;
1593 ctrl1[12] = dsp_flag_n;
1594 ctrl1[13] = dsp_flag_c;
1598 if (instr1 != lastExec)
1600 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1602 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1603 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1616 // DSP execution core
1618 //static bool R20Set = false, tripwire = false;
1619 //static uint32_t pcQueue[32], ptrPCQ = 0;
1620 void DSPExec(int32_t cycles)
1622 #ifdef DSP_SINGLE_STEPPING
1623 if (dsp_control & 0x18)
1626 dsp_control &= ~0x10;
1629 //There is *no* good reason to do this here!
1631 dsp_releaseTimeSlice_flag = 0;
1634 while (cycles > 0 && DSP_RUNNING)
1636 /*extern uint32_t totalFrames;
1637 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1638 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1639 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1641 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1644 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1646 if (dsp_pc == 0xF1B092)
1647 doDSPDis = false;//*/
1648 /*if (dsp_pc == 0xF1B140)
1649 doDSPDis = true;//*/
1651 if (IMASKCleared) // If IMASK was cleared,
1653 #ifdef DSP_DEBUG_IRQ
1654 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1656 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1657 IMASKCleared = false;
1662 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1663 for(int i=0; i<80; i+=4)
1664 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1667 /*if (dsp_pc == 0xF1B55E)
1669 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1671 /*if (dsp_pc == 0xF1B7D2) // Start here???
1673 pcQueue[ptrPCQ++] = dsp_pc;
1675 uint16_t opcode = DSPReadWord(dsp_pc, DSP);
1676 uint32_t index = opcode >> 10;
1677 dsp_opcode_first_parameter = (opcode >> 5) & 0x1F;
1678 dsp_opcode_second_parameter = opcode & 0x1F;
1680 dsp_opcode[index]();
1681 dsp_opcode_use[index]++;
1682 cycles -= dsp_opcode_cycles[index];
1683 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1685 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1688 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1690 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1692 DSPDumpDisassembly();
1695 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1698 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1701 WriteLog("\nBacktrace:\n");
1702 for(int i=0; i<32; i++)
1704 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1705 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1715 // DSP opcode handlers
1718 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1719 // can cause trouble because an interrupt can occur *before* the instruction following the
1720 // jump can execute... !!! FIX !!!
1721 static void dsp_opcode_jump(void)
1724 const char * condition[32] =
1725 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1726 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1727 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1728 "???", "???", "???", "F" };
1730 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);
1733 /* dsp_flag_c=dsp_flag_c?1:0;
1734 dsp_flag_z=dsp_flag_z?1:0;
1735 dsp_flag_n=dsp_flag_n?1:0;*/
1736 // KLUDGE: Used by BRANCH_CONDITION
1737 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1739 if (BRANCH_CONDITION(IMM_2))
1743 WriteLog("Branched!\n");
1745 uint32_t delayed_pc = RM;
1747 dsp_pc = delayed_pc;
1752 WriteLog("Branch NOT taken.\n");
1756 static void dsp_opcode_jr(void)
1759 const char * condition[32] =
1760 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1761 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1762 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1763 "???", "???", "???", "F" };
1765 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);
1768 /* dsp_flag_c=dsp_flag_c?1:0;
1769 dsp_flag_z=dsp_flag_z?1:0;
1770 dsp_flag_n=dsp_flag_n?1:0;*/
1771 // KLUDGE: Used by BRANCH_CONDITION
1772 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
1774 if (BRANCH_CONDITION(IMM_2))
1778 WriteLog("Branched!\n");
1780 int32_t offset = (IMM_1 & 0x10 ? 0xFFFFFFF0 | IMM_1 : IMM_1); // Sign extend IMM_1
1781 int32_t delayed_pc = dsp_pc + (offset * 2);
1783 dsp_pc = delayed_pc;
1788 WriteLog("Branch NOT taken.\n");
1792 static void dsp_opcode_add(void)
1796 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);
1798 uint32_t res = RN + RM;
1799 SET_ZNC_ADD(RN, RM, res);
1803 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_addc(void)
1811 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);
1813 uint32_t res = RN + RM + dsp_flag_c;
1814 uint32_t carry = dsp_flag_c;
1815 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1816 SET_ZNC_ADD(RN + carry, RM, res);
1817 // SET_ZNC_ADD(RN, RM + carry, res);
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);
1825 static void dsp_opcode_addq(void)
1829 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);
1831 uint32_t r1 = dsp_convert_zero[IMM_1];
1832 uint32_t res = RN + r1;
1833 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1837 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1841 static void dsp_opcode_sub(void)
1845 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);
1847 uint32_t res = RN - RM;
1848 SET_ZNC_SUB(RN, RM, res);
1852 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);
1856 static void dsp_opcode_subc(void)
1860 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);
1862 uint32_t res = RN - RM - dsp_flag_c;
1863 uint32_t borrow = dsp_flag_c;
1864 SET_ZNC_SUB(RN - borrow, RM, res);
1868 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);
1872 static void dsp_opcode_subq(void)
1876 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);
1878 uint32_t r1 = dsp_convert_zero[IMM_1];
1879 uint32_t res = RN - r1;
1880 SET_ZNC_SUB(RN, r1, res);
1884 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1888 static void dsp_opcode_cmp(void)
1892 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);
1894 uint32_t res = RN - RM;
1895 SET_ZNC_SUB(RN, RM, res);
1898 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1902 static void dsp_opcode_cmpq(void)
1904 static int32_t sqtable[32] =
1905 { 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 };
1908 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);
1910 uint32_t r1 = sqtable[IMM_1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1911 uint32_t res = RN - r1;
1912 SET_ZNC_SUB(RN, r1, res);
1915 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1919 static void dsp_opcode_and(void)
1923 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);
1929 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);
1933 static void dsp_opcode_or(void)
1937 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);
1943 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);
1947 static void dsp_opcode_xor(void)
1951 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);
1957 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);
1961 static void dsp_opcode_not(void)
1965 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);
1971 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1975 static void dsp_opcode_move_pc(void)
1980 static void dsp_opcode_store_r14_indexed(void)
1982 #ifdef DSP_DIS_STORE14I
1984 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));
1986 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1987 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1989 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1993 static void dsp_opcode_store_r15_indexed(void)
1995 #ifdef DSP_DIS_STORE15I
1997 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));
1999 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2000 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2002 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
2006 static void dsp_opcode_load_r14_ri(void)
2008 #ifdef DSP_DIS_LOAD14R
2010 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);
2012 #ifdef DSP_CORRECT_ALIGNMENT
2013 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
2015 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
2017 #ifdef DSP_DIS_LOAD14R
2019 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2023 static void dsp_opcode_load_r15_ri(void)
2025 #ifdef DSP_DIS_LOAD15R
2027 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);
2029 #ifdef DSP_CORRECT_ALIGNMENT
2030 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
2032 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2034 #ifdef DSP_DIS_LOAD15R
2036 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2040 static void dsp_opcode_store_r14_ri(void)
2042 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2045 static void dsp_opcode_store_r15_ri(void)
2047 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2050 static void dsp_opcode_nop(void)
2054 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2058 static void dsp_opcode_storeb(void)
2060 #ifdef DSP_DIS_STOREB
2062 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);
2064 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2065 DSPWriteLong(RM, RN & 0xFF, DSP);
2067 JaguarWriteByte(RM, RN, DSP);
2070 static void dsp_opcode_storew(void)
2072 #ifdef DSP_DIS_STOREW
2074 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);
2076 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2077 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2078 DSPWriteLong(RM & 0xFFFFFFFE, RN & 0xFFFF, DSP);
2080 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2082 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2083 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2085 JaguarWriteWord(RM, RN, DSP);
2089 static void dsp_opcode_store(void)
2091 #ifdef DSP_DIS_STORE
2093 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);
2095 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2096 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2098 DSPWriteLong(RM, RN, DSP);
2102 static void dsp_opcode_loadb(void)
2104 #ifdef DSP_DIS_LOADB
2106 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);
2108 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2109 RN = DSPReadLong(RM, DSP) & 0xFF;
2111 RN = JaguarReadByte(RM, DSP);
2112 #ifdef DSP_DIS_LOADB
2114 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2118 static void dsp_opcode_loadw(void)
2120 #ifdef DSP_DIS_LOADW
2122 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);
2124 #ifdef DSP_CORRECT_ALIGNMENT
2125 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2126 RN = DSPReadLong(RM & 0xFFFFFFFE, DSP) & 0xFFFF;
2128 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2130 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2131 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2133 RN = JaguarReadWord(RM, DSP);
2135 #ifdef DSP_DIS_LOADW
2137 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2141 static void dsp_opcode_load(void)
2145 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);
2147 #ifdef DSP_CORRECT_ALIGNMENT
2148 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2150 RN = DSPReadLong(RM, DSP);
2154 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2158 static void dsp_opcode_load_r14_indexed(void)
2160 #ifdef DSP_DIS_LOAD14I
2162 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);
2164 #ifdef DSP_CORRECT_ALIGNMENT
2165 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2167 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2169 #ifdef DSP_DIS_LOAD14I
2171 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2175 static void dsp_opcode_load_r15_indexed(void)
2177 #ifdef DSP_DIS_LOAD15I
2179 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);
2181 #ifdef DSP_CORRECT_ALIGNMENT
2182 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2184 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2186 #ifdef DSP_DIS_LOAD15I
2188 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2192 static void dsp_opcode_movei(void)
2194 #ifdef DSP_DIS_MOVEI
2196 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);
2198 // This instruction is followed by 32-bit value in LSW / MSW format...
2199 RN = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
2201 #ifdef DSP_DIS_MOVEI
2203 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2207 static void dsp_opcode_moveta(void)
2209 #ifdef DSP_DIS_MOVETA
2211 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);
2214 #ifdef DSP_DIS_MOVETA
2216 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);
2220 static void dsp_opcode_movefa(void)
2222 #ifdef DSP_DIS_MOVEFA
2224 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);
2227 #ifdef DSP_DIS_MOVEFA
2229 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);
2233 static void dsp_opcode_move(void)
2237 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);
2242 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);
2246 static void dsp_opcode_moveq(void)
2248 #ifdef DSP_DIS_MOVEQ
2250 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);
2253 #ifdef DSP_DIS_MOVEQ
2255 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2259 static void dsp_opcode_resmac(void)
2261 #ifdef DSP_DIS_RESMAC
2263 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));
2265 RN = (uint32_t)dsp_acc;
2266 #ifdef DSP_DIS_RESMAC
2268 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2272 static void dsp_opcode_imult(void)
2274 #ifdef DSP_DIS_IMULT
2276 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);
2278 RN = (int16_t)RN * (int16_t)RM;
2280 #ifdef DSP_DIS_IMULT
2282 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);
2286 static void dsp_opcode_mult(void)
2290 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);
2292 RN = (uint16_t)RM * (uint16_t)RN;
2296 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);
2300 static void dsp_opcode_bclr(void)
2304 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);
2306 uint32_t res = RN & ~(1 << IMM_1);
2311 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_btst(void)
2319 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);
2321 dsp_flag_z = (~RN >> IMM_1) & 1;
2324 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2328 static void dsp_opcode_bset(void)
2332 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);
2334 uint32_t res = RN | (1 << IMM_1);
2339 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2343 static void dsp_opcode_subqt(void)
2345 #ifdef DSP_DIS_SUBQT
2347 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);
2349 RN -= dsp_convert_zero[IMM_1];
2350 #ifdef DSP_DIS_SUBQT
2352 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2356 static void dsp_opcode_addqt(void)
2358 #ifdef DSP_DIS_ADDQT
2360 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);
2362 RN += dsp_convert_zero[IMM_1];
2363 #ifdef DSP_DIS_ADDQT
2365 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2369 static void dsp_opcode_imacn(void)
2371 #ifdef DSP_DIS_IMACN
2373 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);
2375 int32_t res = (int16_t)RM * (int16_t)RN;
2376 dsp_acc += (int64_t)res;
2377 //Should we AND the result to fit into 40 bits here???
2378 #ifdef DSP_DIS_IMACN
2380 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));
2384 static void dsp_opcode_mtoi(void)
2386 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2390 static void dsp_opcode_normi(void)
2397 while ((_Rm & 0xffc00000) == 0)
2402 while ((_Rm & 0xff800000) != 0)
2412 static void dsp_opcode_mmult(void)
2414 int count = dsp_matrix_control&0x0f;
2415 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2419 if (!(dsp_matrix_control & 0x10))
2421 for (int i = 0; i < count; i++)
2425 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2427 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2428 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2435 for (int i = 0; i < count; i++)
2439 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2441 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2442 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2447 RN = res = (int32_t)accum;
2449 //NOTE: The flags are set based upon the last add/multiply done...
2453 static void dsp_opcode_abs(void)
2457 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);
2462 if (_Rn == 0x80000000)
2466 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2467 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2472 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2476 static void dsp_opcode_div(void)
2483 if (dsp_div_control & 1)
2485 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
2486 if (dsp_remain&0x80000000)
2488 RN = (((uint64_t)_Rn) << 16) / _Rm;
2492 dsp_remain = _Rn % _Rm;
2493 if (dsp_remain&0x80000000)
2502 static void dsp_opcode_imultn(void)
2504 #ifdef DSP_DIS_IMULTN
2506 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);
2508 // This is OK, since this multiply won't overflow 32 bits...
2509 int32_t res = (int32_t)((int16_t)RN * (int16_t)RM);
2510 dsp_acc = (int64_t)res;
2512 #ifdef DSP_DIS_IMULTN
2514 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));
2518 static void dsp_opcode_neg(void)
2522 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);
2525 SET_ZNC_SUB(0, RN, res);
2529 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2533 static void dsp_opcode_shlq(void)
2537 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);
2539 // NB: This instruction is the *only* one that does (32 - immediate data).
2540 int32_t r1 = 32 - IMM_1;
2541 uint32_t res = RN << r1;
2542 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2546 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2550 static void dsp_opcode_shrq(void)
2554 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);
2556 int32_t r1 = dsp_convert_zero[IMM_1];
2557 uint32_t res = RN >> r1;
2558 SET_ZN(res); dsp_flag_c = RN & 1;
2562 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2566 static void dsp_opcode_ror(void)
2570 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);
2572 uint32_t r1 = RM & 0x1F;
2573 uint32_t res = (RN >> r1) | (RN << (32 - r1));
2574 SET_ZN(res); dsp_flag_c = (RN >> 31) & 1;
2578 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);
2582 static void dsp_opcode_rorq(void)
2586 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);
2588 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2590 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2592 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2595 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2599 static void dsp_opcode_sha(void)
2601 int32_t sRm=(int32_t)RM;
2606 uint32_t shift=-sRm;
2607 if (shift>=32) shift=32;
2608 dsp_flag_c=(_Rn&0x80000000)>>31;
2618 if (shift>=32) shift=32;
2622 _Rn=((int32_t)_Rn)>>1;
2630 static void dsp_opcode_sharq(void)
2632 #ifdef DSP_DIS_SHARQ
2634 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);
2636 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2637 SET_ZN(res); dsp_flag_c = RN & 0x01;
2639 #ifdef DSP_DIS_SHARQ
2641 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2645 static void dsp_opcode_sh(void)
2647 int32_t sRm=(int32_t)RM;
2652 uint32_t shift=(-sRm);
2653 if (shift>=32) shift=32;
2654 dsp_flag_c=(_Rn&0x80000000)>>31;
2664 if (shift>=32) shift=32;
2676 void dsp_opcode_addqmod(void)
2678 #ifdef DSP_DIS_ADDQMOD
2680 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);
2682 uint32_t r1 = dsp_convert_zero[IMM_1];
2684 uint32_t res = r2 + r1;
2685 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2687 SET_ZNC_ADD(r2, r1, res);
2688 #ifdef DSP_DIS_ADDQMOD
2690 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2694 void dsp_opcode_subqmod(void)
2696 uint32_t r1 = dsp_convert_zero[IMM_1];
2698 uint32_t res = r2 - r1;
2699 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2702 SET_ZNC_SUB(r2, r1, res);
2705 void dsp_opcode_mirror(void)
2708 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2712 void dsp_opcode_sat32s(void)
2714 int32_t r2 = (uint32_t)RN;
2715 int32_t temp = dsp_acc >> 32;
2716 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
2721 void dsp_opcode_sat16s(void)
2724 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2729 void dsp_opcode_illegal(void)
2731 // Don't know what it does, but it does *something*...
2732 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);
2736 // New pipelined DSP core
2739 static void DSP_abs(void);
2740 static void DSP_add(void);
2741 static void DSP_addc(void);
2742 static void DSP_addq(void);
2743 static void DSP_addqmod(void);
2744 static void DSP_addqt(void);
2745 static void DSP_and(void);
2746 static void DSP_bclr(void);
2747 static void DSP_bset(void);
2748 static void DSP_btst(void);
2749 static void DSP_cmp(void);
2750 static void DSP_cmpq(void);
2751 static void DSP_div(void);
2752 static void DSP_imacn(void);
2753 static void DSP_imult(void);
2754 static void DSP_imultn(void);
2755 static void DSP_illegal(void);
2756 static void DSP_jr(void);
2757 static void DSP_jump(void);
2758 static void DSP_load(void);
2759 static void DSP_loadb(void);
2760 static void DSP_loadw(void);
2761 static void DSP_load_r14_i(void);
2762 static void DSP_load_r14_r(void);
2763 static void DSP_load_r15_i(void);
2764 static void DSP_load_r15_r(void);
2765 static void DSP_mirror(void);
2766 static void DSP_mmult(void);
2767 static void DSP_move(void);
2768 static void DSP_movefa(void);
2769 static void DSP_movei(void);
2770 static void DSP_movepc(void);
2771 static void DSP_moveq(void);
2772 static void DSP_moveta(void);
2773 static void DSP_mtoi(void);
2774 static void DSP_mult(void);
2775 static void DSP_neg(void);
2776 static void DSP_nop(void);
2777 static void DSP_normi(void);
2778 static void DSP_not(void);
2779 static void DSP_or(void);
2780 static void DSP_resmac(void);
2781 static void DSP_ror(void);
2782 static void DSP_rorq(void);
2783 static void DSP_sat16s(void);
2784 static void DSP_sat32s(void);
2785 static void DSP_sh(void);
2786 static void DSP_sha(void);
2787 static void DSP_sharq(void);
2788 static void DSP_shlq(void);
2789 static void DSP_shrq(void);
2790 static void DSP_store(void);
2791 static void DSP_storeb(void);
2792 static void DSP_storew(void);
2793 static void DSP_store_r14_i(void);
2794 static void DSP_store_r14_r(void);
2795 static void DSP_store_r15_i(void);
2796 static void DSP_store_r15_r(void);
2797 static void DSP_sub(void);
2798 static void DSP_subc(void);
2799 static void DSP_subq(void);
2800 static void DSP_subqmod(void);
2801 static void DSP_subqt(void);
2802 static void DSP_xor(void);
2804 void (* DSPOpcode[64])() =
2806 DSP_add, DSP_addc, DSP_addq, DSP_addqt,
2807 DSP_sub, DSP_subc, DSP_subq, DSP_subqt,
2808 DSP_neg, DSP_and, DSP_or, DSP_xor,
2809 DSP_not, DSP_btst, DSP_bset, DSP_bclr,
2811 DSP_mult, DSP_imult, DSP_imultn, DSP_resmac,
2812 DSP_imacn, DSP_div, DSP_abs, DSP_sh,
2813 DSP_shlq, DSP_shrq, DSP_sha, DSP_sharq,
2814 DSP_ror, DSP_rorq, DSP_cmp, DSP_cmpq,
2816 DSP_subqmod, DSP_sat16s, DSP_move, DSP_moveq,
2817 DSP_moveta, DSP_movefa, DSP_movei, DSP_loadb,
2818 DSP_loadw, DSP_load, DSP_sat32s, DSP_load_r14_i,
2819 DSP_load_r15_i, DSP_storeb, DSP_storew, DSP_store,
2821 DSP_mirror, DSP_store_r14_i, DSP_store_r15_i, DSP_movepc,
2822 DSP_jump, DSP_jr, DSP_mmult, DSP_mtoi,
2823 DSP_normi, DSP_nop, DSP_load_r14_r, DSP_load_r15_r,
2824 DSP_store_r14_r, DSP_store_r15_r, DSP_illegal, DSP_addqmod
2827 bool readAffected[64][2] =
2829 { true, true}, { true, true}, {false, true}, {false, true},
2830 { true, true}, { true, true}, {false, true}, {false, true},
2831 {false, true}, { true, true}, { true, true}, { true, true},
2832 {false, true}, {false, true}, {false, true}, {false, true},
2834 { true, true}, { true, true}, { true, true}, {false, true},
2835 { true, true}, { true, true}, {false, true}, { true, true},
2836 {false, true}, {false, true}, { true, true}, {false, true},
2837 { true, true}, {false, true}, { true, true}, {false, true},
2839 {false, true}, {false, true}, { true, false}, {false, false},
2840 { true, false}, {false, false}, {false, false}, { true, false},
2841 { true, false}, { true, false}, {false, true}, { true, false},
2842 { true, false}, { true, true}, { true, true}, { true, true},
2844 {false, true}, { true, true}, { true, true}, {false, true},
2845 { true, false}, { true, false}, { true, true}, { true, false},
2846 { true, false}, {false, false}, { true, false}, { true, false},
2847 { true, true}, { true, true}, {false, false}, {false, true}
2850 bool isLoadStore[65] =
2852 false, false, false, false, false, false, false, false,
2853 false, false, false, false, false, false, false, false,
2855 false, false, false, false, false, false, false, false,
2856 false, false, false, false, false, false, false, false,
2858 false, false, false, false, false, false, false, true,
2859 true, true, false, true, true, true, true, true,
2861 false, true, true, false, false, false, false, false,
2862 false, false, true, true, true, true, false, false, false
2865 void FlushDSPPipeline(void)
2867 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2869 for(int i=0; i<4; i++)
2870 pipeline[i].opcode = PIPELINE_STALL;
2872 for(int i=0; i<32; i++)
2877 // New pipelined DSP execution core
2879 /*void DSPExecP(int32_t cycles)
2881 // bool inhibitFetch = false;
2883 dsp_releaseTimeSlice_flag = 0;
2886 while (cycles > 0 && DSP_RUNNING)
2888 WriteLog("DSPExecP: Pipeline status...\n");
2889 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);
2890 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);
2891 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);
2892 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);
2893 WriteLog(" --> Scoreboard: ");
2894 for(int i=0; i<32; i++)
2895 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2897 // Stage 1: Instruction fetch
2898 // if (!inhibitFetch)
2900 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2901 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2902 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2903 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2904 if (pipeline[plPtrFetch].opcode == 38)
2905 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2906 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2909 // inhibitFetch = false;
2910 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2912 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2913 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);
2914 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);
2915 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);
2916 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);
2917 // Stage 2: Read registers
2918 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2919 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2920 if (scoreboard[pipeline[plPtrRead].operand2])
2921 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2922 // We have a hit in the scoreboard, so we have to stall the pipeline...
2924 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2925 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2926 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2927 pipeline[plPtrFetch] = pipeline[plPtrRead];
2928 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2932 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2933 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2934 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2936 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2937 // Shouldn't we be more selective with the register scoreboarding?
2938 // Yes, we should. !!! FIX !!!
2939 scoreboard[pipeline[plPtrRead].operand2] = true;
2940 //Advance PC here??? Yes.
2941 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2942 //This is a mangling of the pipeline stages, but what else to do???
2943 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2946 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2947 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);
2948 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);
2949 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);
2950 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);
2952 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2954 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2955 DSPOpcode[pipeline[plPtrExec].opcode]();
2956 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2957 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2962 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2963 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);
2964 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);
2965 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);
2966 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2967 // Stage 4: Write back register
2968 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
2970 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
2971 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
2973 scoreboard[pipeline[plPtrWrite].operand1]
2974 = scoreboard[pipeline[plPtrWrite].operand2] = false;
2977 // Push instructions through the pipeline...
2978 plPtrFetch = (++plPtrFetch) & 0x03;
2979 plPtrRead = (++plPtrRead) & 0x03;
2980 plPtrExec = (++plPtrExec) & 0x03;
2981 plPtrWrite = (++plPtrWrite) & 0x03;
2988 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
2990 // Should be fixed now. Another problem is figuring how to do the sequence following
2991 // a branch followed with the JR & JUMP instructions...
2993 // There are two conflicting problems:
2996 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
2997 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
2998 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
2999 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3000 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3001 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3002 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3003 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3004 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3005 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3006 DSP: Finished interrupt.
3007 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3008 ; bank 0 (where is was prepared)!
3009 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3010 F1B252: NOP [NCZ:001]
3013 // The other is when you see this at the end of an IRQ:
3016 JUMP T, (R29) ; R29 = Previous stack + 2
3017 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3019 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3020 ; 1) The STORE goes through the pipeline and is executed/written back
3021 ; 2) The pipeline is flushed
3022 ; 3) The DSP_PC is set to the new address
3023 ; 4) Execution resumes
3025 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3026 ; bank 0 instead of the current bank 1 and so goes astray!
3029 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3030 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3034 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3035 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3036 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3037 If it were done properly, the STORE write back would occur *after* (well, technically,
3038 during) the execution of the the JUMP that follows it.
3042 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3043 F1B08A: NOP [NCZ:001]
3045 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3048 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3051 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3052 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3053 F1B08A: NOP [NCZ:001]
3055 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3058 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3059 DSP: CPU -> DSP interrupt
3060 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3061 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3063 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3066 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3067 F1B006: NOP [NCZ:001]
3069 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3072 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3073 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3076 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3077 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3080 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3081 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3084 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3085 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3088 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3091 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3094 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3095 F1B0FE: NOP [NCZ:000]
3097 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3100 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3103 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3104 F1B138: NOP [NCZ:000]
3106 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3109 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3110 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3111 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3114 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3115 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3118 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3119 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3120 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3122 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3123 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3126 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3127 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3128 DSP: Finished interrupt.
3129 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3131 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3134 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3135 F1B016: NOP [NCZ:001]
3137 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3140 uint32_t pcQueue1[0x400];
3141 uint32_t pcQPtr1 = 0;
3142 static uint32_t prevR1;
3143 //Let's try a 3 stage pipeline....
3144 //Looks like 3 stage is correct, otherwise bad things happen...
3145 void DSPExecP2(int32_t cycles)
3147 dsp_releaseTimeSlice_flag = 0;
3150 while (cycles > 0 && DSP_RUNNING)
3152 /*extern uint32_t totalFrames;
3153 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3154 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3155 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3157 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3160 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3162 if (dsp_pc == 0xF1B092)
3163 doDSPDis = false;//*/
3164 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3165 doDSPDis = true;//*/
3166 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3167 doDSPDis = true;//*/
3168 /*if (dsp_pc == 0xF1B0A0)
3169 doDSPDis = true;//*/
3170 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3171 doDSPDis = true;//*/
3172 //Two parter... (not sure how to write this)
3173 //if (dsp_pc == 0xF1B0D2)
3174 // prevR1 = dsp_reg[1];
3176 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3177 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3180 pcQueue1[pcQPtr1++] = dsp_pc;
3183 #ifdef DSP_DEBUG_PL2
3184 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3186 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3191 for(int i=0; i<0x400; i++)
3193 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3194 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3200 if (IMASKCleared) // If IMASK was cleared,
3202 #ifdef DSP_DEBUG_IRQ
3203 WriteLog("DSP: Finished interrupt.\n");
3205 DSPHandleIRQs(); // See if any other interrupts are pending!
3206 IMASKCleared = false;
3209 //if (dsp_flags & REGPAGE)
3210 // WriteLog(" --> REGPAGE has just been set!\n");
3211 #ifdef DSP_DEBUG_PL2
3214 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3215 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]);
3216 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]);
3217 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]);
3218 WriteLog(" --> Scoreboard: ");
3219 for(int i=0; i<32; i++)
3220 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3224 // Stage 1a: Instruction fetch
3225 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3226 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3227 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3228 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3229 if (pipeline[plPtrRead].opcode == 38)
3230 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3231 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3232 #ifdef DSP_DEBUG_PL2
3235 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3236 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3237 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]);
3238 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]);
3239 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]);
3242 // Stage 1b: Read registers
3243 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3244 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3246 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3247 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3248 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3249 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1])
3250 || ((pipeline[plPtrRead].opcode == 43 || pipeline[plPtrRead].opcode == 58) && scoreboard[14])
3251 || ((pipeline[plPtrRead].opcode == 44 || pipeline[plPtrRead].opcode == 59) && scoreboard[15])
3252 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3254 || (isLoadStore[pipeline[plPtrRead].opcode] && isLoadStore[pipeline[plPtrExec].opcode]))
3255 // We have a hit in the scoreboard, so we have to stall the pipeline...
3256 #ifdef DSP_DEBUG_PL2
3260 WriteLog(" --> Stalling pipeline: ");
3261 if (readAffected[pipeline[plPtrRead].opcode][0])
3262 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3263 if (readAffected[pipeline[plPtrRead].opcode][1])
3264 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3268 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3269 #ifdef DSP_DEBUG_PL2
3274 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3275 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3276 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3278 // Shouldn't we be more selective with the register scoreboarding?
3279 // Yes, we should. !!! FIX !!! Kinda [DONE]
3280 #ifndef NEW_SCOREBOARD
3281 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3283 //Hopefully this will fix the dual MOVEQ # problem...
3284 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3287 //Advance PC here??? Yes.
3288 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3291 #ifdef DSP_DEBUG_PL2
3294 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3295 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]);
3296 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]);
3297 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]);
3301 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3303 #ifdef DSP_DEBUG_PL2
3305 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"));
3309 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3314 lastExec = pipeline[plPtrExec].instruction;
3315 //WriteLog("[lastExec = %04X]\n", lastExec);
3317 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3318 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3319 DSPOpcode[pipeline[plPtrExec].opcode]();
3320 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3324 //Let's not, until we do the stalling correctly...
3325 //But, we gotta while we're doing the comparison core...!
3326 //Or do we? cycles--;
3327 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3328 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3329 //to model this clock cycle behavior correctly...
3330 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3331 //don't affect the reads at stage 1...
3332 #ifdef DSP_DEBUG_STALL
3334 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3338 #ifdef DSP_DEBUG_PL2
3341 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3342 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]);
3343 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]);
3344 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]);
3348 // Stage 3: Write back register/memory address
3349 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3351 /*if (pipeline[plPtrWrite].writebackRegister == 3
3352 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3355 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3358 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3360 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3361 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3364 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3365 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3366 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3367 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3369 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3373 #ifndef NEW_SCOREBOARD
3374 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3375 scoreboard[pipeline[plPtrWrite].operand2] = false;
3377 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3378 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3379 if (scoreboard[pipeline[plPtrWrite].operand2])
3380 scoreboard[pipeline[plPtrWrite].operand2]--;
3384 // Push instructions through the pipeline...
3385 plPtrRead = (++plPtrRead) & 0x03;
3386 plPtrExec = (++plPtrExec) & 0x03;
3387 plPtrWrite = (++plPtrWrite) & 0x03;
3396 //#define DSP_DEBUG_PL3
3397 //Let's try a 2 stage pipeline....
3398 void DSPExecP3(int32_t cycles)
3400 dsp_releaseTimeSlice_flag = 0;
3403 while (cycles > 0 && DSP_RUNNING)
3405 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3407 #ifdef DSP_DEBUG_PL3
3408 WriteLog("DSPExecP: Pipeline status...\n");
3409 WriteLog("\tF/R -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrRead].opcode, pipeline[plPtrRead].operand1, pipeline[plPtrRead].operand2, pipeline[plPtrRead].reg1, pipeline[plPtrRead].reg2, pipeline[plPtrRead].result, pipeline[plPtrRead].writebackRegister, dsp_opcode_str[pipeline[plPtrRead].opcode]);
3410 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3411 WriteLog(" --> Scoreboard: ");
3412 for(int i=0; i<32; i++)
3413 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3416 // Stage 1a: Instruction fetch
3417 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3418 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3419 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3420 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3421 if (pipeline[plPtrRead].opcode == 38)
3422 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3423 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3424 #ifdef DSP_DEBUG_PL3
3425 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3426 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3427 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]);
3428 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]);
3430 // Stage 1b: Read registers
3431 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3432 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3433 // We have a hit in the scoreboard, so we have to stall the pipeline...
3434 #ifdef DSP_DEBUG_PL3
3436 WriteLog(" --> Stalling pipeline: ");
3437 if (readAffected[pipeline[plPtrRead].opcode][0])
3438 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3439 if (readAffected[pipeline[plPtrRead].opcode][1])
3440 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3443 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3444 #ifdef DSP_DEBUG_PL3
3449 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3450 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3451 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3453 // Shouldn't we be more selective with the register scoreboarding?
3454 // Yes, we should. !!! FIX !!! [Kinda DONE]
3455 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3457 //Advance PC here??? Yes.
3458 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3461 #ifdef DSP_DEBUG_PL3
3462 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3463 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]);
3464 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]);
3466 // Stage 2a: Execute
3467 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3469 #ifdef DSP_DEBUG_PL3
3470 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3472 DSPOpcode[pipeline[plPtrExec].opcode]();
3473 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3474 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3479 #ifdef DSP_DEBUG_PL3
3480 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3481 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]);
3482 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]);
3485 // Stage 2b: Write back register
3486 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3488 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3489 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3491 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3492 scoreboard[pipeline[plPtrExec].operand2] = false;
3495 // Push instructions through the pipeline...
3496 plPtrRead = (++plPtrRead) & 0x03;
3497 plPtrExec = (++plPtrExec) & 0x03;
3504 // DSP pipelined opcode handlers
3507 #define PRM pipeline[plPtrExec].reg1
3508 #define PRN pipeline[plPtrExec].reg2
3509 #define PIMM1 pipeline[plPtrExec].operand1
3510 #define PIMM2 pipeline[plPtrExec].operand2
3511 #define PRES pipeline[plPtrExec].result
3512 #define PWBR pipeline[plPtrExec].writebackRegister
3513 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3514 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3515 #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))
3516 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3518 static void DSP_abs(void)
3522 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);
3526 if (_Rn == 0x80000000)
3530 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3531 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3532 CLR_ZN; SET_Z(PRES);
3536 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3540 static void DSP_add(void)
3544 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);
3546 uint32_t res = PRN + PRM;
3547 SET_ZNC_ADD(PRN, PRM, res);
3551 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);
3555 static void DSP_addc(void)
3559 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);
3561 uint32_t res = PRN + PRM + dsp_flag_c;
3562 uint32_t carry = dsp_flag_c;
3563 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3564 SET_ZNC_ADD(PRN + carry, PRM, res);
3565 // SET_ZNC_ADD(PRN, PRM + carry, res);
3569 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);
3573 static void DSP_addq(void)
3577 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);
3579 uint32_t r1 = dsp_convert_zero[PIMM1];
3580 uint32_t res = PRN + r1;
3581 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3585 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3589 static void DSP_addqmod(void)
3591 #ifdef DSP_DIS_ADDQMOD
3593 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);
3595 uint32_t r1 = dsp_convert_zero[PIMM1];
3597 uint32_t res = r2 + r1;
3598 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3600 SET_ZNC_ADD(r2, r1, res);
3601 #ifdef DSP_DIS_ADDQMOD
3603 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3607 static void DSP_addqt(void)
3609 #ifdef DSP_DIS_ADDQT
3611 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);
3613 PRES = PRN + dsp_convert_zero[PIMM1];
3614 #ifdef DSP_DIS_ADDQT
3616 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3620 static void DSP_and(void)
3624 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);
3630 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);
3634 static void DSP_bclr(void)
3638 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);
3640 PRES = PRN & ~(1 << PIMM1);
3644 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3648 static void DSP_bset(void)
3652 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);
3654 PRES = PRN | (1 << PIMM1);
3658 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3662 static void DSP_btst(void)
3666 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);
3668 dsp_flag_z = (~PRN >> PIMM1) & 1;
3672 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3676 static void DSP_cmp(void)
3680 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);
3682 uint32_t res = PRN - PRM;
3683 SET_ZNC_SUB(PRN, PRM, res);
3687 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3691 static void DSP_cmpq(void)
3693 static int32_t sqtable[32] =
3694 { 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 };
3697 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);
3699 uint32_t r1 = sqtable[PIMM1 & 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3700 uint32_t res = PRN - r1;
3701 SET_ZNC_SUB(PRN, r1, res);
3705 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3709 static void DSP_div(void)
3711 uint32_t _Rm = PRM, _Rn = PRN;
3715 if (dsp_div_control & 1)
3717 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3718 if (dsp_remain & 0x80000000)
3720 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3724 dsp_remain = _Rn % _Rm;
3725 if (dsp_remain & 0x80000000)
3734 static void DSP_imacn(void)
3736 #ifdef DSP_DIS_IMACN
3738 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);
3740 int32_t res = (int16_t)PRM * (int16_t)PRN;
3741 dsp_acc += (int64_t)res;
3742 //Should we AND the result to fit into 40 bits here???
3744 #ifdef DSP_DIS_IMACN
3746 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));
3750 static void DSP_imult(void)
3752 #ifdef DSP_DIS_IMULT
3754 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);
3756 PRES = (int16_t)PRN * (int16_t)PRM;
3758 #ifdef DSP_DIS_IMULT
3760 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);
3764 static void DSP_imultn(void)
3766 #ifdef DSP_DIS_IMULTN
3768 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);
3770 // This is OK, since this multiply won't overflow 32 bits...
3771 int32_t res = (int32_t)((int16_t)PRN * (int16_t)PRM);
3772 dsp_acc = (int64_t)res;
3775 #ifdef DSP_DIS_IMULTN
3777 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));
3781 static void DSP_illegal(void)
3783 #ifdef DSP_DIS_ILLEGAL
3785 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3790 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3791 // can cause trouble because an interrupt can occur *before* the instruction following the
3792 // jump can execute... !!! FIX !!!
3793 // This can probably be solved by judicious coding in the pipeline execution core...
3794 // And should be fixed now...
3795 static void DSP_jr(void)
3798 const char * condition[32] =
3799 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3800 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3801 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3802 "???", "???", "???", "F" };
3804 //How come this is always off by 2???
3805 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);
3807 // KLUDGE: Used by BRANCH_CONDITION macro
3808 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3810 if (BRANCH_CONDITION(PIMM2))
3814 WriteLog("Branched!\n");
3816 int32_t offset = (PIMM1 & 0x10 ? 0xFFFFFFF0 | PIMM1 : PIMM1); // Sign extend PIMM1
3817 //Account for pipeline effects...
3818 uint32_t newPC = dsp_pc + (offset * 2) - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
3819 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3821 // Now that we've branched, we have to make sure that the following instruction
3822 // is executed atomically with this one and then flush the pipeline before setting
3825 // Step 1: Handle writebacks at stage 3 of pipeline
3826 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3828 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3829 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3831 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3832 scoreboard[pipeline[plPtrWrite].operand2] = false;
3834 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3836 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3838 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3839 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3842 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3843 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3844 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3845 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3847 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3851 #ifndef NEW_SCOREBOARD
3852 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3853 scoreboard[pipeline[plPtrWrite].operand2] = false;
3855 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3856 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3857 if (scoreboard[pipeline[plPtrWrite].operand2])
3858 scoreboard[pipeline[plPtrWrite].operand2]--;
3862 // Step 2: Push instruction through pipeline & execute following instruction
3863 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3864 // we effectively handle the final push of the instruction through the
3865 // pipeline when the new PC takes effect (since when we return, the
3866 // pipeline code will be executing the writeback stage. If we reverse
3867 // the execution order of the pipeline stages, this will no longer be
3869 pipeline[plPtrExec] = pipeline[plPtrRead];
3870 //This is BAD. We need to get that next opcode and execute it!
3871 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3872 // remove this crap.
3873 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3875 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3876 pipeline[plPtrExec].opcode = instruction >> 10;
3877 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3878 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3879 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3880 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3881 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3883 dsp_pc += 2; // For DSP_DIS_* accuracy
3884 DSPOpcode[pipeline[plPtrExec].opcode]();
3885 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3886 pipeline[plPtrWrite] = pipeline[plPtrExec];
3888 // Step 3: Flush pipeline & set new PC
3889 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3896 WriteLog("Branch NOT taken.\n");
3902 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3905 static void DSP_jump(void)
3908 const char * condition[32] =
3909 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3910 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3911 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3912 "???", "???", "???", "F" };
3914 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);
3916 // KLUDGE: Used by BRANCH_CONDITION macro
3917 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3919 if (BRANCH_CONDITION(PIMM2))
3923 WriteLog("Branched!\n");
3925 uint32_t PCSave = PRM;
3926 // Now that we've branched, we have to make sure that the following instruction
3927 // is executed atomically with this one and then flush the pipeline before setting
3930 // Step 1: Handle writebacks at stage 3 of pipeline
3931 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3933 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3934 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3936 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3937 scoreboard[pipeline[plPtrWrite].operand2] = false;
3939 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3941 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3943 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3944 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3947 if (pipeline[plPtrWrite].type == TYPE_BYTE)
3948 JaguarWriteByte(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3949 else if (pipeline[plPtrWrite].type == TYPE_WORD)
3950 JaguarWriteWord(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3952 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3956 #ifndef NEW_SCOREBOARD
3957 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3958 scoreboard[pipeline[plPtrWrite].operand2] = false;
3960 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3961 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3962 if (scoreboard[pipeline[plPtrWrite].operand2])
3963 scoreboard[pipeline[plPtrWrite].operand2]--;
3967 // Step 2: Push instruction through pipeline & execute following instruction
3968 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3969 // we effectively handle the final push of the instruction through the
3970 // pipeline when the new PC takes effect (since when we return, the
3971 // pipeline code will be executing the writeback stage. If we reverse
3972 // the execution order of the pipeline stages, this will no longer be
3974 pipeline[plPtrExec] = pipeline[plPtrRead];
3975 //This is BAD. We need to get that next opcode and execute it!
3976 //Also, same problem in JR!
3977 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3978 // remove this crap.
3979 if (pipeline[plPtrExec].opcode == PIPELINE_STALL)
3981 uint16_t instruction = DSPReadWord(dsp_pc, DSP);
3982 pipeline[plPtrExec].opcode = instruction >> 10;
3983 pipeline[plPtrExec].operand1 = (instruction >> 5) & 0x1F;
3984 pipeline[plPtrExec].operand2 = instruction & 0x1F;
3985 pipeline[plPtrExec].reg1 = dsp_reg[pipeline[plPtrExec].operand1];
3986 pipeline[plPtrExec].reg2 = dsp_reg[pipeline[plPtrExec].operand2];
3987 pipeline[plPtrExec].writebackRegister = pipeline[plPtrExec].operand2; // Set it to RN
3989 dsp_pc += 2; // For DSP_DIS_* accuracy
3990 DSPOpcode[pipeline[plPtrExec].opcode]();
3991 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3992 pipeline[plPtrWrite] = pipeline[plPtrExec];
3994 // Step 3: Flush pipeline & set new PC
3995 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4002 WriteLog("Branch NOT taken.\n");
4010 static void DSP_load(void)
4014 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);
4016 #ifdef DSP_CORRECT_ALIGNMENT
4017 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4019 PRES = DSPReadLong(PRM, DSP);
4023 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4027 static void DSP_loadb(void)
4029 #ifdef DSP_DIS_LOADB
4031 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);
4033 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4034 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4036 PRES = JaguarReadByte(PRM, DSP);
4037 #ifdef DSP_DIS_LOADB
4039 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4043 static void DSP_loadw(void)
4045 #ifdef DSP_DIS_LOADW
4047 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);
4049 #ifdef DSP_CORRECT_ALIGNMENT
4050 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4051 PRES = DSPReadLong(PRM & 0xFFFFFFFE, DSP) & 0xFFFF;
4053 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4055 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4056 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4058 PRES = JaguarReadWord(PRM, DSP);
4060 #ifdef DSP_DIS_LOADW
4062 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4066 static void DSP_load_r14_i(void)
4068 #ifdef DSP_DIS_LOAD14I
4070 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);
4072 #ifdef DSP_CORRECT_ALIGNMENT
4073 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4075 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4077 #ifdef DSP_DIS_LOAD14I
4079 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4083 static void DSP_load_r14_r(void)
4085 #ifdef DSP_DIS_LOAD14R
4087 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);
4089 #ifdef DSP_CORRECT_ALIGNMENT
4090 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4092 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4094 #ifdef DSP_DIS_LOAD14R
4096 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4100 static void DSP_load_r15_i(void)
4102 #ifdef DSP_DIS_LOAD15I
4104 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);
4106 #ifdef DSP_CORRECT_ALIGNMENT
4107 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4109 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4111 #ifdef DSP_DIS_LOAD15I
4113 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4117 static void DSP_load_r15_r(void)
4119 #ifdef DSP_DIS_LOAD15R
4121 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);
4123 #ifdef DSP_CORRECT_ALIGNMENT
4124 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4126 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4128 #ifdef DSP_DIS_LOAD15R
4130 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4134 static void DSP_mirror(void)
4137 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4141 static void DSP_mmult(void)
4143 int count = dsp_matrix_control&0x0f;
4144 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4148 if (!(dsp_matrix_control & 0x10))
4150 for (int i = 0; i < count; i++)
4154 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4156 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4157 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4164 for (int i = 0; i < count; i++)
4168 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4170 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4171 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4177 PRES = res = (int32_t)accum;
4179 //NOTE: The flags are set based upon the last add/multiply done...
4183 static void DSP_move(void)
4187 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);
4192 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);
4196 static void DSP_movefa(void)
4198 #ifdef DSP_DIS_MOVEFA
4200 // 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);
4201 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);
4203 // PRES = ALTERNATE_RM;
4204 PRES = dsp_alternate_reg[PIMM1];
4205 #ifdef DSP_DIS_MOVEFA
4207 // 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);
4208 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);
4212 static void DSP_movei(void)
4214 #ifdef DSP_DIS_MOVEI
4216 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);
4218 // // This instruction is followed by 32-bit value in LSW / MSW format...
4219 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4221 #ifdef DSP_DIS_MOVEI
4223 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4227 static void DSP_movepc(void)
4229 #ifdef DSP_DIS_MOVEPC
4231 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);
4233 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4234 // PRES = dsp_pc - 2;
4235 //Account for pipeline effects...
4236 PRES = dsp_pc - 2 - (pipeline[plPtrRead].opcode == 38 ? 6 : (pipeline[plPtrRead].opcode == PIPELINE_STALL ? 0 : 2));
4237 #ifdef DSP_DIS_MOVEPC
4239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4243 static void DSP_moveq(void)
4245 #ifdef DSP_DIS_MOVEQ
4247 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);
4250 #ifdef DSP_DIS_MOVEQ
4252 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4256 static void DSP_moveta(void)
4258 #ifdef DSP_DIS_MOVETA
4260 // 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);
4261 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]);
4263 // ALTERNATE_RN = PRM;
4264 dsp_alternate_reg[PIMM2] = PRM;
4266 #ifdef DSP_DIS_MOVETA
4268 // 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);
4269 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]);
4273 static void DSP_mtoi(void)
4275 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4279 static void DSP_mult(void)
4283 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);
4285 PRES = (uint16_t)PRM * (uint16_t)PRN;
4289 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);
4293 static void DSP_neg(void)
4297 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);
4299 uint32_t res = -PRN;
4300 SET_ZNC_SUB(0, PRN, res);
4304 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4308 static void DSP_nop(void)
4312 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4317 static void DSP_normi(void)
4324 while ((_Rm & 0xffc00000) == 0)
4329 while ((_Rm & 0xff800000) != 0)
4339 static void DSP_not(void)
4343 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);
4349 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4353 static void DSP_or(void)
4357 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);
4363 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);
4367 static void DSP_resmac(void)
4369 #ifdef DSP_DIS_RESMAC
4371 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));
4373 PRES = (uint32_t)dsp_acc;
4374 #ifdef DSP_DIS_RESMAC
4376 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4380 static void DSP_ror(void)
4384 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);
4386 uint32_t r1 = PRM & 0x1F;
4387 uint32_t res = (PRN >> r1) | (PRN << (32 - r1));
4388 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4392 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);
4396 static void DSP_rorq(void)
4400 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);
4402 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4404 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4406 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4409 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4413 static void DSP_sat16s(void)
4416 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4421 static void DSP_sat32s(void)
4423 int32_t r2 = (uint32_t)PRN;
4424 int32_t temp = dsp_acc >> 32;
4425 uint32_t res = (temp < -1) ? (int32_t)0x80000000 : (temp > 0) ? (int32_t)0x7FFFFFFF : r2;
4430 static void DSP_sh(void)
4432 int32_t sRm = (int32_t)PRM;
4437 uint32_t shift = -sRm;
4442 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4452 uint32_t shift = sRm;
4457 dsp_flag_c = _Rn & 0x1;
4470 static void DSP_sha(void)
4472 int32_t sRm = (int32_t)PRM;
4477 uint32_t shift = -sRm;
4482 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4492 uint32_t shift = sRm;
4497 dsp_flag_c = _Rn & 0x1;
4501 _Rn = ((int32_t)_Rn) >> 1;
4510 static void DSP_sharq(void)
4512 #ifdef DSP_DIS_SHARQ
4514 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);
4516 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4517 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4519 #ifdef DSP_DIS_SHARQ
4521 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4525 static void DSP_shlq(void)
4529 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);
4531 int32_t r1 = 32 - PIMM1;
4532 uint32_t res = PRN << r1;
4533 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4537 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4541 static void DSP_shrq(void)
4545 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);
4547 int32_t r1 = dsp_convert_zero[PIMM1];
4548 uint32_t res = PRN >> r1;
4549 SET_ZN(res); dsp_flag_c = PRN & 1;
4553 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4557 static void DSP_store(void)
4559 #ifdef DSP_DIS_STORE
4561 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);
4563 // DSPWriteLong(PRM, PRN, DSP);
4565 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4566 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4568 pipeline[plPtrExec].address = PRM;
4570 pipeline[plPtrExec].value = PRN;
4571 pipeline[plPtrExec].type = TYPE_DWORD;
4575 static void DSP_storeb(void)
4577 #ifdef DSP_DIS_STOREB
4579 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);
4581 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4582 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4584 // JaguarWriteByte(PRM, PRN, DSP);
4587 pipeline[plPtrExec].address = PRM;
4589 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4591 pipeline[plPtrExec].value = PRN & 0xFF;
4592 pipeline[plPtrExec].type = TYPE_DWORD;
4596 pipeline[plPtrExec].value = PRN;
4597 pipeline[plPtrExec].type = TYPE_BYTE;
4603 static void DSP_storew(void)
4605 #ifdef DSP_DIS_STOREW
4607 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);
4609 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4610 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4612 // JaguarWriteWord(PRM, PRN, DSP);
4615 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4616 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4618 pipeline[plPtrExec].address = PRM;
4621 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4623 pipeline[plPtrExec].value = PRN & 0xFFFF;
4624 pipeline[plPtrExec].type = TYPE_DWORD;
4628 pipeline[plPtrExec].value = PRN;
4629 pipeline[plPtrExec].type = TYPE_WORD;
4634 static void DSP_store_r14_i(void)
4636 #ifdef DSP_DIS_STORE14I
4638 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));
4640 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4642 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4643 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4645 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4647 pipeline[plPtrExec].value = PRN;
4648 pipeline[plPtrExec].type = TYPE_DWORD;
4652 static void DSP_store_r14_r(void)
4654 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4656 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4657 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4659 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4661 pipeline[plPtrExec].value = PRN;
4662 pipeline[plPtrExec].type = TYPE_DWORD;
4666 static void DSP_store_r15_i(void)
4668 #ifdef DSP_DIS_STORE15I
4670 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));
4672 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4674 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4675 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4677 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4679 pipeline[plPtrExec].value = PRN;
4680 pipeline[plPtrExec].type = TYPE_DWORD;
4684 static void DSP_store_r15_r(void)
4686 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4688 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4689 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4691 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4693 pipeline[plPtrExec].value = PRN;
4694 pipeline[plPtrExec].type = TYPE_DWORD;
4698 static void DSP_sub(void)
4702 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);
4704 uint32_t res = PRN - PRM;
4705 SET_ZNC_SUB(PRN, PRM, res);
4709 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);
4713 static void DSP_subc(void)
4717 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);
4719 uint32_t res = PRN - PRM - dsp_flag_c;
4720 uint32_t borrow = dsp_flag_c;
4721 SET_ZNC_SUB(PRN - borrow, PRM, res);
4725 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);
4729 static void DSP_subq(void)
4733 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);
4735 uint32_t r1 = dsp_convert_zero[PIMM1];
4736 uint32_t res = PRN - r1;
4737 SET_ZNC_SUB(PRN, r1, res);
4741 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4745 static void DSP_subqmod(void)
4747 uint32_t r1 = dsp_convert_zero[PIMM1];
4749 uint32_t res = r2 - r1;
4750 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4752 SET_ZNC_SUB(r2, r1, res);
4755 static void DSP_subqt(void)
4757 #ifdef DSP_DIS_SUBQT
4759 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);
4761 PRES = PRN - dsp_convert_zero[PIMM1];
4762 #ifdef DSP_DIS_SUBQT
4764 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4768 static void DSP_xor(void)
4772 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);
4778 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);