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>
10 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
13 // --- ---------- -------------------------------------------------------------
14 // JLH 01/16/2010 Created this log ;-)
15 // JLH 11/26/2011 Added fixes for LOAD/STORE alignment issues
16 // JPM 06/06/2016 Visual Studio support
21 #include <SDL.h> // Used only for SDL_GetTicks...
29 #include "m68000/m68kinterface.h"
33 // Seems alignment in loads & stores was off...
34 #define DSP_CORRECT_ALIGNMENT
35 //#define DSP_CORRECT_ALIGNMENT_STORE
38 //#define DSP_DEBUG_IRQ
39 //#define DSP_DEBUG_PL2
40 //#define DSP_DEBUG_STALL
41 //#define DSP_DEBUG_CC
42 #define NEW_SCOREBOARD
44 // Disassembly definitions
51 #define DSP_DIS_ADDQMOD
61 #define DSP_DIS_IMULTN
62 #define DSP_DIS_ILLEGAL
66 #define DSP_DIS_LOAD14I
67 #define DSP_DIS_LOAD14R
68 #define DSP_DIS_LOAD15I
69 #define DSP_DIS_LOAD15R
75 #define DSP_DIS_MOVEFA
76 #define DSP_DIS_MOVEPC // Pipeline only!
77 #define DSP_DIS_MOVETA
83 #define DSP_DIS_RESMAC
90 #define DSP_DIS_STORE14I
91 #define DSP_DIS_STORE15I
92 #define DSP_DIS_STOREB
93 #define DSP_DIS_STOREW
100 bool doDSPDis
= false;
101 //bool doDSPDis = true;
103 bool doDSPDis
= false;
105 //#define DSP_DIS_JUMP
139 + load_r15_indexed 284500
141 + store_r15_indexed 47416
145 + load_r14_ri 1229448
148 // Pipeline structures
150 const bool affectsScoreboard
[64] =
152 true, true, true, true,
153 true, true, true, true,
154 true, true, true, true,
155 true, false, true, true,
157 true, true, false, true,
158 false, true, true, true,
159 true, true, true, true,
160 true, true, false, false,
162 true, true, true, true,
163 false, true, true, true,
164 true, true, true, true,
165 true, false, false, false,
167 true, false, false, true,
168 false, false, true, true,
169 true, false, true, true,
170 false, false, false, true
175 uint16_t instruction
;
176 uint8_t opcode
, operand1
, operand2
;
177 uint32_t reg1
, reg2
, areg1
, areg2
;
179 uint8_t writebackRegister
;
180 // General memory store...
189 #define PIPELINE_STALL 64 // Set to # of opcodes + 1
190 #ifndef NEW_SCOREBOARD
193 uint8_t scoreboard
[32];
195 uint8_t plPtrFetch
, plPtrRead
, plPtrExec
, plPtrWrite
;
196 PipelineStage pipeline
[4];
197 bool IMASKCleared
= false;
199 // DSP flags (old--have to get rid of this crap)
201 #define CINT0FLAG 0x00200
202 #define CINT1FLAG 0x00400
203 #define CINT2FLAG 0x00800
204 #define CINT3FLAG 0x01000
205 #define CINT4FLAG 0x02000
206 #define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG)
207 #define CINT5FLAG 0x20000 /* DSP only */
211 #define ZERO_FLAG 0x00001
212 #define CARRY_FLAG 0x00002
213 #define NEGA_FLAG 0x00004
214 #define IMASK 0x00008
215 #define INT_ENA0 0x00010
216 #define INT_ENA1 0x00020
217 #define INT_ENA2 0x00040
218 #define INT_ENA3 0x00080
219 #define INT_ENA4 0x00100
220 #define INT_CLR0 0x00200
221 #define INT_CLR1 0x00400
222 #define INT_CLR2 0x00800
223 #define INT_CLR3 0x01000
224 #define INT_CLR4 0x02000
225 #define REGPAGE 0x04000
226 #define DMAEN 0x08000
227 #define INT_ENA5 0x10000
228 #define INT_CLR5 0x20000
232 #define DSPGO 0x00001
233 #define CPUINT 0x00002
234 #define DSPINT0 0x00004
235 #define SINGLE_STEP 0x00008
236 #define SINGLE_GO 0x00010
238 #define INT_LAT0 0x00040
239 #define INT_LAT1 0x00080
240 #define INT_LAT2 0x00100
241 #define INT_LAT3 0x00200
242 #define INT_LAT4 0x00400
243 #define BUS_HOG 0x00800
244 #define VERSION 0x0F000
245 #define INT_LAT5 0x10000
247 extern uint32_t jaguar_mainRom_crc32
;
249 // Is opcode 62 *really* a NOP? Seems like it...
250 static void dsp_opcode_abs(void);
251 static void dsp_opcode_add(void);
252 static void dsp_opcode_addc(void);
253 static void dsp_opcode_addq(void);
254 static void dsp_opcode_addqmod(void);
255 static void dsp_opcode_addqt(void);
256 static void dsp_opcode_and(void);
257 static void dsp_opcode_bclr(void);
258 static void dsp_opcode_bset(void);
259 static void dsp_opcode_btst(void);
260 static void dsp_opcode_cmp(void);
261 static void dsp_opcode_cmpq(void);
262 static void dsp_opcode_div(void);
263 static void dsp_opcode_imacn(void);
264 static void dsp_opcode_imult(void);
265 static void dsp_opcode_imultn(void);
266 static void dsp_opcode_jr(void);
267 static void dsp_opcode_jump(void);
268 static void dsp_opcode_load(void);
269 static void dsp_opcode_loadb(void);
270 static void dsp_opcode_loadw(void);
271 static void dsp_opcode_load_r14_indexed(void);
272 static void dsp_opcode_load_r14_ri(void);
273 static void dsp_opcode_load_r15_indexed(void);
274 static void dsp_opcode_load_r15_ri(void);
275 static void dsp_opcode_mirror(void);
276 static void dsp_opcode_mmult(void);
277 static void dsp_opcode_move(void);
278 static void dsp_opcode_movei(void);
279 static void dsp_opcode_movefa(void);
280 static void dsp_opcode_move_pc(void);
281 static void dsp_opcode_moveq(void);
282 static void dsp_opcode_moveta(void);
283 static void dsp_opcode_mtoi(void);
284 static void dsp_opcode_mult(void);
285 static void dsp_opcode_neg(void);
286 static void dsp_opcode_nop(void);
287 static void dsp_opcode_normi(void);
288 static void dsp_opcode_not(void);
289 static void dsp_opcode_or(void);
290 static void dsp_opcode_resmac(void);
291 static void dsp_opcode_ror(void);
292 static void dsp_opcode_rorq(void);
293 static void dsp_opcode_xor(void);
294 static void dsp_opcode_sat16s(void);
295 static void dsp_opcode_sat32s(void);
296 static void dsp_opcode_sh(void);
297 static void dsp_opcode_sha(void);
298 static void dsp_opcode_sharq(void);
299 static void dsp_opcode_shlq(void);
300 static void dsp_opcode_shrq(void);
301 static void dsp_opcode_store(void);
302 static void dsp_opcode_storeb(void);
303 static void dsp_opcode_storew(void);
304 static void dsp_opcode_store_r14_indexed(void);
305 static void dsp_opcode_store_r14_ri(void);
306 static void dsp_opcode_store_r15_indexed(void);
307 static void dsp_opcode_store_r15_ri(void);
308 static void dsp_opcode_sub(void);
309 static void dsp_opcode_subc(void);
310 static void dsp_opcode_subq(void);
311 static void dsp_opcode_subqmod(void);
312 static void dsp_opcode_subqt(void);
313 static void dsp_opcode_illegal(void);
315 /*uint8_t dsp_opcode_cycles[64] =
317 3, 3, 3, 3, 3, 3, 3, 3,
318 3, 3, 3, 3, 3, 3, 3, 3,
319 3, 3, 1, 3, 1, 18, 3, 3,
320 3, 3, 3, 3, 3, 3, 3, 3,
321 3, 3, 2, 2, 2, 2, 3, 4,
322 5, 4, 5, 6, 6, 1, 1, 1,
323 1, 2, 2, 2, 1, 1, 9, 3,
324 3, 1, 6, 6, 2, 2, 3, 3
326 //Here's a QnD kludge...
327 //This is wrong, wrong, WRONG, but it seems to work for the time being...
328 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
329 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
330 // Yup, without cheating like this, the sound in things like Rayman, FACTS, &
331 // Tripper Getem get starved for time and sounds like crap. So we have to figure
332 // out how to fix that. :-/
333 uint8_t dsp_opcode_cycles
[64] =
335 1, 1, 1, 1, 1, 1, 1, 1,
336 1, 1, 1, 1, 1, 1, 1, 1,
337 1, 1, 1, 1, 1, 9, 1, 1,
338 1, 1, 1, 1, 1, 1, 1, 1,
339 1, 1, 1, 1, 1, 1, 1, 2,
340 2, 2, 2, 3, 3, 1, 1, 1,
341 1, 1, 1, 1, 1, 1, 4, 1,
342 1, 1, 3, 3, 1, 1, 1, 1
345 void (* dsp_opcode
[64])() =
347 dsp_opcode_add
, dsp_opcode_addc
, dsp_opcode_addq
, dsp_opcode_addqt
,
348 dsp_opcode_sub
, dsp_opcode_subc
, dsp_opcode_subq
, dsp_opcode_subqt
,
349 dsp_opcode_neg
, dsp_opcode_and
, dsp_opcode_or
, dsp_opcode_xor
,
350 dsp_opcode_not
, dsp_opcode_btst
, dsp_opcode_bset
, dsp_opcode_bclr
,
351 dsp_opcode_mult
, dsp_opcode_imult
, dsp_opcode_imultn
, dsp_opcode_resmac
,
352 dsp_opcode_imacn
, dsp_opcode_div
, dsp_opcode_abs
, dsp_opcode_sh
,
353 dsp_opcode_shlq
, dsp_opcode_shrq
, dsp_opcode_sha
, dsp_opcode_sharq
,
354 dsp_opcode_ror
, dsp_opcode_rorq
, dsp_opcode_cmp
, dsp_opcode_cmpq
,
355 dsp_opcode_subqmod
, dsp_opcode_sat16s
, dsp_opcode_move
, dsp_opcode_moveq
,
356 dsp_opcode_moveta
, dsp_opcode_movefa
, dsp_opcode_movei
, dsp_opcode_loadb
,
357 dsp_opcode_loadw
, dsp_opcode_load
, dsp_opcode_sat32s
, dsp_opcode_load_r14_indexed
,
358 dsp_opcode_load_r15_indexed
, dsp_opcode_storeb
, dsp_opcode_storew
, dsp_opcode_store
,
359 dsp_opcode_mirror
, dsp_opcode_store_r14_indexed
, dsp_opcode_store_r15_indexed
, dsp_opcode_move_pc
,
360 dsp_opcode_jump
, dsp_opcode_jr
, dsp_opcode_mmult
, dsp_opcode_mtoi
,
361 dsp_opcode_normi
, dsp_opcode_nop
, dsp_opcode_load_r14_ri
, dsp_opcode_load_r15_ri
,
362 dsp_opcode_store_r14_ri
, dsp_opcode_store_r15_ri
, dsp_opcode_illegal
, dsp_opcode_addqmod
,
365 uint32_t dsp_opcode_use
[65];
367 const char * dsp_opcode_str
[65]=
369 "add", "addc", "addq", "addqt",
370 "sub", "subc", "subq", "subqt",
371 "neg", "and", "or", "xor",
372 "not", "btst", "bset", "bclr",
373 "mult", "imult", "imultn", "resmac",
374 "imacn", "div", "abs", "sh",
375 "shlq", "shrq", "sha", "sharq",
376 "ror", "rorq", "cmp", "cmpq",
377 "subqmod", "sat16s", "move", "moveq",
378 "moveta", "movefa", "movei", "loadb",
379 "loadw", "load", "sat32s", "load_r14_indexed",
380 "load_r15_indexed", "storeb", "storew", "store",
381 "mirror", "store_r14_indexed","store_r15_indexed","move_pc",
382 "jump", "jr", "mmult", "mtoi",
383 "normi", "nop", "load_r14_ri", "load_r15_ri",
384 "store_r14_ri", "store_r15_ri", "illegal", "addqmod",
389 static uint64_t dsp_acc
; // 40 bit register, NOT 32!
390 static uint32_t dsp_remain
;
391 static uint32_t dsp_modulo
;
392 static uint32_t dsp_flags
;
393 static uint32_t dsp_matrix_control
;
394 static uint32_t dsp_pointer_to_matrix
;
395 static uint32_t dsp_data_organization
;
396 uint32_t dsp_control
;
397 static uint32_t dsp_div_control
;
398 static uint8_t dsp_flag_z
, dsp_flag_n
, dsp_flag_c
;
399 static uint32_t * dsp_reg
= NULL
, * dsp_alternate_reg
= NULL
;
400 uint32_t dsp_reg_bank_0
[32], dsp_reg_bank_1
[32];
402 static uint32_t dsp_opcode_first_parameter
;
403 static uint32_t dsp_opcode_second_parameter
;
405 #define DSP_RUNNING (dsp_control & 0x01)
407 #define RM dsp_reg[dsp_opcode_first_parameter]
408 #define RN dsp_reg[dsp_opcode_second_parameter]
409 #define ALTERNATE_RM dsp_alternate_reg[dsp_opcode_first_parameter]
410 #define ALTERNATE_RN dsp_alternate_reg[dsp_opcode_second_parameter]
411 #define IMM_1 dsp_opcode_first_parameter
412 #define IMM_2 dsp_opcode_second_parameter
414 #define CLR_Z (dsp_flag_z = 0)
415 #define CLR_ZN (dsp_flag_z = dsp_flag_n = 0)
416 #define CLR_ZNC (dsp_flag_z = dsp_flag_n = dsp_flag_c = 0)
417 #define SET_Z(r) (dsp_flag_z = ((r) == 0))
418 #define SET_N(r) (dsp_flag_n = (((uint32_t)(r) >> 31) & 0x01))
419 #define SET_C_ADD(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(~(a))))
420 #define SET_C_SUB(a,b) (dsp_flag_c = ((uint32_t)(b) > (uint32_t)(a)))
421 #define SET_ZN(r) SET_N(r); SET_Z(r)
422 #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
423 #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
425 uint32_t dsp_convert_zero
[32] = {
426 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
427 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
430 uint8_t dsp_branch_condition_table
[32 * 8];
431 static uint16_t mirror_table
[65536];
432 static uint8_t dsp_ram_8
[0x2000];
434 #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
436 static uint32_t dsp_in_exec
= 0;
437 static uint32_t dsp_releaseTimeSlice_flag
= 0;
442 // Comparison core vars (used only for core comparison! :-)
443 static uint64_t count
= 0;
444 static uint8_t ram1
[0x2000], ram2
[0x2000];
445 static uint32_t regs1
[64], regs2
[64];
446 static uint32_t ctrl1
[14], ctrl2
[14];
449 // Private function prototypes
451 void DSPDumpRegisters(void);
452 void DSPDumpDisassembly(void);
453 void FlushDSPPipeline(void);
456 void dsp_reset_stats(void)
458 for(int i
=0; i
<65; i
++)
459 dsp_opcode_use
[i
] = 0;
463 void DSPReleaseTimeslice(void)
465 //This does absolutely nothing!!! !!! FIX !!!
466 dsp_releaseTimeSlice_flag
= 1;
470 void dsp_build_branch_condition_table(void)
472 // Fill in the mirror table
473 for(int i
=0; i
<65536; i
++)
475 mirror_table
[i
] = ((i
>> 15) & 0x0001) | ((i
>> 13) & 0x0002)
476 | ((i
>> 11) & 0x0004) | ((i
>> 9) & 0x0008)
477 | ((i
>> 7) & 0x0010) | ((i
>> 5) & 0x0020)
478 | ((i
>> 3) & 0x0040) | ((i
>> 1) & 0x0080)
479 | ((i
<< 1) & 0x0100) | ((i
<< 3) & 0x0200)
480 | ((i
<< 5) & 0x0400) | ((i
<< 7) & 0x0800)
481 | ((i
<< 9) & 0x1000) | ((i
<< 11) & 0x2000)
482 | ((i
<< 13) & 0x4000) | ((i
<< 15) & 0x8000);
485 // Fill in the condition table
486 for(int i
=0; i
<8; i
++)
488 for(int j
=0; j
<32; j
++)
492 if ((j
& 1) && (i
& ZERO_FLAG
))
495 if ((j
& 2) && (!(i
& ZERO_FLAG
)))
498 if ((j
& 4) && (i
& (CARRY_FLAG
<< (j
>> 4))))
501 if ((j
& 8) && (!(i
& (CARRY_FLAG
<< (j
>> 4)))))
504 dsp_branch_condition_table
[i
* 32 + j
] = result
;
510 uint8_t DSPReadByte(uint32_t offset
, uint32_t who
/*=UNKNOWN*/)
512 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
513 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName
[who
]);
515 // if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
518 /* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
520 if (offset==0xF1CFE0)
523 if (offset
>= DSP_WORK_RAM_BASE
&& offset
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
524 return dsp_ram_8
[offset
- DSP_WORK_RAM_BASE
];
526 if (offset
>= DSP_CONTROL_RAM_BASE
&& offset
<= (DSP_CONTROL_RAM_BASE
+ 0x1F))
528 uint32_t data
= DSPReadLong(offset
& 0xFFFFFFFC, who
);
530 if ((offset
& 0x03) == 0)
532 else if ((offset
& 0x03) == 1)
533 return ((data
>> 16) & 0xFF);
534 else if ((offset
& 0x03) == 2)
535 return ((data
>> 8) & 0xFF);
536 else if ((offset
& 0x03) == 3)
537 return (data
& 0xFF);
540 return JaguarReadByte(offset
, who
);
544 uint16_t DSPReadWord(uint32_t offset
, uint32_t who
/*=UNKNOWN*/)
546 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
547 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName
[who
]);
549 offset
&= 0xFFFFFFFE;
551 if (offset
>= DSP_WORK_RAM_BASE
&& offset
<= DSP_WORK_RAM_BASE
+0x1FFF)
553 offset
-= DSP_WORK_RAM_BASE
;
554 /* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
556 return GET16(dsp_ram_8
, offset
);
558 else if ((offset
>=DSP_CONTROL_RAM_BASE
)&&(offset
<DSP_CONTROL_RAM_BASE
+0x20))
560 uint32_t data
= DSPReadLong(offset
& 0xFFFFFFFC, who
);
563 return data
& 0xFFFF;
568 return JaguarReadWord(offset
, who
);
572 uint32_t DSPReadLong(uint32_t offset
, uint32_t who
/*=UNKNOWN*/)
574 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
575 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName
[who
]);
578 offset
&= 0xFFFFFFFC;
579 /*if (offset == 0xF1BCF4)
581 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));
582 DSPDumpDisassembly();
584 if (offset
>= DSP_WORK_RAM_BASE
&& offset
<= DSP_WORK_RAM_BASE
+ 0x1FFF)
586 offset
-= DSP_WORK_RAM_BASE
;
587 return GET32(dsp_ram_8
, offset
);
589 //NOTE: Didn't return DSP_ACCUM!!!
590 //Mebbe it's not 'spose to! Yes, it is!
591 if (offset
>= DSP_CONTROL_RAM_BASE
&& offset
<= DSP_CONTROL_RAM_BASE
+ 0x23)
597 dsp_flags
= (dsp_flags
& 0xFFFFFFF8) | (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
;
598 return dsp_flags
& 0xFFFFC1FF;
599 case 0x04: return dsp_matrix_control
;
600 case 0x08: return dsp_pointer_to_matrix
;
601 case 0x0C: return dsp_data_organization
;
602 case 0x10: return dsp_pc
;
603 case 0x14: return dsp_control
;
604 case 0x18: return dsp_modulo
;
605 case 0x1C: return dsp_remain
;
607 return (int32_t)((int8_t)(dsp_acc
>> 32)); // Top 8 bits of 40-bit accumulator, sign extended
609 // unaligned long read-- !!! FIX !!!
613 return JaguarReadLong(offset
, who
);
617 void DSPWriteByte(uint32_t offset
, uint8_t data
, uint32_t who
/*=UNKNOWN*/)
619 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
620 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName
[who
]);
622 if ((offset
>= DSP_WORK_RAM_BASE
) && (offset
< DSP_WORK_RAM_BASE
+ 0x2000))
624 offset
-= DSP_WORK_RAM_BASE
;
625 dsp_ram_8
[offset
] = data
;
626 //This is rather stupid! !!! FIX !!!
627 /* if (dsp_in_exec == 0)
629 m68k_end_timeslice();
630 dsp_releaseTimeslice();
634 if ((offset
>= DSP_CONTROL_RAM_BASE
) && (offset
< DSP_CONTROL_RAM_BASE
+ 0x20))
636 uint32_t reg
= offset
& 0x1C;
637 int bytenum
= offset
& 0x03;
639 if ((reg
>= 0x1C) && (reg
<= 0x1F))
640 dsp_div_control
= (dsp_div_control
& (~(0xFF << (bytenum
<< 3)))) | (data
<< (bytenum
<< 3));
643 //This looks funky. !!! FIX !!!
644 uint32_t old_data
= DSPReadLong(offset
&0xFFFFFFC, who
);
645 bytenum
= 3 - bytenum
; // convention motorola !!!
646 old_data
= (old_data
& (~(0xFF << (bytenum
<< 3)))) | (data
<< (bytenum
<< 3));
647 DSPWriteLong(offset
& 0xFFFFFFC, old_data
, who
);
651 // WriteLog("dsp: writing %.2x at 0x%.8x\n",data,offset);
652 //Should this *ever* happen??? Shouldn't we be saying "unknown" here???
653 // Well, yes, it can. There are 3 MMU users after all: 68K, GPU & DSP...!
654 JaguarWriteByte(offset
, data
, who
);
658 void DSPWriteWord(uint32_t offset
, uint16_t data
, uint32_t who
/*=UNKNOWN*/)
660 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
661 WriteLog("DSP: WriteWord--Attempt to write to DSP register file by %s!\n", whoName
[who
]);
662 offset
&= 0xFFFFFFFE;
663 /*if (offset == 0xF1BCF4)
665 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
667 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
668 if ((offset
>= DSP_WORK_RAM_BASE
) && (offset
< DSP_WORK_RAM_BASE
+0x2000))
670 /*if (offset == 0xF1B2F4)
672 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
674 offset
-= DSP_WORK_RAM_BASE
;
675 dsp_ram_8
[offset
] = data
>> 8;
676 dsp_ram_8
[offset
+1] = data
& 0xFF;
677 //This is rather stupid! !!! FIX !!!
678 /* if (dsp_in_exec == 0)
680 // WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
681 m68k_end_timeslice();
682 dsp_releaseTimeslice();
686 SET16(ram1
, offset
, data
),
687 SET16(ram2
, offset
, data
);
692 else if ((offset
>= DSP_CONTROL_RAM_BASE
) && (offset
< DSP_CONTROL_RAM_BASE
+0x20))
694 if ((offset
& 0x1C) == 0x1C)
697 dsp_div_control
= (dsp_div_control
& 0xFFFF0000) | (data
& 0xFFFF);
699 dsp_div_control
= (dsp_div_control
& 0xFFFF) | ((data
& 0xFFFF) << 16);
703 uint32_t old_data
= DSPReadLong(offset
& 0xFFFFFFC, who
);
706 old_data
= (old_data
& 0xFFFF0000) | (data
& 0xFFFF);
708 old_data
= (old_data
& 0xFFFF) | ((data
& 0xFFFF) << 16);
710 DSPWriteLong(offset
& 0xFFFFFFC, old_data
, who
);
716 JaguarWriteWord(offset
, data
, who
);
720 //bool badWrite = false;
721 void DSPWriteLong(uint32_t offset
, uint32_t data
, uint32_t who
/*=UNKNOWN*/)
723 if (offset
>= 0xF1A000 && offset
<= 0xF1A0FF)
724 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName
[who
]);
726 offset
&= 0xFFFFFFFC;
727 /*if (offset == 0xF1BCF4)
729 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
731 // WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
732 if (offset
>= DSP_WORK_RAM_BASE
&& offset
<= DSP_WORK_RAM_BASE
+ 0x1FFF)
734 /*if (offset == 0xF1BE2C)
736 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
738 offset
-= DSP_WORK_RAM_BASE
;
739 SET32(dsp_ram_8
, offset
, data
);
742 SET32(ram1
, offset
, data
),
743 SET32(ram2
, offset
, data
);
748 else if (offset
>= DSP_CONTROL_RAM_BASE
&& offset
<= (DSP_CONTROL_RAM_BASE
+ 0x1F))
756 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data
, whoName
[who
], (dsp_flags
& REGPAGE
? "" : "not "));
758 // bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
759 IMASKCleared
= (dsp_flags
& IMASK
) && !(data
& IMASK
);
760 // NOTE: According to the JTRM, writing a 1 to IMASK has no effect; only the
761 // IRQ logic can set it. So we mask it out here to prevent problems...
762 dsp_flags
= data
& (~IMASK
);
763 dsp_flag_z
= dsp_flags
& 0x01;
764 dsp_flag_c
= (dsp_flags
>> 1) & 0x01;
765 dsp_flag_n
= (dsp_flags
>> 2) & 0x01;
766 DSPUpdateRegisterBanks();
767 dsp_control
&= ~((dsp_flags
& CINT04FLAGS
) >> 3);
768 dsp_control
&= ~((dsp_flags
& CINT5FLAG
) >> 1);
772 dsp_matrix_control
= data
;
775 // According to JTRM, only lines 2-11 are addressable, the rest being
776 // hardwired to $F1Bxxx.
777 dsp_pointer_to_matrix
= 0xF1B000 | (data
& 0x000FFC);
780 dsp_data_organization
= data
;
785 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc
, whoName
[who
], (DSP_RUNNING
? " (DSP is RUNNING!)" : ""));//*/
790 ctrl1
[0] = ctrl2
[0] = data
;
797 WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName
[who
], data
, dsp_pc
);
799 bool wasRunning
= DSP_RUNNING
;
800 // uint32_t dsp_was_running = DSP_RUNNING;
801 // Check for DSP -> CPU interrupt
805 WriteLog("DSP: DSP -> CPU interrupt\n");
809 #pragma message("Warning: !!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!")
811 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
813 if (JERRYIRQEnabled(IRQ2_DSP
))
815 JERRYSetPendingIRQ(IRQ2_DSP
);
816 DSPReleaseTimeslice();
817 m68k_set_irq(2); // Set 68000 IPL 2...
821 // Check for CPU -> DSP interrupt
825 WriteLog("DSP: CPU -> DSP interrupt\n");
827 m68k_end_timeslice();
828 DSPReleaseTimeslice();
829 DSPSetIRQLine(DSPIRQ_CPU
, ASSERT_LINE
);
833 if (data
& SINGLE_STEP
)
835 // WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
838 // Protect writes to VERSION and the interrupt latches...
839 uint32_t mask
= VERSION
| INT_LAT0
| INT_LAT1
| INT_LAT2
| INT_LAT3
| INT_LAT4
| INT_LAT5
;
840 dsp_control
= (dsp_control
& mask
) | (data
& ~mask
);
844 ctrl1
[8] = ctrl2
[8] = dsp_control
;
848 // if dsp wasn't running but is now running
849 // execute a few cycles
850 //This is just plain wrong, wrong, WRONG!
851 #ifndef DSP_SINGLE_STEPPING
852 /* if (!dsp_was_running && DSP_RUNNING)
857 //This is WRONG! !!! FIX !!!
858 if (dsp_control
& 0x18)
863 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc
, whoName
[who
]);
865 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName
[who
], dsp_pc
);
868 //This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
869 // !!! FIX !!! [DONE]
873 m68k_end_timeslice();
875 DSPReleaseTimeslice();
879 //DSPDumpDisassembly();
884 WriteLog("DSP: Modulo data %08X written by %s.\n", data
, whoName
[who
]);
888 dsp_div_control
= data
;
890 // default: // unaligned long read
896 //We don't have to break this up like this! We CAN do 32 bit writes!
897 // JaguarWriteWord(offset, (data>>16) & 0xFFFF, DSP);
898 // JaguarWriteWord(offset+2, data & 0xFFFF, DSP);
899 //if (offset > 0xF1FFFF)
901 JaguarWriteLong(offset
, data
, who
);
906 // Update the DSP register file pointers depending on REGPAGE bit
908 void DSPUpdateRegisterBanks(void)
910 int bank
= (dsp_flags
& REGPAGE
);
912 if (dsp_flags
& IMASK
)
913 bank
= 0; // IMASK forces main bank to be bank 0
916 dsp_reg
= dsp_reg_bank_1
, dsp_alternate_reg
= dsp_reg_bank_0
;
918 dsp_reg
= dsp_reg_bank_0
, dsp_alternate_reg
= dsp_reg_bank_1
;
921 WriteLog("DSP: Register bank #%s active.\n", (bank
? "1" : "0"));
927 // Check for and handle any asserted DSP IRQs
929 void DSPHandleIRQs(void)
931 if (dsp_flags
& IMASK
) // Bail if we're already inside an interrupt
934 // Get the active interrupt bits (latches) & interrupt mask (enables)
935 uint32_t bits
= ((dsp_control
>> 10) & 0x20) | ((dsp_control
>> 6) & 0x1F),
936 mask
= ((dsp_flags
>> 11) & 0x20) | ((dsp_flags
>> 4) & 0x1F);
938 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
941 if (!bits
) // Bail if nothing is enabled
944 int which
= 0; // Determine which interrupt
960 WriteLog("DSP: Generating interrupt #%i...", which
);
963 //if (which == 0) doDSPDis = true;
965 // NOTE: Since the actual Jaguar hardware injects the code sequence below
966 // directly into the pipeline, it has the side effect of ensuring that the
967 // instruction interrupted also gets to do its writeback. We simulate that
969 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
971 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
972 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
974 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
975 scoreboard[pipeline[plPtrWrite].operand2] = false;
977 //This should be execute (or should it?--not sure now!)
978 //Actually, the way this is called now, this should be correct (i.e., the plPtrs advance,
979 //and what just executed is now in the Write position...). So why didn't it do the
980 //writeback into register 0?
982 WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc
);
983 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
]);
984 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
]);
985 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
]);
987 if (pipeline
[plPtrWrite
].opcode
!= PIPELINE_STALL
)
989 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFF)
991 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFE)
992 dsp_reg
[pipeline
[plPtrWrite
].writebackRegister
] = pipeline
[plPtrWrite
].result
;
995 if (pipeline
[plPtrWrite
].type
== TYPE_BYTE
)
996 JaguarWriteByte(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
997 else if (pipeline
[plPtrWrite
].type
== TYPE_WORD
)
998 JaguarWriteWord(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
1000 JaguarWriteLong(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
1004 #ifndef NEW_SCOREBOARD
1005 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
1006 scoreboard
[pipeline
[plPtrWrite
].operand2
] = false;
1008 //Yup, sequential MOVEQ # problem fixing (I hope!)...
1009 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
1010 if (scoreboard
[pipeline
[plPtrWrite
].operand2
])
1011 scoreboard
[pipeline
[plPtrWrite
].operand2
]--;
1018 ctrl2
[4] = dsp_flags
;
1021 DSPUpdateRegisterBanks();
1022 #ifdef DSP_DEBUG_IRQ
1023 // WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]);
1024 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]);
1027 // subqt #4,r31 ; pre-decrement stack pointer
1028 // move pc,r30 ; address of interrupted code
1029 // store r30,(r31) ; store return address
1036 //This might not come back to the right place if the instruction was MOVEI #. !!! FIX !!!
1037 //But, then again, JTRM says that it adds two regardless of what the instruction was...
1038 //It missed the place that it was supposed to come back to, so this is WRONG!
1040 // Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1042 // R -> baz (<- PC points here)
1043 // E -> bar (when it should point here!)
1046 // 'Foo' just completed executing as per above. PC is pointing to the instruction 'baz'
1047 // which means (assuming they're all 2 bytes long) that the code below will come back on
1048 // instruction 'baz' instead of 'bar' which is the next instruction to execute in the
1049 // instruction stream...
1051 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1052 DSPWriteLong(dsp_reg
[31], dsp_pc
- 2 - (pipeline
[plPtrExec
].opcode
== 38 ? 6 : (pipeline
[plPtrExec
].opcode
== PIPELINE_STALL
? 0 : 2)), DSP
);
1055 SET32(ram2
, regs2
[31] - 0xF1B000, dsp_pc
- 2 - (pipeline
[plPtrExec
].opcode
== 38 ? 6 : (pipeline
[plPtrExec
].opcode
== PIPELINE_STALL
? 0 : 2)));
1059 // movei #service_address,r30 ; pointer to ISR entry
1060 // jump (r30) ; jump to ISR
1062 dsp_pc
= dsp_reg
[30] = DSP_WORK_RAM_BASE
+ (which
* 0x10);
1065 ctrl2
[0] = regs2
[30] = dsp_pc
;
1073 // Non-pipelined version...
1075 void DSPHandleIRQsNP(void)
1079 memcpy(dsp_ram_8
, ram1
, 0x2000);
1080 memcpy(dsp_reg_bank_0
, regs1
, 32 * 4);
1081 memcpy(dsp_reg_bank_1
, ®s1
[32], 32 * 4);
1084 dsp_remain
= ctrl1
[2];
1085 dsp_modulo
= ctrl1
[3];
1086 dsp_flags
= ctrl1
[4];
1087 dsp_matrix_control
= ctrl1
[5];
1088 dsp_pointer_to_matrix
= ctrl1
[6];
1089 dsp_data_organization
= ctrl1
[7];
1090 dsp_control
= ctrl1
[8];
1091 dsp_div_control
= ctrl1
[9];
1092 IMASKCleared
= ctrl1
[10];
1093 dsp_flag_z
= ctrl1
[11];
1094 dsp_flag_n
= ctrl1
[12];
1095 dsp_flag_c
= ctrl1
[13];
1096 DSPUpdateRegisterBanks();
1099 if (dsp_flags
& IMASK
) // Bail if we're already inside an interrupt
1102 // Get the active interrupt bits (latches) & interrupt mask (enables)
1103 uint32_t bits
= ((dsp_control
>> 10) & 0x20) | ((dsp_control
>> 6) & 0x1F),
1104 mask
= ((dsp_flags
>> 11) & 0x20) | ((dsp_flags
>> 4) & 0x1F);
1106 // WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1109 if (!bits
) // Bail if nothing is enabled
1112 int which
= 0; // Determine which interrupt
1126 dsp_flags
|= IMASK
; // Force Bank #0
1129 ctrl1
[4] = dsp_flags
;
1132 #ifdef DSP_DEBUG_IRQ
1133 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0
[30], dsp_reg_bank_0
[31]);
1134 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1
[30], dsp_reg_bank_1
[31]);
1136 DSPUpdateRegisterBanks();
1137 #ifdef DSP_DEBUG_IRQ
1138 WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0
[30], dsp_reg_bank_0
[31]);
1139 WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1
[30], dsp_reg_bank_1
[31]);
1142 #ifdef DSP_DEBUG_IRQ
1143 WriteLog("DSP: Generating interrupt #%i...", which
);
1144 WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc
, dsp_reg
[31]);
1147 // subqt #4,r31 ; pre-decrement stack pointer
1148 // move pc,r30 ; address of interrupted code
1149 // store r30,(r31) ; store return address
1151 dsp_reg
[30] = dsp_pc
- 2; // -2 because we've executed the instruction already
1158 // DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1159 DSPWriteLong(dsp_reg
[31], dsp_reg
[30], DSP
);
1162 SET32(ram1
, regs1
[31] - 0xF1B000, dsp_pc
- 2);
1166 // movei #service_address,r30 ; pointer to ISR entry
1167 // jump (r30) ; jump to ISR
1169 dsp_pc
= dsp_reg
[30] = DSP_WORK_RAM_BASE
+ (which
* 0x10);
1172 ctrl1
[0] = regs1
[30] = dsp_pc
;
1179 // Set the specified DSP IRQ line to a given state
1181 void DSPSetIRQLine(int irqline
, int state
)
1183 //NOTE: This doesn't take INT_LAT5 into account. !!! FIX !!!
1184 uint32_t mask
= INT_LAT0
<< irqline
;
1185 dsp_control
&= ~mask
; // Clear the latch bit
1188 ctrl1
[8] = ctrl2
[8] = dsp_control
;
1194 dsp_control
|= mask
; // Set the latch bit
1196 #pragma message("Warning: !!! No checking done to see if we're using pipelined DSP or not !!!")
1198 #warning "!!! No checking done to see if we're using pipelined DSP or not !!!"
1204 ctrl1
[8] = ctrl2
[8] = dsp_control
;
1210 // Not sure if this is correct behavior, but according to JTRM,
1211 // the IRQ output of JERRY is fed to this IRQ in the GPU...
1212 // Not sure this is right--DSP interrupts seem to be different from the JERRY interrupts!
1213 // GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
1217 bool DSPIsRunning(void)
1219 return (DSP_RUNNING
? true : false);
1225 // memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
1226 // memory_malloc_secure((void **)&dsp_reg_bank_0, 32 * sizeof(int32_t), "DSP bank 0 regs");
1227 // memory_malloc_secure((void **)&dsp_reg_bank_1, 32 * sizeof(int32_t), "DSP bank 1 regs");
1229 dsp_build_branch_condition_table();
1236 dsp_pc
= 0x00F1B000;
1237 dsp_acc
= 0x00000000;
1238 dsp_remain
= 0x00000000;
1239 dsp_modulo
= 0xFFFFFFFF;
1240 dsp_flags
= 0x00040000;
1241 dsp_matrix_control
= 0x00000000;
1242 dsp_pointer_to_matrix
= 0x00000000;
1243 dsp_data_organization
= 0xFFFFFFFF;
1244 dsp_control
= 0x00002000; // Report DSP version 2
1245 dsp_div_control
= 0x00000000;
1248 dsp_reg
= dsp_reg_bank_0
;
1249 dsp_alternate_reg
= dsp_reg_bank_1
;
1251 for(int i
=0; i
<32; i
++)
1252 dsp_reg
[i
] = dsp_alternate_reg
[i
] = 0x00000000;
1255 IMASKCleared
= false;
1259 // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
1260 for(uint32_t i
=0; i
<8192; i
+=4)
1261 *((uint32_t *)(&dsp_ram_8
[i
])) = rand();
1265 void DSPDumpDisassembly(void)
1269 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1270 uint32_t j
= 0xF1B000;
1272 while (j
<= 0xF1CFFF)
1275 j
+= dasmjag(JAGUAR_DSP
, buffer
, j
);
1276 WriteLog("\t%08X: %s\n", oldj
, buffer
);
1281 void DSPDumpRegisters(void)
1283 //Shoud add modulus, etc to dump here...
1284 WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, dsp_pc
);
1285 WriteLog("\nRegisters bank 0\n");
1287 for(int j
=0; j
<8; j
++)
1289 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1290 (j
<< 2) + 0, dsp_reg_bank_0
[(j
<< 2) + 0],
1291 (j
<< 2) + 1, dsp_reg_bank_0
[(j
<< 2) + 1],
1292 (j
<< 2) + 2, dsp_reg_bank_0
[(j
<< 2) + 2],
1293 (j
<< 2) + 3, dsp_reg_bank_0
[(j
<< 2) + 3]);
1296 WriteLog("Registers bank 1\n");
1298 for(int j
=0; j
<8; j
++)
1300 WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
1301 (j
<< 2) + 0, dsp_reg_bank_1
[(j
<< 2) + 0],
1302 (j
<< 2) + 1, dsp_reg_bank_1
[(j
<< 2) + 1],
1303 (j
<< 2) + 2, dsp_reg_bank_1
[(j
<< 2) + 2],
1304 (j
<< 2) + 3, dsp_reg_bank_1
[(j
<< 2) + 3]);
1311 WriteLog("\n\n---------------------------------------------------------------------\n");
1312 WriteLog("DSP I/O Registers\n");
1313 WriteLog("---------------------------------------------------------------------\n");
1314 WriteLog("F1%04X (D_FLAGS): $%06X\n", 0xA100, (dsp_flags
& 0xFFFFFFF8) | (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
);
1315 WriteLog("F1%04X (D_MTXC): $%04X\n", 0xA104, dsp_matrix_control
);
1316 WriteLog("F1%04X (D_MTXA): $%04X\n", 0xA108, dsp_pointer_to_matrix
);
1317 WriteLog("F1%04X (D_END): $%02X\n", 0xA10C, dsp_data_organization
);
1318 WriteLog("F1%04X (D_PC): $%06X\n", 0xA110, dsp_pc
);
1319 WriteLog("F1%04X (D_CTRL): $%06X\n", 0xA114, dsp_control
);
1320 WriteLog("F1%04X (D_MOD): $%08X\n", 0xA118, dsp_modulo
);
1321 WriteLog("F1%04X (D_REMAIN): $%08X\n", 0xA11C, dsp_remain
);
1322 WriteLog("F1%04X (D_DIVCTRL): $%02X\n", 0xA11C, dsp_div_control
);
1323 WriteLog("F1%04X (D_MACHI): $%02X\n", 0xA120, (dsp_acc
>> 32) & 0xFF);
1324 WriteLog("---------------------------------------------------------------------\n\n\n");
1326 WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc
, dsp_modulo
, (DSP_RUNNING
? "" : "n't"));
1327 WriteLog("DSP: %sin interrupt handler\n", (dsp_flags
& IMASK
? "" : "not "));
1329 // Get the active interrupt bits
1330 int bits
= ((dsp_control
>> 10) & 0x20) | ((dsp_control
>> 6) & 0x1F);
1331 // Get the interrupt mask
1332 int mask
= ((dsp_flags
>> 11) & 0x20) | ((dsp_flags
>> 4) & 0x1F);
1334 WriteLog("DSP: pending=$%X enabled=$%X (%s%s%s%s%s%s)\n", bits
, mask
,
1335 (mask
& 0x01 ? "CPU " : ""), (mask
& 0x02 ? "I2S " : ""),
1336 (mask
& 0x04 ? "Timer0 " : ""), (mask
& 0x08 ? "Timer1 " : ""),
1337 (mask
& 0x10 ? "Ext0 " : ""), (mask
& 0x20 ? "Ext1" : ""));
1341 static char buffer
[512];
1342 int j
= DSP_WORK_RAM_BASE
;
1344 while (j
<= 0xF1CFFF)
1347 j
+= dasmjag(JAGUAR_DSP
, buffer
, j
);
1348 WriteLog("\t%08X: %s\n", oldj
, buffer
);
1351 WriteLog("DSP opcodes use:\n");
1353 for(int i
=0; i
<64; i
++)
1355 if (dsp_opcode_use
[i
])
1356 WriteLog("\t%s %i\n", dsp_opcode_str
[i
], dsp_opcode_use
[i
]);
1363 // DSP comparison core...
1366 static uint16_t lastExec
;
1367 void DSPExecComp(int32_t cycles
)
1369 while (cycles
> 0 && DSP_RUNNING
)
1371 // Load up vars for non-pipelined core
1372 memcpy(dsp_ram_8
, ram1
, 0x2000);
1373 memcpy(dsp_reg_bank_0
, regs1
, 32 * 4);
1374 memcpy(dsp_reg_bank_1
, ®s1
[32], 32 * 4);
1377 dsp_remain
= ctrl1
[2];
1378 dsp_modulo
= ctrl1
[3];
1379 dsp_flags
= ctrl1
[4];
1380 dsp_matrix_control
= ctrl1
[5];
1381 dsp_pointer_to_matrix
= ctrl1
[6];
1382 dsp_data_organization
= ctrl1
[7];
1383 dsp_control
= ctrl1
[8];
1384 dsp_div_control
= ctrl1
[9];
1385 IMASKCleared
= ctrl1
[10];
1386 dsp_flag_z
= ctrl1
[11];
1387 dsp_flag_n
= ctrl1
[12];
1388 dsp_flag_c
= ctrl1
[13];
1389 DSPUpdateRegisterBanks();
1391 // Decrement cycles based on non-pipelined core...
1392 uint16_t instr1
= DSPReadWord(dsp_pc
, DSP
);
1393 cycles
-= dsp_opcode_cycles
[instr1
>> 10];
1395 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1396 DSPExec(1); // Do *one* instruction
1399 memcpy(ram1
, dsp_ram_8
, 0x2000);
1400 memcpy(regs1
, dsp_reg_bank_0
, 32 * 4);
1401 memcpy(®s1
[32], dsp_reg_bank_1
, 32 * 4);
1404 ctrl1
[2] = dsp_remain
;
1405 ctrl1
[3] = dsp_modulo
;
1406 ctrl1
[4] = dsp_flags
;
1407 ctrl1
[5] = dsp_matrix_control
;
1408 ctrl1
[6] = dsp_pointer_to_matrix
;
1409 ctrl1
[7] = dsp_data_organization
;
1410 ctrl1
[8] = dsp_control
;
1411 ctrl1
[9] = dsp_div_control
;
1412 ctrl1
[10] = IMASKCleared
;
1413 ctrl1
[11] = dsp_flag_z
;
1414 ctrl1
[12] = dsp_flag_n
;
1415 ctrl1
[13] = dsp_flag_c
;
1417 // Load up vars for pipelined core
1418 memcpy(dsp_ram_8
, ram2
, 0x2000);
1419 memcpy(dsp_reg_bank_0
, regs2
, 32 * 4);
1420 memcpy(dsp_reg_bank_1
, ®s2
[32], 32 * 4);
1423 dsp_remain
= ctrl2
[2];
1424 dsp_modulo
= ctrl2
[3];
1425 dsp_flags
= ctrl2
[4];
1426 dsp_matrix_control
= ctrl2
[5];
1427 dsp_pointer_to_matrix
= ctrl2
[6];
1428 dsp_data_organization
= ctrl2
[7];
1429 dsp_control
= ctrl2
[8];
1430 dsp_div_control
= ctrl2
[9];
1431 IMASKCleared
= ctrl2
[10];
1432 dsp_flag_z
= ctrl2
[11];
1433 dsp_flag_n
= ctrl2
[12];
1434 dsp_flag_c
= ctrl2
[13];
1435 DSPUpdateRegisterBanks();
1437 //WriteLog("\tAbout to execute pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1438 DSPExecP2(1); // Do *one* instruction
1441 memcpy(ram2
, dsp_ram_8
, 0x2000);
1442 memcpy(regs2
, dsp_reg_bank_0
, 32 * 4);
1443 memcpy(®s2
[32], dsp_reg_bank_1
, 32 * 4);
1446 ctrl2
[2] = dsp_remain
;
1447 ctrl2
[3] = dsp_modulo
;
1448 ctrl2
[4] = dsp_flags
;
1449 ctrl2
[5] = dsp_matrix_control
;
1450 ctrl2
[6] = dsp_pointer_to_matrix
;
1451 ctrl2
[7] = dsp_data_organization
;
1452 ctrl2
[8] = dsp_control
;
1453 ctrl2
[9] = dsp_div_control
;
1454 ctrl2
[10] = IMASKCleared
;
1455 ctrl2
[11] = dsp_flag_z
;
1456 ctrl2
[12] = dsp_flag_n
;
1457 ctrl2
[13] = dsp_flag_c
;
1459 if (instr1
!= lastExec
)
1461 // WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1463 // 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));
1464 //WriteLog("[DSP_PC1=%08X, DSP_PC2=%08X]\n", ctrl1[0], ppc);
1465 // if (ctrl1[0] < ppc) // P ran ahead of NP
1466 //How to test this crap???
1469 DSPExecP2(1); // Do one more instruction
1472 memcpy(ram2
, dsp_ram_8
, 0x2000);
1473 memcpy(regs2
, dsp_reg_bank_0
, 32 * 4);
1474 memcpy(®s2
[32], dsp_reg_bank_1
, 32 * 4);
1477 ctrl2
[2] = dsp_remain
;
1478 ctrl2
[3] = dsp_modulo
;
1479 ctrl2
[4] = dsp_flags
;
1480 ctrl2
[5] = dsp_matrix_control
;
1481 ctrl2
[6] = dsp_pointer_to_matrix
;
1482 ctrl2
[7] = dsp_data_organization
;
1483 ctrl2
[8] = dsp_control
;
1484 ctrl2
[9] = dsp_div_control
;
1485 ctrl2
[10] = IMASKCleared
;
1486 ctrl2
[11] = dsp_flag_z
;
1487 ctrl2
[12] = dsp_flag_n
;
1488 ctrl2
[13] = dsp_flag_c
;
1490 // else // NP ran ahead of P
1491 if (instr1
!= lastExec
) // Must be the other way...
1494 // Load up vars for non-pipelined core
1495 memcpy(dsp_ram_8
, ram1
, 0x2000);
1496 memcpy(dsp_reg_bank_0
, regs1
, 32 * 4);
1497 memcpy(dsp_reg_bank_1
, ®s1
[32], 32 * 4);
1500 dsp_remain
= ctrl1
[2];
1501 dsp_modulo
= ctrl1
[3];
1502 dsp_flags
= ctrl1
[4];
1503 dsp_matrix_control
= ctrl1
[5];
1504 dsp_pointer_to_matrix
= ctrl1
[6];
1505 dsp_data_organization
= ctrl1
[7];
1506 dsp_control
= ctrl1
[8];
1507 dsp_div_control
= ctrl1
[9];
1508 IMASKCleared
= ctrl1
[10];
1509 dsp_flag_z
= ctrl1
[11];
1510 dsp_flag_n
= ctrl1
[12];
1511 dsp_flag_c
= ctrl1
[13];
1512 DSPUpdateRegisterBanks();
1514 for(int k
=0; k
<2; k
++)
1516 // Decrement cycles based on non-pipelined core...
1517 instr1
= DSPReadWord(dsp_pc
, DSP
);
1518 cycles
-= dsp_opcode_cycles
[instr1
>> 10];
1520 //WriteLog("\tAbout to execute non-pipelined core on tick #%u (DSP_PC=%08X)...\n", (uint32_t)count, dsp_pc);
1521 DSPExec(1); // Do *one* instruction
1525 memcpy(ram1
, dsp_ram_8
, 0x2000);
1526 memcpy(regs1
, dsp_reg_bank_0
, 32 * 4);
1527 memcpy(®s1
[32], dsp_reg_bank_1
, 32 * 4);
1530 ctrl1
[2] = dsp_remain
;
1531 ctrl1
[3] = dsp_modulo
;
1532 ctrl1
[4] = dsp_flags
;
1533 ctrl1
[5] = dsp_matrix_control
;
1534 ctrl1
[6] = dsp_pointer_to_matrix
;
1535 ctrl1
[7] = dsp_data_organization
;
1536 ctrl1
[8] = dsp_control
;
1537 ctrl1
[9] = dsp_div_control
;
1538 ctrl1
[10] = IMASKCleared
;
1539 ctrl1
[11] = dsp_flag_z
;
1540 ctrl1
[12] = dsp_flag_n
;
1541 ctrl1
[13] = dsp_flag_c
;
1545 if (instr1
!= lastExec
)
1547 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count
);
1549 WriteLog("Instruction for non-pipelined core: %04X\n", instr1
);
1550 WriteLog("Instruction for pipelined core: %04X\n", lastExec
);
1563 // DSP execution core
1565 //static bool R20Set = false, tripwire = false;
1566 //static uint32_t pcQueue[32], ptrPCQ = 0;
1567 void DSPExec(int32_t cycles
)
1569 #ifdef DSP_SINGLE_STEPPING
1570 if (dsp_control
& 0x18)
1573 dsp_control
&= ~0x10;
1576 //There is *no* good reason to do this here!
1578 dsp_releaseTimeSlice_flag
= 0;
1581 while (cycles
> 0 && DSP_RUNNING
)
1583 /*extern uint32_t totalFrames;
1584 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
1585 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
1586 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
1588 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1591 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1593 if (dsp_pc == 0xF1B092)
1594 doDSPDis = false;//*/
1595 /*if (dsp_pc == 0xF1B140)
1596 doDSPDis = true;//*/
1598 if (IMASKCleared
) // If IMASK was cleared,
1600 #ifdef DSP_DEBUG_IRQ
1601 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc
);
1603 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1604 IMASKCleared
= false;
1609 WriteLog("\nDSP: Encountered bad write in Atari Synth module. PC=%08X, R15=%08X\n", dsp_pc, dsp_reg[15]);
1610 for(int i=0; i<80; i+=4)
1611 WriteLog(" %08X: %08X\n", dsp_reg[15]+i, JaguarReadLong(dsp_reg[15]+i));
1614 /*if (dsp_pc == 0xF1B55E)
1616 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1618 /*if (dsp_pc == 0xF1B7D2) // Start here???
1620 pcQueue[ptrPCQ++] = dsp_pc;
1622 uint16_t opcode
= DSPReadWord(dsp_pc
, DSP
);
1623 uint32_t index
= opcode
>> 10;
1624 dsp_opcode_first_parameter
= (opcode
>> 5) & 0x1F;
1625 dsp_opcode_second_parameter
= opcode
& 0x1F;
1627 dsp_opcode
[index
]();
1628 dsp_opcode_use
[index
]++;
1629 cycles
-= dsp_opcode_cycles
[index
];
1630 /*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1632 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1635 if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1637 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1639 DSPDumpDisassembly();
1642 if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1645 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1648 WriteLog("\nBacktrace:\n");
1649 for(int i=0; i<32; i++)
1651 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1652 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1663 // DSP opcode handlers
1666 // There is a problem here with interrupt handlers the JUMP and JR instructions that
1667 // can cause trouble because an interrupt can occur *before* the instruction following the
1668 // jump can execute... !!! FIX !!!
1669 static void dsp_opcode_jump(void)
1672 const char * condition
[32] =
1673 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1674 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1675 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1676 "???", "???", "???", "F" };
1678 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
);
1681 /* dsp_flag_c=dsp_flag_c?1:0;
1682 dsp_flag_z=dsp_flag_z?1:0;
1683 dsp_flag_n=dsp_flag_n?1:0;*/
1684 // KLUDGE: Used by BRANCH_CONDITION
1685 uint32_t jaguar_flags
= (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
;
1687 if (BRANCH_CONDITION(IMM_2
))
1691 WriteLog("Branched!\n");
1693 uint32_t delayed_pc
= RM
;
1695 dsp_pc
= delayed_pc
;
1700 WriteLog("Branch NOT taken.\n");
1705 static void dsp_opcode_jr(void)
1708 const char * condition
[32] =
1709 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
1710 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
1711 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
1712 "???", "???", "???", "F" };
1714 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
);
1717 /* dsp_flag_c=dsp_flag_c?1:0;
1718 dsp_flag_z=dsp_flag_z?1:0;
1719 dsp_flag_n=dsp_flag_n?1:0;*/
1720 // KLUDGE: Used by BRANCH_CONDITION
1721 uint32_t jaguar_flags
= (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
;
1723 if (BRANCH_CONDITION(IMM_2
))
1727 WriteLog("Branched!\n");
1729 int32_t offset
= (IMM_1
& 0x10 ? 0xFFFFFFF0 | IMM_1
: IMM_1
); // Sign extend IMM_1
1730 int32_t delayed_pc
= dsp_pc
+ (offset
* 2);
1732 dsp_pc
= delayed_pc
;
1737 WriteLog("Branch NOT taken.\n");
1742 static void dsp_opcode_add(void)
1746 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
);
1748 uint32_t res
= RN
+ RM
;
1749 SET_ZNC_ADD(RN
, RM
, res
);
1753 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_1
, RM
, IMM_2
, RN
);
1758 static void dsp_opcode_addc(void)
1762 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
);
1764 uint32_t res
= RN
+ RM
+ dsp_flag_c
;
1765 uint32_t carry
= dsp_flag_c
;
1766 // SET_ZNC_ADD(RN, RM, res); //???BUG??? Yes!
1767 SET_ZNC_ADD(RN
+ carry
, RM
, res
);
1768 // SET_ZNC_ADD(RN, RM + carry, res);
1772 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
);
1777 static void dsp_opcode_addq(void)
1781 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
);
1783 uint32_t r1
= dsp_convert_zero
[IMM_1
];
1784 uint32_t res
= RN
+ r1
;
1785 CLR_ZNC
; SET_ZNC_ADD(RN
, r1
, res
);
1789 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
1794 static void dsp_opcode_sub(void)
1798 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
);
1800 uint32_t res
= RN
- RM
;
1801 SET_ZNC_SUB(RN
, RM
, res
);
1805 WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_1
, RM
, IMM_2
, RN
);
1810 static void dsp_opcode_subc(void)
1814 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
);
1816 // This is how the DSP ALU does it--Two's complement with inverted carry
1817 uint64_t res
= (uint64_t)RN
+ (uint64_t)(RM
^ 0xFFFFFFFF) + (dsp_flag_c
^ 1);
1818 // Carry out of the result is inverted too
1819 dsp_flag_c
= ((res
>> 32) & 0x01) ^ 1;
1820 RN
= (res
& 0xFFFFFFFF);
1824 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
);
1829 static void dsp_opcode_subq(void)
1833 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
);
1835 uint32_t r1
= dsp_convert_zero
[IMM_1
];
1836 uint32_t res
= RN
- r1
;
1837 SET_ZNC_SUB(RN
, r1
, res
);
1841 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
1846 static void dsp_opcode_cmp(void)
1850 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
);
1852 uint32_t res
= RN
- RM
;
1853 SET_ZNC_SUB(RN
, RM
, res
);
1856 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
1861 static void dsp_opcode_cmpq(void)
1863 static int32_t sqtable
[32] =
1864 { 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 };
1867 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
);
1869 uint32_t r1
= sqtable
[IMM_1
& 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
1870 uint32_t res
= RN
- r1
;
1871 SET_ZNC_SUB(RN
, r1
, res
);
1874 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
1879 static void dsp_opcode_and(void)
1883 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
);
1889 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
);
1894 static void dsp_opcode_or(void)
1898 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
);
1904 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
);
1909 static void dsp_opcode_xor(void)
1913 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
);
1919 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
);
1924 static void dsp_opcode_not(void)
1928 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
);
1934 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
1939 static void dsp_opcode_move_pc(void)
1945 static void dsp_opcode_store_r14_indexed(void)
1947 #ifdef DSP_DIS_STORE14I
1949 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));
1951 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1952 DSPWriteLong((dsp_reg
[14] & 0xFFFFFFFC) + (dsp_convert_zero
[IMM_1
] << 2), RN
, DSP
);
1954 DSPWriteLong(dsp_reg
[14] + (dsp_convert_zero
[IMM_1
] << 2), RN
, DSP
);
1959 static void dsp_opcode_store_r15_indexed(void)
1961 #ifdef DSP_DIS_STORE15I
1963 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));
1965 #ifdef DSP_CORRECT_ALIGNMENT_STORE
1966 DSPWriteLong((dsp_reg
[15] & 0xFFFFFFFC) + (dsp_convert_zero
[IMM_1
] << 2), RN
, DSP
);
1968 DSPWriteLong(dsp_reg
[15] + (dsp_convert_zero
[IMM_1
] << 2), RN
, DSP
);
1973 static void dsp_opcode_load_r14_ri(void)
1975 #ifdef DSP_DIS_LOAD14R
1977 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
);
1979 #ifdef DSP_CORRECT_ALIGNMENT
1980 RN
= DSPReadLong((dsp_reg
[14] + RM
) & 0xFFFFFFFC, DSP
);
1982 RN
= DSPReadLong(dsp_reg
[14] + RM
, DSP
);
1984 #ifdef DSP_DIS_LOAD14R
1986 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
1991 static void dsp_opcode_load_r15_ri(void)
1993 #ifdef DSP_DIS_LOAD15R
1995 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
);
1997 #ifdef DSP_CORRECT_ALIGNMENT
1998 RN
= DSPReadLong((dsp_reg
[15] + RM
) & 0xFFFFFFFC, DSP
);
2000 RN
= DSPReadLong(dsp_reg
[15] + RM
, DSP
);
2002 #ifdef DSP_DIS_LOAD15R
2004 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2009 static void dsp_opcode_store_r14_ri(void)
2011 DSPWriteLong(dsp_reg
[14] + RM
, RN
, DSP
);
2015 static void dsp_opcode_store_r15_ri(void)
2017 DSPWriteLong(dsp_reg
[15] + RM
, RN
, DSP
);
2021 static void dsp_opcode_nop(void)
2025 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc
-2, dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
2030 static void dsp_opcode_storeb(void)
2032 #ifdef DSP_DIS_STOREB
2034 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
);
2036 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2037 DSPWriteLong(RM
, RN
& 0xFF, DSP
);
2039 JaguarWriteByte(RM
, RN
, DSP
);
2043 static void dsp_opcode_storew(void)
2045 #ifdef DSP_DIS_STOREW
2047 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
);
2049 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2050 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2051 DSPWriteLong(RM
& 0xFFFFFFFE, RN
& 0xFFFF, DSP
);
2053 JaguarWriteWord(RM
& 0xFFFFFFFE, RN
, DSP
);
2055 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2056 DSPWriteLong(RM
, RN
& 0xFFFF, DSP
);
2058 JaguarWriteWord(RM
, RN
, DSP
);
2063 static void dsp_opcode_store(void)
2065 #ifdef DSP_DIS_STORE
2067 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
);
2069 #ifdef DSP_CORRECT_ALIGNMENT_STORE
2070 DSPWriteLong(RM
& 0xFFFFFFFC, RN
, DSP
);
2072 DSPWriteLong(RM
, RN
, DSP
);
2077 static void dsp_opcode_loadb(void)
2079 #ifdef DSP_DIS_LOADB
2081 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
);
2083 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2084 RN
= DSPReadLong(RM
, DSP
) & 0xFF;
2086 RN
= JaguarReadByte(RM
, DSP
);
2087 #ifdef DSP_DIS_LOADB
2089 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2094 static void dsp_opcode_loadw(void)
2096 #ifdef DSP_DIS_LOADW
2098 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
);
2100 #ifdef DSP_CORRECT_ALIGNMENT
2101 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2102 RN
= DSPReadLong(RM
& 0xFFFFFFFE, DSP
) & 0xFFFF;
2104 RN
= JaguarReadWord(RM
& 0xFFFFFFFE, DSP
);
2106 if (RM
>= DSP_WORK_RAM_BASE
&& RM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
2107 RN
= DSPReadLong(RM
, DSP
) & 0xFFFF;
2109 RN
= JaguarReadWord(RM
, DSP
);
2111 #ifdef DSP_DIS_LOADW
2113 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_load(void)
2122 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
);
2124 #ifdef DSP_CORRECT_ALIGNMENT
2125 RN
= DSPReadLong(RM
& 0xFFFFFFFC, DSP
);
2127 RN
= DSPReadLong(RM
, DSP
);
2131 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2136 static void dsp_opcode_load_r14_indexed(void)
2138 #ifdef DSP_DIS_LOAD14I
2140 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
);
2142 #ifdef DSP_CORRECT_ALIGNMENT
2143 RN
= DSPReadLong((dsp_reg
[14] & 0xFFFFFFFC) + (dsp_convert_zero
[IMM_1
] << 2), DSP
);
2145 RN
= DSPReadLong(dsp_reg
[14] + (dsp_convert_zero
[IMM_1
] << 2), DSP
);
2147 #ifdef DSP_DIS_LOAD14I
2149 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2154 static void dsp_opcode_load_r15_indexed(void)
2156 #ifdef DSP_DIS_LOAD15I
2158 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
);
2160 #ifdef DSP_CORRECT_ALIGNMENT
2161 RN
= DSPReadLong((dsp_reg
[15] & 0xFFFFFFFC) + (dsp_convert_zero
[IMM_1
] << 2), DSP
);
2163 RN
= DSPReadLong(dsp_reg
[15] + (dsp_convert_zero
[IMM_1
] << 2), DSP
);
2165 #ifdef DSP_DIS_LOAD15I
2167 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2172 static void dsp_opcode_movei(void)
2174 #ifdef DSP_DIS_MOVEI
2176 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
);
2178 // This instruction is followed by 32-bit value in LSW / MSW format...
2179 RN
= (uint32_t)DSPReadWord(dsp_pc
, DSP
) | ((uint32_t)DSPReadWord(dsp_pc
+ 2, DSP
) << 16);
2181 #ifdef DSP_DIS_MOVEI
2183 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2188 static void dsp_opcode_moveta(void)
2190 #ifdef DSP_DIS_MOVETA
2192 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
);
2195 #ifdef DSP_DIS_MOVETA
2197 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
);
2202 static void dsp_opcode_movefa(void)
2204 #ifdef DSP_DIS_MOVEFA
2206 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
);
2209 #ifdef DSP_DIS_MOVEFA
2211 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
);
2216 static void dsp_opcode_move(void)
2220 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
);
2225 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
);
2230 static void dsp_opcode_moveq(void)
2232 #ifdef DSP_DIS_MOVEQ
2234 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
);
2237 #ifdef DSP_DIS_MOVEQ
2239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2244 static void dsp_opcode_resmac(void)
2246 #ifdef DSP_DIS_RESMAC
2248 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));
2250 RN
= (uint32_t)dsp_acc
;
2251 #ifdef DSP_DIS_RESMAC
2253 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2258 static void dsp_opcode_imult(void)
2260 #ifdef DSP_DIS_IMULT
2262 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
);
2264 RN
= (int16_t)RN
* (int16_t)RM
;
2266 #ifdef DSP_DIS_IMULT
2268 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
);
2273 static void dsp_opcode_mult(void)
2277 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
);
2279 RN
= (uint16_t)RM
* (uint16_t)RN
;
2283 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
);
2288 static void dsp_opcode_bclr(void)
2292 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
);
2294 uint32_t res
= RN
& ~(1 << IMM_1
);
2299 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2304 static void dsp_opcode_btst(void)
2308 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
);
2310 dsp_flag_z
= (~RN
>> IMM_1
) & 1;
2313 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2318 static void dsp_opcode_bset(void)
2322 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
);
2324 uint32_t res
= RN
| (1 << IMM_1
);
2329 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2334 static void dsp_opcode_subqt(void)
2336 #ifdef DSP_DIS_SUBQT
2338 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
);
2340 RN
-= dsp_convert_zero
[IMM_1
];
2341 #ifdef DSP_DIS_SUBQT
2343 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2348 static void dsp_opcode_addqt(void)
2350 #ifdef DSP_DIS_ADDQT
2352 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
);
2354 RN
+= dsp_convert_zero
[IMM_1
];
2355 #ifdef DSP_DIS_ADDQT
2357 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2362 static void dsp_opcode_imacn(void)
2364 #ifdef DSP_DIS_IMACN
2366 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
);
2368 int32_t res
= (int16_t)RM
* (int16_t)RN
;
2369 dsp_acc
+= (int64_t)res
;
2370 //Should we AND the result to fit into 40 bits here???
2371 #ifdef DSP_DIS_IMACN
2373 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));
2378 static void dsp_opcode_mtoi(void)
2380 RN
= (((int32_t)RM
>> 8) & 0xFF800000) | (RM
& 0x007FFFFF);
2385 static void dsp_opcode_normi(void)
2392 while ((_Rm
& 0xffc00000) == 0)
2397 while ((_Rm
& 0xff800000) != 0)
2408 static void dsp_opcode_mmult(void)
2410 int count
= dsp_matrix_control
&0x0f;
2411 uint32_t addr
= dsp_pointer_to_matrix
; // in the dsp ram
2415 if (!(dsp_matrix_control
& 0x10))
2417 for (int i
= 0; i
< count
; i
++)
2421 a
=(int16_t)((dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]>>16)&0xffff);
2423 a
=(int16_t)(dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]&0xffff);
2424 int16_t b
=((int16_t)DSPReadWord(addr
+ 2, DSP
));
2431 for (int i
= 0; i
< count
; i
++)
2435 a
=(int16_t)((dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]>>16)&0xffff);
2437 a
=(int16_t)(dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]&0xffff);
2438 int16_t b
=((int16_t)DSPReadWord(addr
+ 2, DSP
));
2443 RN
= res
= (int32_t)accum
;
2445 //NOTE: The flags are set based upon the last add/multiply done...
2450 static void dsp_opcode_abs(void)
2454 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
);
2459 if (_Rn
== 0x80000000)
2463 dsp_flag_c
= ((_Rn
& 0x80000000) >> 31);
2464 res
= RN
= (_Rn
& 0x80000000 ? -_Rn
: _Rn
);
2469 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2474 static void dsp_opcode_div(void)
2479 if (dsp_div_control
& 0x01) // 16.16 division
2481 dsp_remain
= ((uint64_t)RN
<< 16) % RM
;
2482 RN
= ((uint64_t)RN
<< 16) / RM
;
2486 // We calculate the remainder first because we destroy RN after
2487 // this by assigning it to itself.
2488 dsp_remain
= RN
% RM
;
2495 // This is what happens according to SCPCD. NYAN!
2500 // Real algorithm, courtesy of SCPCD: NYAN!
2504 // If 16.16 division, stuff top 16 bits of RN into remainder and put the
2505 // bottom 16 of RN in top 16 of quotient
2506 if (dsp_div_control
& 0x01)
2507 q
<<= 16, r
= RN
>> 16;
2509 for(int i
=0; i
<32; i
++)
2511 // uint32_t sign = (r >> 31) & 0x01;
2512 uint32_t sign
= r
& 0x80000000;
2513 r
= (r
<< 1) | ((q
>> 31) & 0x01);
2514 r
+= (sign
? RM
: -RM
);
2515 q
= (q
<< 1) | (((~r
) >> 31) & 0x01);
2524 static void dsp_opcode_imultn(void)
2526 #ifdef DSP_DIS_IMULTN
2528 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
);
2530 // This is OK, since this multiply won't overflow 32 bits...
2531 int32_t res
= (int32_t)((int16_t)RN
* (int16_t)RM
);
2532 dsp_acc
= (int64_t)res
;
2534 #ifdef DSP_DIS_IMULTN
2536 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));
2541 static void dsp_opcode_neg(void)
2545 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
);
2548 SET_ZNC_SUB(0, RN
, res
);
2552 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2557 static void dsp_opcode_shlq(void)
2561 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
);
2563 // NB: This instruction is the *only* one that does (32 - immediate data).
2564 int32_t r1
= 32 - IMM_1
;
2565 uint32_t res
= RN
<< r1
;
2566 SET_ZN(res
); dsp_flag_c
= (RN
>> 31) & 1;
2570 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2575 static void dsp_opcode_shrq(void)
2579 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
);
2581 int32_t r1
= dsp_convert_zero
[IMM_1
];
2582 uint32_t res
= RN
>> r1
;
2583 SET_ZN(res
); dsp_flag_c
= RN
& 1;
2587 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2592 static void dsp_opcode_ror(void)
2596 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
);
2598 uint32_t r1
= RM
& 0x1F;
2599 uint32_t res
= (RN
>> r1
) | (RN
<< (32 - r1
));
2600 SET_ZN(res
); dsp_flag_c
= (RN
>> 31) & 1;
2604 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
);
2609 static void dsp_opcode_rorq(void)
2613 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
);
2615 uint32_t r1
= dsp_convert_zero
[IMM_1
& 0x1F];
2617 uint32_t res
= (r2
>> r1
) | (r2
<< (32 - r1
));
2619 SET_ZN(res
); dsp_flag_c
= (r2
>> 31) & 0x01;
2622 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2627 static void dsp_opcode_sha(void)
2629 int32_t sRm
=(int32_t)RM
;
2634 uint32_t shift
=-sRm
;
2635 if (shift
>=32) shift
=32;
2636 dsp_flag_c
=(_Rn
&0x80000000)>>31;
2646 if (shift
>=32) shift
=32;
2650 _Rn
=((int32_t)_Rn
)>>1;
2659 static void dsp_opcode_sharq(void)
2661 #ifdef DSP_DIS_SHARQ
2663 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
);
2665 uint32_t res
= (int32_t)RN
>> dsp_convert_zero
[IMM_1
];
2666 SET_ZN(res
); dsp_flag_c
= RN
& 0x01;
2668 #ifdef DSP_DIS_SHARQ
2670 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2675 static void dsp_opcode_sh(void)
2677 int32_t sRm
=(int32_t)RM
;
2682 uint32_t shift
=(-sRm
);
2683 if (shift
>=32) shift
=32;
2684 dsp_flag_c
=(_Rn
&0x80000000)>>31;
2694 if (shift
>=32) shift
=32;
2706 void dsp_opcode_addqmod(void)
2708 #ifdef DSP_DIS_ADDQMOD
2710 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
);
2712 uint32_t r1
= dsp_convert_zero
[IMM_1
];
2714 uint32_t res
= r2
+ r1
;
2715 res
= (res
& (~dsp_modulo
)) | (r2
& dsp_modulo
);
2717 SET_ZNC_ADD(r2
, r1
, res
);
2718 #ifdef DSP_DIS_ADDQMOD
2720 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, IMM_2
, RN
);
2724 void dsp_opcode_subqmod(void)
2726 uint32_t r1
= dsp_convert_zero
[IMM_1
];
2728 uint32_t res
= r2
- r1
;
2729 res
= (res
& (~dsp_modulo
)) | (r2
& dsp_modulo
);
2732 SET_ZNC_SUB(r2
, r1
, res
);
2735 void dsp_opcode_mirror(void)
2738 RN
= (mirror_table
[r1
& 0xFFFF] << 16) | mirror_table
[r1
>> 16];
2742 void dsp_opcode_sat32s(void)
2744 int32_t r2
= (uint32_t)RN
;
2745 int32_t temp
= dsp_acc
>> 32;
2746 uint32_t res
= (temp
< -1) ? (int32_t)0x80000000 : (temp
> 0) ? (int32_t)0x7FFFFFFF : r2
;
2751 void dsp_opcode_sat16s(void)
2754 uint32_t res
= (r2
< -32768) ? -32768 : (r2
> 32767) ? 32767 : r2
;
2759 void dsp_opcode_illegal(void)
2761 // Don't know what it does, but it does *something*...
2762 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
);
2766 // New pipelined DSP core
2769 static void DSP_abs(void);
2770 static void DSP_add(void);
2771 static void DSP_addc(void);
2772 static void DSP_addq(void);
2773 static void DSP_addqmod(void);
2774 static void DSP_addqt(void);
2775 static void DSP_and(void);
2776 static void DSP_bclr(void);
2777 static void DSP_bset(void);
2778 static void DSP_btst(void);
2779 static void DSP_cmp(void);
2780 static void DSP_cmpq(void);
2781 static void DSP_div(void);
2782 static void DSP_imacn(void);
2783 static void DSP_imult(void);
2784 static void DSP_imultn(void);
2785 static void DSP_illegal(void);
2786 static void DSP_jr(void);
2787 static void DSP_jump(void);
2788 static void DSP_load(void);
2789 static void DSP_loadb(void);
2790 static void DSP_loadw(void);
2791 static void DSP_load_r14_i(void);
2792 static void DSP_load_r14_r(void);
2793 static void DSP_load_r15_i(void);
2794 static void DSP_load_r15_r(void);
2795 static void DSP_mirror(void);
2796 static void DSP_mmult(void);
2797 static void DSP_move(void);
2798 static void DSP_movefa(void);
2799 static void DSP_movei(void);
2800 static void DSP_movepc(void);
2801 static void DSP_moveq(void);
2802 static void DSP_moveta(void);
2803 static void DSP_mtoi(void);
2804 static void DSP_mult(void);
2805 static void DSP_neg(void);
2806 static void DSP_nop(void);
2807 static void DSP_normi(void);
2808 static void DSP_not(void);
2809 static void DSP_or(void);
2810 static void DSP_resmac(void);
2811 static void DSP_ror(void);
2812 static void DSP_rorq(void);
2813 static void DSP_sat16s(void);
2814 static void DSP_sat32s(void);
2815 static void DSP_sh(void);
2816 static void DSP_sha(void);
2817 static void DSP_sharq(void);
2818 static void DSP_shlq(void);
2819 static void DSP_shrq(void);
2820 static void DSP_store(void);
2821 static void DSP_storeb(void);
2822 static void DSP_storew(void);
2823 static void DSP_store_r14_i(void);
2824 static void DSP_store_r14_r(void);
2825 static void DSP_store_r15_i(void);
2826 static void DSP_store_r15_r(void);
2827 static void DSP_sub(void);
2828 static void DSP_subc(void);
2829 static void DSP_subq(void);
2830 static void DSP_subqmod(void);
2831 static void DSP_subqt(void);
2832 static void DSP_xor(void);
2834 void (* DSPOpcode
[64])() =
2836 DSP_add
, DSP_addc
, DSP_addq
, DSP_addqt
,
2837 DSP_sub
, DSP_subc
, DSP_subq
, DSP_subqt
,
2838 DSP_neg
, DSP_and
, DSP_or
, DSP_xor
,
2839 DSP_not
, DSP_btst
, DSP_bset
, DSP_bclr
,
2841 DSP_mult
, DSP_imult
, DSP_imultn
, DSP_resmac
,
2842 DSP_imacn
, DSP_div
, DSP_abs
, DSP_sh
,
2843 DSP_shlq
, DSP_shrq
, DSP_sha
, DSP_sharq
,
2844 DSP_ror
, DSP_rorq
, DSP_cmp
, DSP_cmpq
,
2846 DSP_subqmod
, DSP_sat16s
, DSP_move
, DSP_moveq
,
2847 DSP_moveta
, DSP_movefa
, DSP_movei
, DSP_loadb
,
2848 DSP_loadw
, DSP_load
, DSP_sat32s
, DSP_load_r14_i
,
2849 DSP_load_r15_i
, DSP_storeb
, DSP_storew
, DSP_store
,
2851 DSP_mirror
, DSP_store_r14_i
, DSP_store_r15_i
, DSP_movepc
,
2852 DSP_jump
, DSP_jr
, DSP_mmult
, DSP_mtoi
,
2853 DSP_normi
, DSP_nop
, DSP_load_r14_r
, DSP_load_r15_r
,
2854 DSP_store_r14_r
, DSP_store_r15_r
, DSP_illegal
, DSP_addqmod
2857 bool readAffected
[64][2] =
2859 { true, true}, { true, true}, {false, true}, {false, true},
2860 { true, true}, { true, true}, {false, true}, {false, true},
2861 {false, true}, { true, true}, { true, true}, { true, true},
2862 {false, true}, {false, true}, {false, true}, {false, true},
2864 { true, true}, { true, true}, { true, true}, {false, true},
2865 { true, true}, { true, true}, {false, true}, { true, true},
2866 {false, true}, {false, true}, { true, true}, {false, true},
2867 { true, true}, {false, true}, { true, true}, {false, true},
2869 {false, true}, {false, true}, { true, false}, {false, false},
2870 { true, false}, {false, false}, {false, false}, { true, false},
2871 { true, false}, { true, false}, {false, true}, { true, false},
2872 { true, false}, { true, true}, { true, true}, { true, true},
2874 {false, true}, { true, true}, { true, true}, {false, true},
2875 { true, false}, { true, false}, { true, true}, { true, false},
2876 { true, false}, {false, false}, { true, false}, { true, false},
2877 { true, true}, { true, true}, {false, false}, {false, true}
2880 bool isLoadStore
[65] =
2882 false, false, false, false, false, false, false, false,
2883 false, false, false, false, false, false, false, false,
2885 false, false, false, false, false, false, false, false,
2886 false, false, false, false, false, false, false, false,
2888 false, false, false, false, false, false, false, true,
2889 true, true, false, true, true, true, true, true,
2891 false, true, true, false, false, false, false, false,
2892 false, false, true, true, true, true, false, false, false
2895 void FlushDSPPipeline(void)
2897 plPtrFetch
= 3, plPtrRead
= 2, plPtrExec
= 1, plPtrWrite
= 0;
2899 for(int i
=0; i
<4; i
++)
2900 pipeline
[i
].opcode
= PIPELINE_STALL
;
2902 for(int i
=0; i
<32; i
++)
2907 // New pipelined DSP execution core
2909 /*void DSPExecP(int32_t cycles)
2911 // bool inhibitFetch = false;
2913 dsp_releaseTimeSlice_flag = 0;
2916 while (cycles > 0 && DSP_RUNNING)
2918 WriteLog("DSPExecP: Pipeline status...\n");
2919 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);
2920 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);
2921 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);
2922 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);
2923 WriteLog(" --> Scoreboard: ");
2924 for(int i=0; i<32; i++)
2925 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2927 // Stage 1: Instruction fetch
2928 // if (!inhibitFetch)
2930 pipeline[plPtrFetch].instruction = DSPReadWord(dsp_pc, DSP);
2931 pipeline[plPtrFetch].opcode = pipeline[plPtrFetch].instruction >> 10;
2932 pipeline[plPtrFetch].operand1 = (pipeline[plPtrFetch].instruction >> 5) & 0x1F;
2933 pipeline[plPtrFetch].operand2 = pipeline[plPtrFetch].instruction & 0x1F;
2934 if (pipeline[plPtrFetch].opcode == 38)
2935 pipeline[plPtrFetch].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
2936 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
2939 // inhibitFetch = false;
2940 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2942 WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2943 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);
2944 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);
2945 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);
2946 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);
2947 // Stage 2: Read registers
2948 //Ok, stalls here depend on whether or not the instruction reads two registers or not
2949 //and *which* register (1 or 2) is the one being read... !!! FIX !!!
2950 if (scoreboard[pipeline[plPtrRead].operand2])
2951 && pipeline[plPtrRead].opcode != PIPELINE_STALL)
2952 // We have a hit in the scoreboard, so we have to stall the pipeline...
2954 //This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2955 // dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2956 WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2957 pipeline[plPtrFetch] = pipeline[plPtrRead];
2958 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2962 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
2963 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
2964 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
2966 if (pipeline[plPtrRead].opcode != PIPELINE_STALL)
2967 // Shouldn't we be more selective with the register scoreboarding?
2968 // Yes, we should. !!! FIX !!!
2969 scoreboard[pipeline[plPtrRead].operand2] = true;
2970 //Advance PC here??? Yes.
2971 // dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2972 //This is a mangling of the pipeline stages, but what else to do???
2973 dsp_pc += (pipeline[plPtrFetch].opcode == 38 ? 6 : 2);
2976 WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2977 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);
2978 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);
2979 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);
2980 WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u \n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister);
2982 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2984 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
2985 DSPOpcode[pipeline[plPtrExec].opcode]();
2986 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
2987 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
2992 WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2993 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);
2994 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);
2995 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);
2996 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);
2997 // Stage 4: Write back register
2998 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3000 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3001 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3003 scoreboard[pipeline[plPtrWrite].operand1]
3004 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3007 // Push instructions through the pipeline...
3008 plPtrFetch = (++plPtrFetch) & 0x03;
3009 plPtrRead = (++plPtrRead) & 0x03;
3010 plPtrExec = (++plPtrExec) & 0x03;
3011 plPtrWrite = (++plPtrWrite) & 0x03;
3018 //Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3020 // Should be fixed now. Another problem is figuring how to do the sequence following
3021 // a branch followed with the JR & JUMP instructions...
3023 // There are two conflicting problems:
3026 F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3027 F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3028 F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3029 F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3030 F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3031 F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3032 F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3033 F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3034 F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3035 DSP: Writing 00004431 to DSP_FLAGS by DSP...
3036 DSP: Finished interrupt.
3037 ; Without pipeline effects, the value in R03 is erroneously read from bank 1 instead of
3038 ; bank 0 (where is was prepared)!
3039 F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3040 F1B252: NOP [NCZ:001]
3043 // The other is when you see this at the end of an IRQ:
3046 JUMP T, (R29) ; R29 = Previous stack + 2
3047 STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3049 ; Actually, this is OK if we do the atomic JUMP/JR operation correctly:
3050 ; 1) The STORE goes through the pipeline and is executed/written back
3051 ; 2) The pipeline is flushed
3052 ; 3) The DSP_PC is set to the new address
3053 ; 4) Execution resumes
3055 JUMP T, (R25) ; Oops! Because of pipeline effects R25 has the value from
3056 ; bank 0 instead of the current bank 1 and so goes astray!
3059 //One other thing: Since these stages are supposed to happen simulaneously, try executing
3060 //them in reverse order to see if that reduces pipeline stalls from late writebacks...
3064 Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3065 follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3066 because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3067 If it were done properly, the STORE write back would occur *after* (well, technically,
3068 during) the execution of the the JUMP that follows it.
3072 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3073 F1B08A: NOP [NCZ:001]
3075 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3078 F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3081 F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3082 F1B08A: JR z, F1B082 [NCZ:001] Branched!
3083 F1B08A: NOP [NCZ:001]
3085 F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3088 Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3089 DSP: CPU -> DSP interrupt
3090 DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3091 Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3093 F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3096 F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3097 F1B006: NOP [NCZ:001]
3099 F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3102 F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3103 F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3106 F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3107 F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3110 F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3111 F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3114 F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3115 F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3118 F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3121 F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3124 F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3125 F1B0FE: NOP [NCZ:000]
3127 F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3130 F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3133 F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3134 F1B138: NOP [NCZ:000]
3136 F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3139 F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3140 F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3141 F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3144 F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3145 F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3148 F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3149 F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3150 F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3152 F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3153 F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3156 F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3157 DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3158 DSP: Finished interrupt.
3159 DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3161 F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3164 F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3165 F1B016: NOP [NCZ:001]
3167 F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3170 uint32_t pcQueue1
[0x400];
3171 uint32_t pcQPtr1
= 0;
3172 static uint32_t prevR1
;
3173 //Let's try a 3 stage pipeline....
3174 //Looks like 3 stage is correct, otherwise bad things happen...
3175 void DSPExecP2(int32_t cycles
)
3177 dsp_releaseTimeSlice_flag
= 0;
3180 while (cycles
> 0 && DSP_RUNNING
)
3182 /*extern uint32_t totalFrames;
3183 //F1B2F6: LOAD (R14+$04), R24 [NCZ:001, R14+$04=00F20018, R24=FFFFFFFF] -> Jaguar: Unknown word read at 00F20018 by DSP (M68K PC=00E32E)
3184 //-> 43 + 1 + 24 -> $2B + $01 + $18 -> 101011 00001 11000 -> 1010 1100 0011 1000 -> AC38
3185 //C470 -> 1100 0100 0111 0000 -> 110001 00011 10000 -> 49, 3, 16 -> STORE R16, (R14+$0C)
3187 if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3190 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3192 if (dsp_pc == 0xF1B092)
3193 doDSPDis = false;//*/
3194 /*if (totalFrames >= 373 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38)
3195 doDSPDis = true;//*/
3196 /*if (totalFrames >= 373 && dsp_pc == 0xF1B0A0)
3197 doDSPDis = true;//*/
3198 /*if (dsp_pc == 0xF1B0A0)
3199 doDSPDis = true;//*/
3200 /*if (dsp_pc == 0xF1B0D2) && dsp_reg[1] == 0x2140C)
3201 doDSPDis = true;//*/
3202 //Two parter... (not sure how to write this)
3203 //if (dsp_pc == 0xF1B0D2)
3204 // prevR1 = dsp_reg[1];
3206 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3207 //F1B0D2: ADDQT #8, R01 [NCZ:000, R01=0002140C] -> [NCZ:000, R01=00021414]
3210 pcQueue1
[pcQPtr1
++] = dsp_pc
;
3213 #ifdef DSP_DEBUG_PL2
3214 if ((dsp_pc
< 0xF1B000 || dsp_pc
> 0xF1CFFF) && !doDSPDis
)
3216 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3221 for(int i
=0; i
<0x400; i
++)
3223 dasmjag(JAGUAR_DSP
, buffer
, pcQueue1
[(i
+ pcQPtr1
) & 0x3FF]);
3224 WriteLog("\t%08X: %s\n", pcQueue1
[(i
+ pcQPtr1
) & 0x3FF], buffer
);
3230 if (IMASKCleared
) // If IMASK was cleared,
3232 #ifdef DSP_DEBUG_IRQ
3233 WriteLog("DSP: Finished interrupt.\n");
3235 DSPHandleIRQs(); // See if any other interrupts are pending!
3236 IMASKCleared
= false;
3239 //if (dsp_flags & REGPAGE)
3240 // WriteLog(" --> REGPAGE has just been set!\n");
3241 #ifdef DSP_DEBUG_PL2
3244 WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc
);
3245 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
]);
3246 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
]);
3247 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
]);
3248 WriteLog(" --> Scoreboard: ");
3249 for(int i
=0; i
<32; i
++)
3250 WriteLog("%s ", scoreboard
[i
] ? "T" : "F");
3254 // Stage 1a: Instruction fetch
3255 pipeline
[plPtrRead
].instruction
= DSPReadWord(dsp_pc
, DSP
);
3256 pipeline
[plPtrRead
].opcode
= pipeline
[plPtrRead
].instruction
>> 10;
3257 pipeline
[plPtrRead
].operand1
= (pipeline
[plPtrRead
].instruction
>> 5) & 0x1F;
3258 pipeline
[plPtrRead
].operand2
= pipeline
[plPtrRead
].instruction
& 0x1F;
3259 if (pipeline
[plPtrRead
].opcode
== 38)
3260 pipeline
[plPtrRead
].result
= (uint32_t)DSPReadWord(dsp_pc
+ 2, DSP
)
3261 | ((uint32_t)DSPReadWord(dsp_pc
+ 4, DSP
) << 16);
3262 #ifdef DSP_DEBUG_PL2
3265 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline
[plPtrRead
].instruction
, dsp_pc
);
3266 WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc
);
3267 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
]);
3268 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
]);
3269 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
]);
3272 // Stage 1b: Read registers
3273 //Small problem--when say LOAD or STORE (R14/5+$nn) is executed AFTER an instruction that
3274 //modifies R14/5, we don't check the scoreboard for R14/5 (and we need to!)... !!! FIX !!!
3276 //Another problem: Any sequential combination of LOAD and STORE operations will cause the
3277 //pipeline to stall, and we don't take care of that here. !!! FIX !!!
3278 if ((scoreboard
[pipeline
[plPtrRead
].operand1
] && readAffected
[pipeline
[plPtrRead
].opcode
][0])
3279 || (scoreboard
[pipeline
[plPtrRead
].operand2
] && readAffected
[pipeline
[plPtrRead
].opcode
][1])
3280 || ((pipeline
[plPtrRead
].opcode
== 43 || pipeline
[plPtrRead
].opcode
== 58) && scoreboard
[14])
3281 || ((pipeline
[plPtrRead
].opcode
== 44 || pipeline
[plPtrRead
].opcode
== 59) && scoreboard
[15])
3282 //Not sure that this is the best way to fix the LOAD/STORE problem... But it seems to
3284 || (isLoadStore
[pipeline
[plPtrRead
].opcode
] && isLoadStore
[pipeline
[plPtrExec
].opcode
]))
3285 // We have a hit in the scoreboard, so we have to stall the pipeline...
3286 #ifdef DSP_DEBUG_PL2
3290 WriteLog(" --> Stalling pipeline: ");
3291 if (readAffected
[pipeline
[plPtrRead
].opcode
][0])
3292 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline
[plPtrRead
].operand1
, scoreboard
[pipeline
[plPtrRead
].operand1
] ? "true" : "false");
3293 if (readAffected
[pipeline
[plPtrRead
].opcode
][1])
3294 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline
[plPtrRead
].operand2
, scoreboard
[pipeline
[plPtrRead
].operand2
] ? "true" : "false");
3298 pipeline
[plPtrRead
].opcode
= PIPELINE_STALL
;
3299 #ifdef DSP_DEBUG_PL2
3304 pipeline
[plPtrRead
].reg1
= dsp_reg
[pipeline
[plPtrRead
].operand1
];
3305 pipeline
[plPtrRead
].reg2
= dsp_reg
[pipeline
[plPtrRead
].operand2
];
3306 pipeline
[plPtrRead
].writebackRegister
= pipeline
[plPtrRead
].operand2
; // Set it to RN
3308 // Shouldn't we be more selective with the register scoreboarding?
3309 // Yes, we should. !!! FIX !!! Kinda [DONE]
3310 #ifndef NEW_SCOREBOARD
3311 scoreboard
[pipeline
[plPtrRead
].operand2
] = affectsScoreboard
[pipeline
[plPtrRead
].opcode
];
3313 //Hopefully this will fix the dual MOVEQ # problem...
3314 scoreboard
[pipeline
[plPtrRead
].operand2
] += (affectsScoreboard
[pipeline
[plPtrRead
].opcode
] ? 1 : 0);
3317 //Advance PC here??? Yes.
3318 dsp_pc
+= (pipeline
[plPtrRead
].opcode
== 38 ? 6 : 2);
3321 #ifdef DSP_DEBUG_PL2
3324 WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc
);
3325 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
]);
3326 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
]);
3327 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
]);
3331 if (pipeline
[plPtrExec
].opcode
!= PIPELINE_STALL
)
3333 #ifdef DSP_DEBUG_PL2
3335 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"));
3339 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str
[pipeline
[plPtrExec
].opcode
]);
3344 lastExec
= pipeline
[plPtrExec
].instruction
;
3345 //WriteLog("[lastExec = %04X]\n", lastExec);
3347 cycles
-= dsp_opcode_cycles
[pipeline
[plPtrExec
].opcode
];
3348 dsp_opcode_use
[pipeline
[plPtrExec
].opcode
]++;
3349 DSPOpcode
[pipeline
[plPtrExec
].opcode
]();
3350 //WriteLog(" --> Returned from execute. DSP_PC: %08X\n", dsp_pc);
3354 //Let's not, until we do the stalling correctly...
3355 //But, we gotta while we're doing the comparison core...!
3356 //Or do we? cycles--;
3357 //Really, the whole thing is wrong. When the pipeline is correctly stuffed, most instructions
3358 //will execute in one clock cycle (others, like DIV, will likely not). So, the challenge is
3359 //to model this clock cycle behavior correctly...
3360 //Also, the pipeline stalls too much--mostly because the transparent writebacks at stage 3
3361 //don't affect the reads at stage 1...
3362 #ifdef DSP_DEBUG_STALL
3364 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc
);
3368 #ifdef DSP_DEBUG_PL2
3371 WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc
);
3372 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
]);
3373 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
]);
3374 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
]);
3378 // Stage 3: Write back register/memory address
3379 if (pipeline
[plPtrWrite
].opcode
!= PIPELINE_STALL
)
3381 /*if (pipeline[plPtrWrite].writebackRegister == 3
3382 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3385 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3388 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFF)
3390 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFE)
3391 dsp_reg
[pipeline
[plPtrWrite
].writebackRegister
] = pipeline
[plPtrWrite
].result
;
3394 if (pipeline
[plPtrWrite
].type
== TYPE_BYTE
)
3395 JaguarWriteByte(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3396 else if (pipeline
[plPtrWrite
].type
== TYPE_WORD
)
3397 JaguarWriteWord(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3399 JaguarWriteLong(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3403 #ifndef NEW_SCOREBOARD
3404 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3405 scoreboard
[pipeline
[plPtrWrite
].operand2
] = false;
3407 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3408 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3409 if (scoreboard
[pipeline
[plPtrWrite
].operand2
])
3410 scoreboard
[pipeline
[plPtrWrite
].operand2
]--;
3414 // Push instructions through the pipeline...
3415 plPtrRead
= (++plPtrRead
) & 0x03;
3416 plPtrExec
= (++plPtrExec
) & 0x03;
3417 plPtrWrite
= (++plPtrWrite
) & 0x03;
3426 //#define DSP_DEBUG_PL3
3427 //Let's try a 2 stage pipeline....
3428 void DSPExecP3(int32_t cycles)
3430 dsp_releaseTimeSlice_flag = 0;
3433 while (cycles > 0 && DSP_RUNNING)
3435 //if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3437 #ifdef DSP_DEBUG_PL3
3438 WriteLog("DSPExecP: Pipeline status...\n");
3439 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]);
3440 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3441 WriteLog(" --> Scoreboard: ");
3442 for(int i=0; i<32; i++)
3443 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3446 // Stage 1a: Instruction fetch
3447 pipeline[plPtrRead].instruction = DSPReadWord(dsp_pc, DSP);
3448 pipeline[plPtrRead].opcode = pipeline[plPtrRead].instruction >> 10;
3449 pipeline[plPtrRead].operand1 = (pipeline[plPtrRead].instruction >> 5) & 0x1F;
3450 pipeline[plPtrRead].operand2 = pipeline[plPtrRead].instruction & 0x1F;
3451 if (pipeline[plPtrRead].opcode == 38)
3452 pipeline[plPtrRead].result = (uint32_t)DSPReadWord(dsp_pc + 2, DSP)
3453 | ((uint32_t)DSPReadWord(dsp_pc + 4, DSP) << 16);
3454 #ifdef DSP_DEBUG_PL3
3455 WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3456 WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3457 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]);
3458 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]);
3460 // Stage 1b: Read registers
3461 if ((scoreboard[pipeline[plPtrRead].operand1] && readAffected[pipeline[plPtrRead].opcode][0])
3462 || (scoreboard[pipeline[plPtrRead].operand2] && readAffected[pipeline[plPtrRead].opcode][1]))
3463 // We have a hit in the scoreboard, so we have to stall the pipeline...
3464 #ifdef DSP_DEBUG_PL3
3466 WriteLog(" --> Stalling pipeline: ");
3467 if (readAffected[pipeline[plPtrRead].opcode][0])
3468 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3469 if (readAffected[pipeline[plPtrRead].opcode][1])
3470 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3473 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3474 #ifdef DSP_DEBUG_PL3
3479 pipeline[plPtrRead].reg1 = dsp_reg[pipeline[plPtrRead].operand1];
3480 pipeline[plPtrRead].reg2 = dsp_reg[pipeline[plPtrRead].operand2];
3481 pipeline[plPtrRead].writebackRegister = pipeline[plPtrRead].operand2; // Set it to RN
3483 // Shouldn't we be more selective with the register scoreboarding?
3484 // Yes, we should. !!! FIX !!! [Kinda DONE]
3485 scoreboard[pipeline[plPtrRead].operand2] = affectsScoreboard[pipeline[plPtrRead].opcode];
3487 //Advance PC here??? Yes.
3488 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3491 #ifdef DSP_DEBUG_PL3
3492 WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3493 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]);
3494 WriteLog("\tE/W -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrExec].opcode, pipeline[plPtrExec].operand1, pipeline[plPtrExec].operand2, pipeline[plPtrExec].reg1, pipeline[plPtrExec].reg2, pipeline[plPtrExec].result, pipeline[plPtrExec].writebackRegister, dsp_opcode_str[pipeline[plPtrExec].opcode]);
3496 // Stage 2a: Execute
3497 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3499 #ifdef DSP_DEBUG_PL3
3500 WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3502 DSPOpcode[pipeline[plPtrExec].opcode]();
3503 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3504 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3509 #ifdef DSP_DEBUG_PL3
3510 WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3511 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]);
3512 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]);
3515 // Stage 2b: Write back register
3516 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3518 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3519 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3521 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3522 scoreboard[pipeline[plPtrExec].operand2] = false;
3525 // Push instructions through the pipeline...
3526 plPtrRead = (++plPtrRead) & 0x03;
3527 plPtrExec = (++plPtrExec) & 0x03;
3534 // DSP pipelined opcode handlers
3537 #define PRM pipeline[plPtrExec].reg1
3538 #define PRN pipeline[plPtrExec].reg2
3539 #define PIMM1 pipeline[plPtrExec].operand1
3540 #define PIMM2 pipeline[plPtrExec].operand2
3541 #define PRES pipeline[plPtrExec].result
3542 #define PWBR pipeline[plPtrExec].writebackRegister
3543 #define NO_WRITEBACK pipeline[plPtrExec].writebackRegister = 0xFF
3544 //#define DSP_PPC dsp_pc - (pipeline[plPtrRead].opcode == 38 ? 6 : 2) - (pipeline[plPtrExec].opcode == 38 ? 6 : 2)
3545 #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))
3546 #define WRITEBACK_ADDR pipeline[plPtrExec].writebackRegister = 0xFE
3548 static void DSP_abs(void)
3552 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
);
3556 if (_Rn
== 0x80000000)
3560 dsp_flag_c
= ((_Rn
& 0x80000000) >> 31);
3561 PRES
= (_Rn
& 0x80000000 ? -_Rn
: _Rn
);
3562 CLR_ZN
; SET_Z(PRES
);
3566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3570 static void DSP_add(void)
3574 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
);
3576 uint32_t res
= PRN
+ PRM
;
3577 SET_ZNC_ADD(PRN
, PRM
, res
);
3581 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
);
3585 static void DSP_addc(void)
3589 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
);
3591 uint32_t res
= PRN
+ PRM
+ dsp_flag_c
;
3592 uint32_t carry
= dsp_flag_c
;
3593 // SET_ZNC_ADD(PRN, PRM, res); //???BUG??? Yes!
3594 SET_ZNC_ADD(PRN
+ carry
, PRM
, res
);
3595 // SET_ZNC_ADD(PRN, PRM + carry, res);
3599 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
);
3603 static void DSP_addq(void)
3607 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
);
3609 uint32_t r1
= dsp_convert_zero
[PIMM1
];
3610 uint32_t res
= PRN
+ r1
;
3611 CLR_ZNC
; SET_ZNC_ADD(PRN
, r1
, res
);
3615 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3619 static void DSP_addqmod(void)
3621 #ifdef DSP_DIS_ADDQMOD
3623 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
);
3625 uint32_t r1
= dsp_convert_zero
[PIMM1
];
3627 uint32_t res
= r2
+ r1
;
3628 res
= (res
& (~dsp_modulo
)) | (r2
& dsp_modulo
);
3630 SET_ZNC_ADD(r2
, r1
, res
);
3631 #ifdef DSP_DIS_ADDQMOD
3633 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3637 static void DSP_addqt(void)
3639 #ifdef DSP_DIS_ADDQT
3641 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
);
3643 PRES
= PRN
+ dsp_convert_zero
[PIMM1
];
3644 #ifdef DSP_DIS_ADDQT
3646 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3650 static void DSP_and(void)
3654 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
);
3660 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
);
3664 static void DSP_bclr(void)
3668 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
);
3670 PRES
= PRN
& ~(1 << PIMM1
);
3674 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3678 static void DSP_bset(void)
3682 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
);
3684 PRES
= PRN
| (1 << PIMM1
);
3688 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
3692 static void DSP_btst(void)
3696 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
);
3698 dsp_flag_z
= (~PRN
>> PIMM1
) & 1;
3702 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRN
);
3706 static void DSP_cmp(void)
3710 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
);
3712 uint32_t res
= PRN
- PRM
;
3713 SET_ZNC_SUB(PRN
, PRM
, res
);
3717 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
3721 static void DSP_cmpq(void)
3723 static int32_t sqtable
[32] =
3724 { 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 };
3727 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
);
3729 uint32_t r1
= sqtable
[PIMM1
& 0x1F]; // I like this better -> (INT8)(jaguar.op >> 2) >> 3;
3730 uint32_t res
= PRN
- r1
;
3731 SET_ZNC_SUB(PRN
, r1
, res
);
3735 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
3739 static void DSP_div(void)
3741 uint32_t _Rm
= PRM
, _Rn
= PRN
;
3745 if (dsp_div_control
& 1)
3747 dsp_remain
= (((uint64_t)_Rn
) << 16) % _Rm
;
3748 if (dsp_remain
& 0x80000000)
3750 PRES
= (((uint64_t)_Rn
) << 16) / _Rm
;
3754 dsp_remain
= _Rn
% _Rm
;
3755 if (dsp_remain
& 0x80000000)
3764 static void DSP_imacn(void)
3766 #ifdef DSP_DIS_IMACN
3768 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
);
3770 int32_t res
= (int16_t)PRM
* (int16_t)PRN
;
3771 dsp_acc
+= (int64_t)res
;
3772 //Should we AND the result to fit into 40 bits here???
3774 #ifdef DSP_DIS_IMACN
3776 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));
3780 static void DSP_imult(void)
3782 #ifdef DSP_DIS_IMULT
3784 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
);
3786 PRES
= (int16_t)PRN
* (int16_t)PRM
;
3788 #ifdef DSP_DIS_IMULT
3790 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
);
3794 static void DSP_imultn(void)
3796 #ifdef DSP_DIS_IMULTN
3798 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
);
3800 // This is OK, since this multiply won't overflow 32 bits...
3801 int32_t res
= (int32_t)((int16_t)PRN
* (int16_t)PRM
);
3802 dsp_acc
= (int64_t)res
;
3805 #ifdef DSP_DIS_IMULTN
3807 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));
3811 static void DSP_illegal(void)
3813 #ifdef DSP_DIS_ILLEGAL
3815 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC
, dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
3820 // There is a problem here with interrupt handlers the JUMP and JR instructions that
3821 // can cause trouble because an interrupt can occur *before* the instruction following the
3822 // jump can execute... !!! FIX !!!
3823 // This can probably be solved by judicious coding in the pipeline execution core...
3824 // And should be fixed now...
3825 static void DSP_jr(void)
3828 const char * condition
[32] =
3829 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3830 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3831 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3832 "???", "???", "???", "F" };
3834 //How come this is always off by 2???
3835 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
);
3837 // KLUDGE: Used by BRANCH_CONDITION macro
3838 uint32_t jaguar_flags
= (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
;
3840 if (BRANCH_CONDITION(PIMM2
))
3844 WriteLog("Branched!\n");
3846 int32_t offset
= (PIMM1
& 0x10 ? 0xFFFFFFF0 | PIMM1
: PIMM1
); // Sign extend PIMM1
3847 //Account for pipeline effects...
3848 uint32_t newPC
= dsp_pc
+ (offset
* 2) - (pipeline
[plPtrRead
].opcode
== 38 ? 6 : (pipeline
[plPtrRead
].opcode
== PIPELINE_STALL
? 0 : 2));
3849 //WriteLog(" --> Old PC: %08X, new PC: %08X\n", dsp_pc, newPC);
3851 // Now that we've branched, we have to make sure that the following instruction
3852 // is executed atomically with this one and then flush the pipeline before setting
3855 // Step 1: Handle writebacks at stage 3 of pipeline
3856 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3858 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3859 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3861 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3862 scoreboard[pipeline[plPtrWrite].operand2] = false;
3864 if (pipeline
[plPtrWrite
].opcode
!= PIPELINE_STALL
)
3866 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFF)
3868 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFE)
3869 dsp_reg
[pipeline
[plPtrWrite
].writebackRegister
] = pipeline
[plPtrWrite
].result
;
3872 if (pipeline
[plPtrWrite
].type
== TYPE_BYTE
)
3873 JaguarWriteByte(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3874 else if (pipeline
[plPtrWrite
].type
== TYPE_WORD
)
3875 JaguarWriteWord(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3877 JaguarWriteLong(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3881 #ifndef NEW_SCOREBOARD
3882 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3883 scoreboard
[pipeline
[plPtrWrite
].operand2
] = false;
3885 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3886 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3887 if (scoreboard
[pipeline
[plPtrWrite
].operand2
])
3888 scoreboard
[pipeline
[plPtrWrite
].operand2
]--;
3892 // Step 2: Push instruction through pipeline & execute following instruction
3893 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3894 // we effectively handle the final push of the instruction through the
3895 // pipeline when the new PC takes effect (since when we return, the
3896 // pipeline code will be executing the writeback stage. If we reverse
3897 // the execution order of the pipeline stages, this will no longer be
3899 pipeline
[plPtrExec
] = pipeline
[plPtrRead
];
3900 //This is BAD. We need to get that next opcode and execute it!
3901 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
3902 // remove this crap.
3903 if (pipeline
[plPtrExec
].opcode
== PIPELINE_STALL
)
3905 uint16_t instruction
= DSPReadWord(dsp_pc
, DSP
);
3906 pipeline
[plPtrExec
].opcode
= instruction
>> 10;
3907 pipeline
[plPtrExec
].operand1
= (instruction
>> 5) & 0x1F;
3908 pipeline
[plPtrExec
].operand2
= instruction
& 0x1F;
3909 pipeline
[plPtrExec
].reg1
= dsp_reg
[pipeline
[plPtrExec
].operand1
];
3910 pipeline
[plPtrExec
].reg2
= dsp_reg
[pipeline
[plPtrExec
].operand2
];
3911 pipeline
[plPtrExec
].writebackRegister
= pipeline
[plPtrExec
].operand2
; // Set it to RN
3913 dsp_pc
+= 2; // For DSP_DIS_* accuracy
3914 DSPOpcode
[pipeline
[plPtrExec
].opcode
]();
3915 dsp_opcode_use
[pipeline
[plPtrExec
].opcode
]++;
3916 pipeline
[plPtrWrite
] = pipeline
[plPtrExec
];
3918 // Step 3: Flush pipeline & set new PC
3919 pipeline
[plPtrRead
].opcode
= pipeline
[plPtrExec
].opcode
= PIPELINE_STALL
;
3926 WriteLog("Branch NOT taken.\n");
3932 // WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3935 static void DSP_jump(void)
3938 const char * condition
[32] =
3939 { "T", "nz", "z", "???", "nc", "nc nz", "nc z", "???", "c", "c nz",
3940 "c z", "???", "???", "???", "???", "???", "???", "???", "???",
3941 "???", "nn", "nn nz", "nn z", "???", "n", "n nz", "n z", "???",
3942 "???", "???", "???", "F" };
3944 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
);
3946 // KLUDGE: Used by BRANCH_CONDITION macro
3947 uint32_t jaguar_flags
= (dsp_flag_n
<< 2) | (dsp_flag_c
<< 1) | dsp_flag_z
;
3949 if (BRANCH_CONDITION(PIMM2
))
3953 WriteLog("Branched!\n");
3955 uint32_t PCSave
= PRM
;
3956 // Now that we've branched, we have to make sure that the following instruction
3957 // is executed atomically with this one and then flush the pipeline before setting
3960 // Step 1: Handle writebacks at stage 3 of pipeline
3961 /* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3963 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3964 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3966 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3967 scoreboard[pipeline[plPtrWrite].operand2] = false;
3969 if (pipeline
[plPtrWrite
].opcode
!= PIPELINE_STALL
)
3971 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFF)
3973 if (pipeline
[plPtrWrite
].writebackRegister
!= 0xFE)
3974 dsp_reg
[pipeline
[plPtrWrite
].writebackRegister
] = pipeline
[plPtrWrite
].result
;
3977 if (pipeline
[plPtrWrite
].type
== TYPE_BYTE
)
3978 JaguarWriteByte(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3979 else if (pipeline
[plPtrWrite
].type
== TYPE_WORD
)
3980 JaguarWriteWord(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3982 JaguarWriteLong(pipeline
[plPtrWrite
].address
, pipeline
[plPtrWrite
].value
);
3986 #ifndef NEW_SCOREBOARD
3987 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3988 scoreboard
[pipeline
[plPtrWrite
].operand2
] = false;
3990 //Yup, sequential MOVEQ # problem fixing (I hope!)...
3991 if (affectsScoreboard
[pipeline
[plPtrWrite
].opcode
])
3992 if (scoreboard
[pipeline
[plPtrWrite
].operand2
])
3993 scoreboard
[pipeline
[plPtrWrite
].operand2
]--;
3997 // Step 2: Push instruction through pipeline & execute following instruction
3998 // NOTE: By putting our following instruction at stage 3 of the pipeline,
3999 // we effectively handle the final push of the instruction through the
4000 // pipeline when the new PC takes effect (since when we return, the
4001 // pipeline code will be executing the writeback stage. If we reverse
4002 // the execution order of the pipeline stages, this will no longer be
4004 pipeline
[plPtrExec
] = pipeline
[plPtrRead
];
4005 //This is BAD. We need to get that next opcode and execute it!
4006 //Also, same problem in JR!
4007 //NOTE: The problem is here because of a bad stall. Once those are fixed, we can probably
4008 // remove this crap.
4009 if (pipeline
[plPtrExec
].opcode
== PIPELINE_STALL
)
4011 uint16_t instruction
= DSPReadWord(dsp_pc
, DSP
);
4012 pipeline
[plPtrExec
].opcode
= instruction
>> 10;
4013 pipeline
[plPtrExec
].operand1
= (instruction
>> 5) & 0x1F;
4014 pipeline
[plPtrExec
].operand2
= instruction
& 0x1F;
4015 pipeline
[plPtrExec
].reg1
= dsp_reg
[pipeline
[plPtrExec
].operand1
];
4016 pipeline
[plPtrExec
].reg2
= dsp_reg
[pipeline
[plPtrExec
].operand2
];
4017 pipeline
[plPtrExec
].writebackRegister
= pipeline
[plPtrExec
].operand2
; // Set it to RN
4019 dsp_pc
+= 2; // For DSP_DIS_* accuracy
4020 DSPOpcode
[pipeline
[plPtrExec
].opcode
]();
4021 dsp_opcode_use
[pipeline
[plPtrExec
].opcode
]++;
4022 pipeline
[plPtrWrite
] = pipeline
[plPtrExec
];
4024 // Step 3: Flush pipeline & set new PC
4025 pipeline
[plPtrRead
].opcode
= pipeline
[plPtrExec
].opcode
= PIPELINE_STALL
;
4032 WriteLog("Branch NOT taken.\n");
4040 static void DSP_load(void)
4044 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
);
4046 #ifdef DSP_CORRECT_ALIGNMENT
4047 PRES
= DSPReadLong(PRM
& 0xFFFFFFFC, DSP
);
4049 PRES
= DSPReadLong(PRM
, DSP
);
4053 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4057 static void DSP_loadb(void)
4059 #ifdef DSP_DIS_LOADB
4061 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
);
4063 if (PRM
>= DSP_WORK_RAM_BASE
&& PRM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
4064 PRES
= DSPReadLong(PRM
, DSP
) & 0xFF;
4066 PRES
= JaguarReadByte(PRM
, DSP
);
4067 #ifdef DSP_DIS_LOADB
4069 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4073 static void DSP_loadw(void)
4075 #ifdef DSP_DIS_LOADW
4077 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
);
4079 #ifdef DSP_CORRECT_ALIGNMENT
4080 if (PRM
>= DSP_WORK_RAM_BASE
&& PRM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
4081 PRES
= DSPReadLong(PRM
& 0xFFFFFFFE, DSP
) & 0xFFFF;
4083 PRES
= JaguarReadWord(PRM
& 0xFFFFFFFE, DSP
);
4085 if (PRM
>= DSP_WORK_RAM_BASE
&& PRM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
4086 PRES
= DSPReadLong(PRM
, DSP
) & 0xFFFF;
4088 PRES
= JaguarReadWord(PRM
, DSP
);
4090 #ifdef DSP_DIS_LOADW
4092 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4096 static void DSP_load_r14_i(void)
4098 #ifdef DSP_DIS_LOAD14I
4100 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
);
4102 #ifdef DSP_CORRECT_ALIGNMENT
4103 PRES
= DSPReadLong((dsp_reg
[14] & 0xFFFFFFFC) + (dsp_convert_zero
[PIMM1
] << 2), DSP
);
4105 PRES
= DSPReadLong(dsp_reg
[14] + (dsp_convert_zero
[PIMM1
] << 2), DSP
);
4107 #ifdef DSP_DIS_LOAD14I
4109 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4113 static void DSP_load_r14_r(void)
4115 #ifdef DSP_DIS_LOAD14R
4117 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
);
4119 #ifdef DSP_CORRECT_ALIGNMENT
4120 PRES
= DSPReadLong((dsp_reg
[14] + PRM
) & 0xFFFFFFFC, DSP
);
4122 PRES
= DSPReadLong(dsp_reg
[14] + PRM
, DSP
);
4124 #ifdef DSP_DIS_LOAD14R
4126 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4130 static void DSP_load_r15_i(void)
4132 #ifdef DSP_DIS_LOAD15I
4134 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
);
4136 #ifdef DSP_CORRECT_ALIGNMENT
4137 PRES
= DSPReadLong((dsp_reg
[15] &0xFFFFFFFC) + (dsp_convert_zero
[PIMM1
] << 2), DSP
);
4139 PRES
= DSPReadLong(dsp_reg
[15] + (dsp_convert_zero
[PIMM1
] << 2), DSP
);
4141 #ifdef DSP_DIS_LOAD15I
4143 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4147 static void DSP_load_r15_r(void)
4149 #ifdef DSP_DIS_LOAD15R
4151 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
);
4153 #ifdef DSP_CORRECT_ALIGNMENT
4154 PRES
= DSPReadLong((dsp_reg
[15] + PRM
) & 0xFFFFFFFC, DSP
);
4156 PRES
= DSPReadLong(dsp_reg
[15] + PRM
, DSP
);
4158 #ifdef DSP_DIS_LOAD15R
4160 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4164 static void DSP_mirror(void)
4167 PRES
= (mirror_table
[r1
& 0xFFFF] << 16) | mirror_table
[r1
>> 16];
4171 static void DSP_mmult(void)
4173 int count
= dsp_matrix_control
&0x0f;
4174 uint32_t addr
= dsp_pointer_to_matrix
; // in the dsp ram
4178 if (!(dsp_matrix_control
& 0x10))
4180 for (int i
= 0; i
< count
; i
++)
4184 a
=(int16_t)((dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]>>16)&0xffff);
4186 a
=(int16_t)(dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]&0xffff);
4187 int16_t b
=((int16_t)DSPReadWord(addr
+ 2, DSP
));
4194 for (int i
= 0; i
< count
; i
++)
4198 a
=(int16_t)((dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]>>16)&0xffff);
4200 a
=(int16_t)(dsp_alternate_reg
[dsp_opcode_first_parameter
+ (i
>>1)]&0xffff);
4201 int16_t b
=((int16_t)DSPReadWord(addr
+ 2, DSP
));
4207 PRES
= res
= (int32_t)accum
;
4209 //NOTE: The flags are set based upon the last add/multiply done...
4213 static void DSP_move(void)
4217 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
);
4222 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
);
4226 static void DSP_movefa(void)
4228 #ifdef DSP_DIS_MOVEFA
4230 // 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);
4231 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
);
4233 // PRES = ALTERNATE_RM;
4234 PRES
= dsp_alternate_reg
[PIMM1
];
4235 #ifdef DSP_DIS_MOVEFA
4237 // 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);
4238 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
);
4242 static void DSP_movei(void)
4244 #ifdef DSP_DIS_MOVEI
4246 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
);
4248 // // This instruction is followed by 32-bit value in LSW / MSW format...
4249 // PRES = (uint32_t)DSPReadWord(dsp_pc, DSP) | ((uint32_t)DSPReadWord(dsp_pc + 2, DSP) << 16);
4251 #ifdef DSP_DIS_MOVEI
4253 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4257 static void DSP_movepc(void)
4259 #ifdef DSP_DIS_MOVEPC
4261 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
);
4263 //Need to fix this to take into account pipelining effects... !!! FIX !!! [DONE]
4264 // PRES = dsp_pc - 2;
4265 //Account for pipeline effects...
4266 PRES
= dsp_pc
- 2 - (pipeline
[plPtrRead
].opcode
== 38 ? 6 : (pipeline
[plPtrRead
].opcode
== PIPELINE_STALL
? 0 : 2));
4267 #ifdef DSP_DIS_MOVEPC
4269 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4273 static void DSP_moveq(void)
4275 #ifdef DSP_DIS_MOVEQ
4277 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
);
4280 #ifdef DSP_DIS_MOVEQ
4282 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4286 static void DSP_moveta(void)
4288 #ifdef DSP_DIS_MOVETA
4290 // 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);
4291 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
]);
4293 // ALTERNATE_RN = PRM;
4294 dsp_alternate_reg
[PIMM2
] = PRM
;
4296 #ifdef DSP_DIS_MOVETA
4298 // 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);
4299 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
]);
4303 static void DSP_mtoi(void)
4305 PRES
= (((int32_t)PRM
>> 8) & 0xFF800000) | (PRM
& 0x007FFFFF);
4309 static void DSP_mult(void)
4313 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
);
4315 PRES
= (uint16_t)PRM
* (uint16_t)PRN
;
4319 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
);
4323 static void DSP_neg(void)
4327 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
);
4329 uint32_t res
= -PRN
;
4330 SET_ZNC_SUB(0, PRN
, res
);
4334 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4338 static void DSP_nop(void)
4342 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC
, dsp_flag_n
, dsp_flag_c
, dsp_flag_z
);
4347 static void DSP_normi(void)
4354 while ((_Rm
& 0xffc00000) == 0)
4359 while ((_Rm
& 0xff800000) != 0)
4369 static void DSP_not(void)
4373 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
);
4379 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4383 static void DSP_or(void)
4387 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
);
4393 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
);
4397 static void DSP_resmac(void)
4399 #ifdef DSP_DIS_RESMAC
4401 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));
4403 PRES
= (uint32_t)dsp_acc
;
4404 #ifdef DSP_DIS_RESMAC
4406 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRN
);
4410 static void DSP_ror(void)
4414 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
);
4416 uint32_t r1
= PRM
& 0x1F;
4417 uint32_t res
= (PRN
>> r1
) | (PRN
<< (32 - r1
));
4418 SET_ZN(res
); dsp_flag_c
= (PRN
>> 31) & 1;
4422 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
);
4426 static void DSP_rorq(void)
4430 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
);
4432 uint32_t r1
= dsp_convert_zero
[PIMM1
& 0x1F];
4434 uint32_t res
= (r2
>> r1
) | (r2
<< (32 - r1
));
4436 SET_ZN(res
); dsp_flag_c
= (r2
>> 31) & 0x01;
4439 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4443 static void DSP_sat16s(void)
4446 uint32_t res
= (r2
< -32768) ? -32768 : (r2
> 32767) ? 32767 : r2
;
4451 static void DSP_sat32s(void)
4453 int32_t r2
= (uint32_t)PRN
;
4454 int32_t temp
= dsp_acc
>> 32;
4455 uint32_t res
= (temp
< -1) ? (int32_t)0x80000000 : (temp
> 0) ? (int32_t)0x7FFFFFFF : r2
;
4460 static void DSP_sh(void)
4462 int32_t sRm
= (int32_t)PRM
;
4467 uint32_t shift
= -sRm
;
4472 dsp_flag_c
= (_Rn
& 0x80000000) >> 31;
4482 uint32_t shift
= sRm
;
4487 dsp_flag_c
= _Rn
& 0x1;
4500 static void DSP_sha(void)
4502 int32_t sRm
= (int32_t)PRM
;
4507 uint32_t shift
= -sRm
;
4512 dsp_flag_c
= (_Rn
& 0x80000000) >> 31;
4522 uint32_t shift
= sRm
;
4527 dsp_flag_c
= _Rn
& 0x1;
4531 _Rn
= ((int32_t)_Rn
) >> 1;
4540 static void DSP_sharq(void)
4542 #ifdef DSP_DIS_SHARQ
4544 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
);
4546 uint32_t res
= (int32_t)PRN
>> dsp_convert_zero
[PIMM1
];
4547 SET_ZN(res
); dsp_flag_c
= PRN
& 0x01;
4549 #ifdef DSP_DIS_SHARQ
4551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4555 static void DSP_shlq(void)
4559 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
);
4561 int32_t r1
= 32 - PIMM1
;
4562 uint32_t res
= PRN
<< r1
;
4563 SET_ZN(res
); dsp_flag_c
= (PRN
>> 31) & 1;
4567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4571 static void DSP_shrq(void)
4575 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
);
4577 int32_t r1
= dsp_convert_zero
[PIMM1
];
4578 uint32_t res
= PRN
>> r1
;
4579 SET_ZN(res
); dsp_flag_c
= PRN
& 1;
4583 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4587 static void DSP_store(void)
4589 #ifdef DSP_DIS_STORE
4591 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
);
4593 // DSPWriteLong(PRM, PRN, DSP);
4595 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4596 pipeline
[plPtrExec
].address
= PRM
& 0xFFFFFFFC;
4598 pipeline
[plPtrExec
].address
= PRM
;
4600 pipeline
[plPtrExec
].value
= PRN
;
4601 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4605 static void DSP_storeb(void)
4607 #ifdef DSP_DIS_STOREB
4609 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
);
4611 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4612 // DSPWriteLong(PRM, PRN & 0xFF, DSP);
4614 // JaguarWriteByte(PRM, PRN, DSP);
4617 pipeline
[plPtrExec
].address
= PRM
;
4619 if (PRM
>= DSP_WORK_RAM_BASE
&& PRM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
4621 pipeline
[plPtrExec
].value
= PRN
& 0xFF;
4622 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4626 pipeline
[plPtrExec
].value
= PRN
;
4627 pipeline
[plPtrExec
].type
= TYPE_BYTE
;
4633 static void DSP_storew(void)
4635 #ifdef DSP_DIS_STOREW
4637 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
);
4639 // if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4640 // DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4642 // JaguarWriteWord(PRM, PRN, DSP);
4645 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4646 pipeline
[plPtrExec
].address
= PRM
& 0xFFFFFFFE;
4648 pipeline
[plPtrExec
].address
= PRM
;
4651 if (PRM
>= DSP_WORK_RAM_BASE
&& PRM
<= (DSP_WORK_RAM_BASE
+ 0x1FFF))
4653 pipeline
[plPtrExec
].value
= PRN
& 0xFFFF;
4654 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4658 pipeline
[plPtrExec
].value
= PRN
;
4659 pipeline
[plPtrExec
].type
= TYPE_WORD
;
4664 static void DSP_store_r14_i(void)
4666 #ifdef DSP_DIS_STORE14I
4668 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));
4670 // DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4672 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4673 pipeline
[plPtrExec
].address
= (dsp_reg
[14] & 0xFFFFFFFC) + (dsp_convert_zero
[PIMM1
] << 2);
4675 pipeline
[plPtrExec
].address
= dsp_reg
[14] + (dsp_convert_zero
[PIMM1
] << 2);
4677 pipeline
[plPtrExec
].value
= PRN
;
4678 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4682 static void DSP_store_r14_r(void)
4684 // DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4686 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4687 pipeline
[plPtrExec
].address
= (dsp_reg
[14] + PRM
) & 0xFFFFFFFC;
4689 pipeline
[plPtrExec
].address
= dsp_reg
[14] + PRM
;
4691 pipeline
[plPtrExec
].value
= PRN
;
4692 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4696 static void DSP_store_r15_i(void)
4698 #ifdef DSP_DIS_STORE15I
4700 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));
4702 // DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4704 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4705 pipeline
[plPtrExec
].address
= (dsp_reg
[15] & 0xFFFFFFFC) + (dsp_convert_zero
[PIMM1
] << 2);
4707 pipeline
[plPtrExec
].address
= dsp_reg
[15] + (dsp_convert_zero
[PIMM1
] << 2);
4709 pipeline
[plPtrExec
].value
= PRN
;
4710 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4714 static void DSP_store_r15_r(void)
4716 // DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4718 #ifdef DSP_CORRECT_ALIGNMENT_STORE
4719 pipeline
[plPtrExec
].address
= (dsp_reg
[15] + PRM
) & 0xFFFFFFFC;
4721 pipeline
[plPtrExec
].address
= dsp_reg
[15] + PRM
;
4723 pipeline
[plPtrExec
].value
= PRN
;
4724 pipeline
[plPtrExec
].type
= TYPE_DWORD
;
4728 static void DSP_sub(void)
4732 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
);
4734 uint32_t res
= PRN
- PRM
;
4735 SET_ZNC_SUB(PRN
, PRM
, res
);
4739 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
);
4743 static void DSP_subc(void)
4747 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
);
4749 uint32_t res
= PRN
- PRM
- dsp_flag_c
;
4750 uint32_t borrow
= dsp_flag_c
;
4751 SET_ZNC_SUB(PRN
- borrow
, PRM
, res
);
4755 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
);
4759 static void DSP_subq(void)
4763 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
);
4765 uint32_t r1
= dsp_convert_zero
[PIMM1
];
4766 uint32_t res
= PRN
- r1
;
4767 SET_ZNC_SUB(PRN
, r1
, res
);
4771 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4775 static void DSP_subqmod(void)
4777 uint32_t r1
= dsp_convert_zero
[PIMM1
];
4779 uint32_t res
= r2
- r1
;
4780 res
= (res
& (~dsp_modulo
)) | (r2
& dsp_modulo
);
4782 SET_ZNC_SUB(r2
, r1
, res
);
4785 static void DSP_subqt(void)
4787 #ifdef DSP_DIS_SUBQT
4789 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
);
4791 PRES
= PRN
- dsp_convert_zero
[PIMM1
];
4792 #ifdef DSP_DIS_SUBQT
4794 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n
, dsp_flag_c
, dsp_flag_z
, PIMM2
, PRES
);
4798 static void DSP_xor(void)
4802 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
);
4808 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
);