Added search paths in case of missing DWARF directories information
[clinton/Virtual-Jaguar-Rx.git] / src / dsp.cpp
CommitLineData
cf76e892
JPM
1//
2// DSP core
3//
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
8//
9// JLH = James Hammons <jlhamm@acm.org>
10// JPM = Jean-Paul Mari <djipi.mari@gmail.com>
11//
12// Who When What
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
17//
18
19#include "dsp.h"
20
21#include <SDL.h> // Used only for SDL_GetTicks...
22#include <stdlib.h>
23#include "dac.h"
24#include "gpu.h"
25#include "jagdasm.h"
26#include "jaguar.h"
27#include "jerry.h"
28#include "log.h"
29#include "m68000/m68kinterface.h"
30//#include "memory.h"
31
32
33// Seems alignment in loads & stores was off...
34#define DSP_CORRECT_ALIGNMENT
35//#define DSP_CORRECT_ALIGNMENT_STORE
36
37//#define DSP_DEBUG
38//#define DSP_DEBUG_IRQ
39//#define DSP_DEBUG_PL2
40//#define DSP_DEBUG_STALL
41//#define DSP_DEBUG_CC
42#define NEW_SCOREBOARD
43
44// Disassembly definitions
45
46#if 0
47#define DSP_DIS_ABS
48#define DSP_DIS_ADD
49#define DSP_DIS_ADDC
50#define DSP_DIS_ADDQ
51#define DSP_DIS_ADDQMOD
52#define DSP_DIS_ADDQT
53#define DSP_DIS_AND
54#define DSP_DIS_BCLR
55#define DSP_DIS_BSET
56#define DSP_DIS_BTST
57#define DSP_DIS_CMP
58#define DSP_DIS_CMPQ
59#define DSP_DIS_IMACN
60#define DSP_DIS_IMULT
61#define DSP_DIS_IMULTN
62#define DSP_DIS_ILLEGAL
63#define DSP_DIS_JR
64#define DSP_DIS_JUMP
65#define DSP_DIS_LOAD
66#define DSP_DIS_LOAD14I
67#define DSP_DIS_LOAD14R
68#define DSP_DIS_LOAD15I
69#define DSP_DIS_LOAD15R
70#define DSP_DIS_LOADB
71#define DSP_DIS_LOADW
72#define DSP_DIS_MOVE
73#define DSP_DIS_MOVEI
74#define DSP_DIS_MOVEQ
75#define DSP_DIS_MOVEFA
76#define DSP_DIS_MOVEPC // Pipeline only!
77#define DSP_DIS_MOVETA
78#define DSP_DIS_MULT
79#define DSP_DIS_NEG
80#define DSP_DIS_NOP
81#define DSP_DIS_NOT
82#define DSP_DIS_OR
83#define DSP_DIS_RESMAC
84#define DSP_DIS_ROR
85#define DSP_DIS_RORQ
86#define DSP_DIS_SHARQ
87#define DSP_DIS_SHLQ
88#define DSP_DIS_SHRQ
89#define DSP_DIS_STORE
90#define DSP_DIS_STORE14I
91#define DSP_DIS_STORE15I
92#define DSP_DIS_STOREB
93#define DSP_DIS_STOREW
94#define DSP_DIS_SUB
95#define DSP_DIS_SUBC
96#define DSP_DIS_SUBQ
97#define DSP_DIS_SUBQT
98#define DSP_DIS_XOR
99//*/
100bool doDSPDis = false;
101//bool doDSPDis = true;
102#endif
103bool doDSPDis = false;
104//#define DSP_DIS_JR
105//#define DSP_DIS_JUMP
106
107/*
108No dis yet:
109+ subqt 4560
110+ mult 1472
111+ imultn 395024
112+ resmac 395024
113+ imacn 395024
114+ addqmod 93328
115
116dsp opcodes use:
117+ add 1672497
118+ addq 4366576
119+ addqt 44405640
120+ sub 94833
121+ subq 111769
122+ and 47416
123+ btst 94521
124+ bset 2277826
125+ bclr 3223372
126+ mult 47104
127+ imult 237080
128+ shlq 365464
129+ shrq 141624
130+ sharq 318368
131+ cmp 45175078
132+ move 2238994
133+ moveq 335305
134+ moveta 19
135+ movefa 47406440
136+ movei 1920664
137+ loadb 94832
138+ load 4031281
139+ load_r15_indexed 284500
140+ store 2161732
141+ store_r15_indexed 47416
142+ jump 3872424
143+ jr 46386967
144+ nop 3300029
145+ load_r14_ri 1229448
146*/
147
148// Pipeline structures
149
150const bool affectsScoreboard[64] =
151{
152 true, true, true, true,
153 true, true, true, true,
154 true, true, true, true,
155 true, false, true, true,
156
157 true, true, false, true,
158 false, true, true, true,
159 true, true, true, true,
160 true, true, false, false,
161
162 true, true, true, true,
163 false, true, true, true,
164 true, true, true, true,
165 true, false, false, false,
166
167 true, false, false, true,
168 false, false, true, true,
169 true, false, true, true,
170 false, false, false, true
171};
172
173struct PipelineStage
174{
175 uint16_t instruction;
176 uint8_t opcode, operand1, operand2;
177 uint32_t reg1, reg2, areg1, areg2;
178 uint32_t result;
179 uint8_t writebackRegister;
180 // General memory store...
181 uint32_t address;
182 uint32_t value;
183 uint8_t type;
184};
185
186#define TYPE_BYTE 0
187#define TYPE_WORD 1
188#define TYPE_DWORD 2
189#define PIPELINE_STALL 64 // Set to # of opcodes + 1
190#ifndef NEW_SCOREBOARD
191bool scoreboard[32];
192#else
193uint8_t scoreboard[32];
194#endif
195uint8_t plPtrFetch, plPtrRead, plPtrExec, plPtrWrite;
196PipelineStage pipeline[4];
197bool IMASKCleared = false;
198
199// DSP flags (old--have to get rid of this crap)
200
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 */
208
209// DSP_FLAGS bits
210
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
229
230// DSP_CTRL bits
231
232#define DSPGO 0x00001
233#define CPUINT 0x00002
234#define DSPINT0 0x00004
235#define SINGLE_STEP 0x00008
236#define SINGLE_GO 0x00010
237// Bit 5 is unused!
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
246
247extern uint32_t jaguar_mainRom_crc32;
248
249// Is opcode 62 *really* a NOP? Seems like it...
250static void dsp_opcode_abs(void);
251static void dsp_opcode_add(void);
252static void dsp_opcode_addc(void);
253static void dsp_opcode_addq(void);
254static void dsp_opcode_addqmod(void);
255static void dsp_opcode_addqt(void);
256static void dsp_opcode_and(void);
257static void dsp_opcode_bclr(void);
258static void dsp_opcode_bset(void);
259static void dsp_opcode_btst(void);
260static void dsp_opcode_cmp(void);
261static void dsp_opcode_cmpq(void);
262static void dsp_opcode_div(void);
263static void dsp_opcode_imacn(void);
264static void dsp_opcode_imult(void);
265static void dsp_opcode_imultn(void);
266static void dsp_opcode_jr(void);
267static void dsp_opcode_jump(void);
268static void dsp_opcode_load(void);
269static void dsp_opcode_loadb(void);
270static void dsp_opcode_loadw(void);
271static void dsp_opcode_load_r14_indexed(void);
272static void dsp_opcode_load_r14_ri(void);
273static void dsp_opcode_load_r15_indexed(void);
274static void dsp_opcode_load_r15_ri(void);
275static void dsp_opcode_mirror(void);
276static void dsp_opcode_mmult(void);
277static void dsp_opcode_move(void);
278static void dsp_opcode_movei(void);
279static void dsp_opcode_movefa(void);
280static void dsp_opcode_move_pc(void);
281static void dsp_opcode_moveq(void);
282static void dsp_opcode_moveta(void);
283static void dsp_opcode_mtoi(void);
284static void dsp_opcode_mult(void);
285static void dsp_opcode_neg(void);
286static void dsp_opcode_nop(void);
287static void dsp_opcode_normi(void);
288static void dsp_opcode_not(void);
289static void dsp_opcode_or(void);
290static void dsp_opcode_resmac(void);
291static void dsp_opcode_ror(void);
292static void dsp_opcode_rorq(void);
293static void dsp_opcode_xor(void);
294static void dsp_opcode_sat16s(void);
295static void dsp_opcode_sat32s(void);
296static void dsp_opcode_sh(void);
297static void dsp_opcode_sha(void);
298static void dsp_opcode_sharq(void);
299static void dsp_opcode_shlq(void);
300static void dsp_opcode_shrq(void);
301static void dsp_opcode_store(void);
302static void dsp_opcode_storeb(void);
303static void dsp_opcode_storew(void);
304static void dsp_opcode_store_r14_indexed(void);
305static void dsp_opcode_store_r14_ri(void);
306static void dsp_opcode_store_r15_indexed(void);
307static void dsp_opcode_store_r15_ri(void);
308static void dsp_opcode_sub(void);
309static void dsp_opcode_subc(void);
310static void dsp_opcode_subq(void);
311static void dsp_opcode_subqmod(void);
312static void dsp_opcode_subqt(void);
313static void dsp_opcode_illegal(void);
314
315/*uint8_t dsp_opcode_cycles[64] =
316{
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
325};//*/
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. :-/
333uint8_t dsp_opcode_cycles[64] =
334{
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
343};//*/
344
345void (* dsp_opcode[64])() =
346{
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,
363};
364
365uint32_t dsp_opcode_use[65];
366
367const char * dsp_opcode_str[65]=
368{
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",
385 "STALL"
386};
387
388uint32_t dsp_pc;
389static uint64_t dsp_acc; // 40 bit register, NOT 32!
390static uint32_t dsp_remain;
391static uint32_t dsp_modulo;
392static uint32_t dsp_flags;
393static uint32_t dsp_matrix_control;
394static uint32_t dsp_pointer_to_matrix;
395static uint32_t dsp_data_organization;
396uint32_t dsp_control;
397static uint32_t dsp_div_control;
398static uint8_t dsp_flag_z, dsp_flag_n, dsp_flag_c;
399static uint32_t * dsp_reg = NULL, * dsp_alternate_reg = NULL;
400uint32_t dsp_reg_bank_0[32], dsp_reg_bank_1[32];
401
402static uint32_t dsp_opcode_first_parameter;
403static uint32_t dsp_opcode_second_parameter;
404
405#define DSP_RUNNING (dsp_control & 0x01)
406
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
413
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)
424
425uint32_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
428};
429
430uint8_t dsp_branch_condition_table[32 * 8];
431static uint16_t mirror_table[65536];
432static uint8_t dsp_ram_8[0x2000];
433
434#define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
435
436static uint32_t dsp_in_exec = 0;
437static uint32_t dsp_releaseTimeSlice_flag = 0;
438
439FILE * dsp_fp;
440
441#ifdef DSP_DEBUG_CC
442// Comparison core vars (used only for core comparison! :-)
443static uint64_t count = 0;
444static uint8_t ram1[0x2000], ram2[0x2000];
445static uint32_t regs1[64], regs2[64];
446static uint32_t ctrl1[14], ctrl2[14];
447#endif
448
449// Private function prototypes
450
451void DSPDumpRegisters(void);
452void DSPDumpDisassembly(void);
453void FlushDSPPipeline(void);
454
455
456void dsp_reset_stats(void)
457{
458 for(int i=0; i<65; i++)
459 dsp_opcode_use[i] = 0;
460}
461
462
463void DSPReleaseTimeslice(void)
464{
465//This does absolutely nothing!!! !!! FIX !!!
466 dsp_releaseTimeSlice_flag = 1;
467}
468
469
470void dsp_build_branch_condition_table(void)
471{
472 // Fill in the mirror table
473 for(int i=0; i<65536; i++)
474 {
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);
483 }
484
485 // Fill in the condition table
486 for(int i=0; i<8; i++)
487 {
488 for(int j=0; j<32; j++)
489 {
490 int result = 1;
491
492 if ((j & 1) && (i & ZERO_FLAG))
493 result = 0;
494
495 if ((j & 2) && (!(i & ZERO_FLAG)))
496 result = 0;
497
498 if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
499 result = 0;
500
501 if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
502 result = 0;
503
504 dsp_branch_condition_table[i * 32 + j] = result;
505 }
506 }
507}
508
509
510uint8_t DSPReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
511{
512 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
513 WriteLog("DSP: ReadByte--Attempt to read from DSP register file by %s!\n", whoName[who]);
514// battlemorph
515// if ((offset==0xF1CFE0)||(offset==0xF1CFE2))
516// return(0xffff);
517 // mutant penguin
518/* if ((jaguar_mainRom_crc32==0xbfd751a4)||(jaguar_mainRom_crc32==0x053efaf9))
519 {
520 if (offset==0xF1CFE0)
521 return(0xff);
522 }*/
523 if (offset >= DSP_WORK_RAM_BASE && offset <= (DSP_WORK_RAM_BASE + 0x1FFF))
524 return dsp_ram_8[offset - DSP_WORK_RAM_BASE];
525
526 if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
527 {
528 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
529
530 if ((offset & 0x03) == 0)
531 return (data >> 24);
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);
538 }
539
540 return JaguarReadByte(offset, who);
541}
542
543
544uint16_t DSPReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
545{
546 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
547 WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]);
548 //???
549 offset &= 0xFFFFFFFE;
550
551 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF)
552 {
553 offset -= DSP_WORK_RAM_BASE;
554/* uint16_t data = (((uint16_t)dsp_ram_8[offset])<<8)|((uint16_t)dsp_ram_8[offset+1]);
555 return data;*/
556 return GET16(dsp_ram_8, offset);
557 }
558 else if ((offset>=DSP_CONTROL_RAM_BASE)&&(offset<DSP_CONTROL_RAM_BASE+0x20))
559 {
560 uint32_t data = DSPReadLong(offset & 0xFFFFFFFC, who);
561
562 if (offset & 0x03)
563 return data & 0xFFFF;
564 else
565 return data >> 16;
566 }
567
568 return JaguarReadWord(offset, who);
569}
570
571
572uint32_t DSPReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
573{
574 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
575 WriteLog("DSP: ReadLong--Attempt to read from DSP register file by %s!\n", whoName[who]);
576
577 // ??? WHY ???
578 offset &= 0xFFFFFFFC;
579/*if (offset == 0xF1BCF4)
580{
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();
583}*/
584 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
585 {
586 offset -= DSP_WORK_RAM_BASE;
587 return GET32(dsp_ram_8, offset);
588 }
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)
592 {
593 offset &= 0x3F;
594 switch (offset)
595 {
596 case 0x00:
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;
606 case 0x20:
607 return (int32_t)((int8_t)(dsp_acc >> 32)); // Top 8 bits of 40-bit accumulator, sign extended
608 }
609 // unaligned long read-- !!! FIX !!!
610 return 0xFFFFFFFF;
611 }
612
613 return JaguarReadLong(offset, who);
614}
615
616
617void DSPWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
618{
619 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
620 WriteLog("DSP: WriteByte--Attempt to write to DSP register file by %s!\n", whoName[who]);
621
622 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE + 0x2000))
623 {
624 offset -= DSP_WORK_RAM_BASE;
625 dsp_ram_8[offset] = data;
626//This is rather stupid! !!! FIX !!!
627/* if (dsp_in_exec == 0)
628 {
629 m68k_end_timeslice();
630 dsp_releaseTimeslice();
631 }*/
632 return;
633 }
634 if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE + 0x20))
635 {
636 uint32_t reg = offset & 0x1C;
637 int bytenum = offset & 0x03;
638
639 if ((reg >= 0x1C) && (reg <= 0x1F))
640 dsp_div_control = (dsp_div_control & (~(0xFF << (bytenum << 3)))) | (data << (bytenum << 3));
641 else
642 {
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);
648 }
649 return;
650 }
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);
655}
656
657
658void DSPWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
659{
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)
664{
665 WriteLog("DSPWriteWord: Writing to 0xF1BCF4... %04X -> %04X\n", GET16(dsp_ram_8, 0x0CF4), data);
666}*/
667// WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset);
668 if ((offset >= DSP_WORK_RAM_BASE) && (offset < DSP_WORK_RAM_BASE+0x2000))
669 {
670/*if (offset == 0xF1B2F4)
671{
672 WriteLog("DSP: %s is writing %04X at location 0xF1B2F4 (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc);
673}//*/
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)
679 {
680// WriteLog("dsp: writing %.4x at 0x%.8x\n",data,offset+DSP_WORK_RAM_BASE);
681 m68k_end_timeslice();
682 dsp_releaseTimeslice();
683 }*/
684//CC only!
685#ifdef DSP_DEBUG_CC
686SET16(ram1, offset, data),
687SET16(ram2, offset, data);
688#endif
689//!!!!!!!!
690 return;
691 }
692 else if ((offset >= DSP_CONTROL_RAM_BASE) && (offset < DSP_CONTROL_RAM_BASE+0x20))
693 {
694 if ((offset & 0x1C) == 0x1C)
695 {
696 if (offset & 0x03)
697 dsp_div_control = (dsp_div_control & 0xFFFF0000) | (data & 0xFFFF);
698 else
699 dsp_div_control = (dsp_div_control & 0xFFFF) | ((data & 0xFFFF) << 16);
700 }
701 else
702 {
703 uint32_t old_data = DSPReadLong(offset & 0xFFFFFFC, who);
704
705 if (offset & 0x03)
706 old_data = (old_data & 0xFFFF0000) | (data & 0xFFFF);
707 else
708 old_data = (old_data & 0xFFFF) | ((data & 0xFFFF) << 16);
709
710 DSPWriteLong(offset & 0xFFFFFFC, old_data, who);
711 }
712
713 return;
714 }
715
716 JaguarWriteWord(offset, data, who);
717}
718
719
720//bool badWrite = false;
721void DSPWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
722{
723 if (offset >= 0xF1A000 && offset <= 0xF1A0FF)
724 WriteLog("DSP: WriteLong--Attempt to write to DSP register file by %s!\n", whoName[who]);
725 // ??? WHY ???
726 offset &= 0xFFFFFFFC;
727/*if (offset == 0xF1BCF4)
728{
729 WriteLog("DSPWriteLong: Writing to 0xF1BCF4... %08X -> %08X\n", GET32(dsp_ram_8, 0x0CF4), data);
730}*/
731// WriteLog("dsp: writing %.8x at 0x%.8x\n",data,offset);
732 if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE + 0x1FFF)
733 {
734/*if (offset == 0xF1BE2C)
735{
736 WriteLog("DSP: %s is writing %08X at location 0xF1BE2C (DSP_PC: %08X)...\n", whoName[who], data, dsp_pc - 2);
737}//*/
738 offset -= DSP_WORK_RAM_BASE;
739 SET32(dsp_ram_8, offset, data);
740//CC only!
741#ifdef DSP_DEBUG_CC
742SET32(ram1, offset, data),
743SET32(ram2, offset, data);
744#endif
745//!!!!!!!!
746 return;
747 }
748 else if (offset >= DSP_CONTROL_RAM_BASE && offset <= (DSP_CONTROL_RAM_BASE + 0x1F))
749 {
750 offset &= 0x1F;
751 switch (offset)
752 {
753 case 0x00:
754 {
755#ifdef DSP_DEBUG
756 WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
757#endif
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);
769 break;
770 }
771 case 0x04:
772 dsp_matrix_control = data;
773 break;
774 case 0x08:
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);
778 break;
779 case 0x0C:
780 dsp_data_organization = data;
781 break;
782 case 0x10:
783 dsp_pc = data;
784#ifdef DSP_DEBUG
785 WriteLog("DSP: Setting DSP PC to %08X by %s%s\n", dsp_pc, whoName[who], (DSP_RUNNING ? " (DSP is RUNNING!)" : ""));//*/
786#endif
787//CC only!
788#ifdef DSP_DEBUG_CC
789if (who != DSP)
790 ctrl1[0] = ctrl2[0] = data;
791#endif
792//!!!!!!!!
793 break;
794 case 0x14:
795 {
796//#ifdef DSP_DEBUG
797WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
798//#endif
799 bool wasRunning = DSP_RUNNING;
800// uint32_t dsp_was_running = DSP_RUNNING;
801 // Check for DSP -> CPU interrupt
802 if (data & CPUINT)
803 {
804#ifdef DSP_DEBUG
805 WriteLog("DSP: DSP -> CPU interrupt\n");
806#endif
807
808#ifdef _MSC_VER
809#pragma message("Warning: !!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!")
810#else
811#warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
812#endif // _MSC_VER
813 if (JERRYIRQEnabled(IRQ2_DSP))
814 {
815 JERRYSetPendingIRQ(IRQ2_DSP);
816 DSPReleaseTimeslice();
817 m68k_set_irq(2); // Set 68000 IPL 2...
818 }
819 data &= ~CPUINT;
820 }
821 // Check for CPU -> DSP interrupt
822 if (data & DSPINT0)
823 {
824#ifdef DSP_DEBUG
825 WriteLog("DSP: CPU -> DSP interrupt\n");
826#endif
827 m68k_end_timeslice();
828 DSPReleaseTimeslice();
829 DSPSetIRQLine(DSPIRQ_CPU, ASSERT_LINE);
830 data &= ~DSPINT0;
831 }
832 // single stepping
833 if (data & SINGLE_STEP)
834 {
835// WriteLog("DSP: Asked to perform a single step (single step is %senabled)\n", (data & 0x8 ? "" : "not "));
836 }
837
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);
841//CC only!
842#ifdef DSP_DEBUG_CC
843if (who != DSP)
844 ctrl1[8] = ctrl2[8] = dsp_control;
845#endif
846//!!!!!!!!
847
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)
853 {
854 DSPExec(200);
855 }*/
856#else
857//This is WRONG! !!! FIX !!!
858 if (dsp_control & 0x18)
859 DSPExec(1);
860#endif
861#ifdef DSP_DEBUG
862if (DSP_RUNNING)
863 WriteLog(" --> Starting to run at %08X by %s...", dsp_pc, whoName[who]);
864else
865 WriteLog(" --> Stopped by %s! (DSP PC: %08X)", whoName[who], dsp_pc);
866WriteLog("\n");
867#endif // DSP_DEBUG
868//This isn't exactly right either--we don't know if it was the M68K or the DSP writing here...
869// !!! FIX !!! [DONE]
870 if (DSP_RUNNING)
871 {
872 if (who == M68K)
873 m68k_end_timeslice();
874 else if (who == DSP)
875 DSPReleaseTimeslice();
876
877 if (!wasRunning)
878 FlushDSPPipeline();
879//DSPDumpDisassembly();
880 }
881 break;
882 }
883 case 0x18:
884WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]);
885 dsp_modulo = data;
886 break;
887 case 0x1C:
888 dsp_div_control = data;
889 break;
890// default: // unaligned long read
891 //__asm int 3
892 }
893 return;
894 }
895
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)
900// badWrite = true;
901 JaguarWriteLong(offset, data, who);
902}
903
904
905//
906// Update the DSP register file pointers depending on REGPAGE bit
907//
908void DSPUpdateRegisterBanks(void)
909{
910 int bank = (dsp_flags & REGPAGE);
911
912 if (dsp_flags & IMASK)
913 bank = 0; // IMASK forces main bank to be bank 0
914
915 if (bank)
916 dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0;
917 else
918 dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1;
919
920#ifdef DSP_DEBUG_IRQ
921 WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0"));
922#endif
923}
924
925
926//
927// Check for and handle any asserted DSP IRQs
928//
929void DSPHandleIRQs(void)
930{
931 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
932 return;
933
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);
937
938// WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
939 bits &= mask;
940
941 if (!bits) // Bail if nothing is enabled
942 return;
943
944 int which = 0; // Determine which interrupt
945
946 if (bits & 0x01)
947 which = 0;
948 if (bits & 0x02)
949 which = 1;
950 if (bits & 0x04)
951 which = 2;
952 if (bits & 0x08)
953 which = 3;
954 if (bits & 0x10)
955 which = 4;
956 if (bits & 0x20)
957 which = 5;
958
959#ifdef DSP_DEBUG_IRQ
960 WriteLog("DSP: Generating interrupt #%i...", which);
961#endif
962//temp... !!!!!
963//if (which == 0) doDSPDis = true;
964
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
968 // behavior here.
969/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
970 {
971 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
972 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
973
974 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
975 scoreboard[pipeline[plPtrWrite].operand2] = false;
976 }//*/
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?
981#ifdef DSP_DEBUG_IRQ
982WriteLog("--> Pipeline dump [DSP_PC=%08X]...\n", dsp_pc);
983WriteLog("\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]);
984WriteLog("\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]);
985WriteLog("\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]);
986#endif
987 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
988 {
989 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
990 {
991 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
992 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
993 else
994 {
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);
999 else
1000 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
1001 }
1002 }
1003
1004#ifndef NEW_SCOREBOARD
1005 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
1006 scoreboard[pipeline[plPtrWrite].operand2] = false;
1007#else
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]--;
1012#endif
1013 }
1014
1015 dsp_flags |= IMASK;
1016//CC only!
1017#ifdef DSP_DEBUG_CC
1018ctrl2[4] = dsp_flags;
1019#endif
1020//!!!!!!!!
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]);
1025#endif
1026
1027 // subqt #4,r31 ; pre-decrement stack pointer
1028 // move pc,r30 ; address of interrupted code
1029 // store r30,(r31) ; store return address
1030 dsp_reg[31] -= 4;
1031//CC only!
1032#ifdef DSP_DEBUG_CC
1033regs2[31] -= 4;
1034#endif
1035//!!!!!!!!
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!
1039//
1040// Look at the pipeline when an interrupt occurs (instructions of foo, bar, baz):
1041//
1042// R -> baz (<- PC points here)
1043// E -> bar (when it should point here!)
1044// W -> foo
1045//
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...
1050
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);
1053//CC only!
1054#ifdef DSP_DEBUG_CC
1055SET32(ram2, regs2[31] - 0xF1B000, dsp_pc - 2 - (pipeline[plPtrExec].opcode == 38 ? 6 : (pipeline[plPtrExec].opcode == PIPELINE_STALL ? 0 : 2)));
1056#endif
1057//!!!!!!!!
1058
1059 // movei #service_address,r30 ; pointer to ISR entry
1060 // jump (r30) ; jump to ISR
1061 // nop
1062 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1063//CC only!
1064#ifdef DSP_DEBUG_CC
1065ctrl2[0] = regs2[30] = dsp_pc;
1066#endif
1067//!!!!!!!!
1068 FlushDSPPipeline();
1069}
1070
1071
1072//
1073// Non-pipelined version...
1074//
1075void DSPHandleIRQsNP(void)
1076{
1077//CC only!
1078#ifdef DSP_DEBUG_CC
1079 memcpy(dsp_ram_8, ram1, 0x2000);
1080 memcpy(dsp_reg_bank_0, regs1, 32 * 4);
1081 memcpy(dsp_reg_bank_1, &regs1[32], 32 * 4);
1082 dsp_pc = ctrl1[0];
1083 dsp_acc = ctrl1[1];
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];
1096DSPUpdateRegisterBanks();
1097#endif
1098//!!!!!!!!
1099 if (dsp_flags & IMASK) // Bail if we're already inside an interrupt
1100 return;
1101
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);
1105
1106// WriteLog("dsp: bits=%.2x mask=%.2x\n",bits,mask);
1107 bits &= mask;
1108
1109 if (!bits) // Bail if nothing is enabled
1110 return;
1111
1112 int which = 0; // Determine which interrupt
1113 if (bits & 0x01)
1114 which = 0;
1115 if (bits & 0x02)
1116 which = 1;
1117 if (bits & 0x04)
1118 which = 2;
1119 if (bits & 0x08)
1120 which = 3;
1121 if (bits & 0x10)
1122 which = 4;
1123 if (bits & 0x20)
1124 which = 5;
1125
1126 dsp_flags |= IMASK; // Force Bank #0
1127//CC only!
1128#ifdef DSP_DEBUG_CC
1129ctrl1[4] = dsp_flags;
1130#endif
1131//!!!!!!!!
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]);
1135#endif
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]);
1140#endif
1141
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]);
1145#endif
1146
1147 // subqt #4,r31 ; pre-decrement stack pointer
1148 // move pc,r30 ; address of interrupted code
1149 // store r30,(r31) ; store return address
1150 dsp_reg[31] -= 4;
1151 dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already
1152
1153//CC only!
1154#ifdef DSP_DEBUG_CC
1155regs1[31] -= 4;
1156#endif
1157//!!!!!!!!
1158// DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP);
1159 DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP);
1160//CC only!
1161#ifdef DSP_DEBUG_CC
1162SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2);
1163#endif
1164//!!!!!!!!
1165
1166 // movei #service_address,r30 ; pointer to ISR entry
1167 // jump (r30) ; jump to ISR
1168 // nop
1169 dsp_pc = dsp_reg[30] = DSP_WORK_RAM_BASE + (which * 0x10);
1170//CC only!
1171#ifdef DSP_DEBUG_CC
1172ctrl1[0] = regs1[30] = dsp_pc;
1173#endif
1174//!!!!!!!!
1175}
1176
1177
1178//
1179// Set the specified DSP IRQ line to a given state
1180//
1181void DSPSetIRQLine(int irqline, int state)
1182{
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
1186//CC only!
1187#ifdef DSP_DEBUG_CC
1188ctrl1[8] = ctrl2[8] = dsp_control;
1189#endif
1190//!!!!!!!!
1191
1192 if (state)
1193 {
1194 dsp_control |= mask; // Set the latch bit
1195#ifdef _MSC_VER
1196#pragma message("Warning: !!! No checking done to see if we're using pipelined DSP or not !!!")
1197#else
1198#warning "!!! No checking done to see if we're using pipelined DSP or not !!!"
1199#endif // _MSC_VER
1200// DSPHandleIRQs();
1201 DSPHandleIRQsNP();
1202//CC only!
1203#ifdef DSP_DEBUG_CC
1204ctrl1[8] = ctrl2[8] = dsp_control;
1205DSPHandleIRQsNP();
1206#endif
1207//!!!!!!!!
1208 }
1209
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);
1214}
1215
1216
1217bool DSPIsRunning(void)
1218{
1219 return (DSP_RUNNING ? true : false);
1220}
1221
1222
1223void DSPInit(void)
1224{
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");
1228
1229 dsp_build_branch_condition_table();
1230 DSPReset();
1231}
1232
1233
1234void DSPReset(void)
1235{
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;
1246 dsp_in_exec = 0;
1247
1248 dsp_reg = dsp_reg_bank_0;
1249 dsp_alternate_reg = dsp_reg_bank_1;
1250
1251 for(int i=0; i<32; i++)
1252 dsp_reg[i] = dsp_alternate_reg[i] = 0x00000000;
1253
1254 CLR_ZNC;
1255 IMASKCleared = false;
1256 FlushDSPPipeline();
1257 dsp_reset_stats();
1258
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();
1262}
1263
1264
1265void DSPDumpDisassembly(void)
1266{
1267 char buffer[512];
1268
1269 WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
1270 uint32_t j = 0xF1B000;
1271
1272 while (j <= 0xF1CFFF)
1273 {
1274 uint32_t oldj = j;
1275 j += dasmjag(JAGUAR_DSP, buffer, j);
1276 WriteLog("\t%08X: %s\n", oldj, buffer);
1277 }
1278}
1279
1280
1281void DSPDumpRegisters(void)
1282{
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");
1286
1287 for(int j=0; j<8; j++)
1288 {
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]);
1294 }
1295
1296 WriteLog("Registers bank 1\n");
1297
1298 for(int j=0; j<8; j++)
1299 {
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]);
1305 }
1306}
1307
1308
1309void DSPDone(void)
1310{
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");
1325
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 "));
1328
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);
1333
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" : ""));
1338 DSPDumpRegisters();
1339 WriteLog("\n");
1340
1341 static char buffer[512];
1342 int j = DSP_WORK_RAM_BASE;
1343
1344 while (j <= 0xF1CFFF)
1345 {
1346 uint32_t oldj = j;
1347 j += dasmjag(JAGUAR_DSP, buffer, j);
1348 WriteLog("\t%08X: %s\n", oldj, buffer);
1349 }
1350
1351 WriteLog("DSP opcodes use:\n");
1352
1353 for(int i=0; i<64; i++)
1354 {
1355 if (dsp_opcode_use[i])
1356 WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]);
1357 }
1358}
1359
1360
1361
1362//
1363// DSP comparison core...
1364//
1365#ifdef DSP_DEBUG_CC
1366static uint16_t lastExec;
1367void DSPExecComp(int32_t cycles)
1368{
1369 while (cycles > 0 && DSP_RUNNING)
1370 {
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, &regs1[32], 32 * 4);
1375 dsp_pc = ctrl1[0];
1376 dsp_acc = ctrl1[1];
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];
1389DSPUpdateRegisterBanks();
1390
1391 // Decrement cycles based on non-pipelined core...
1392 uint16_t instr1 = DSPReadWord(dsp_pc, DSP);
1393 cycles -= dsp_opcode_cycles[instr1 >> 10];
1394
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
1397
1398 // Save vars
1399 memcpy(ram1, dsp_ram_8, 0x2000);
1400 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1401 memcpy(&regs1[32], dsp_reg_bank_1, 32 * 4);
1402 ctrl1[0] = dsp_pc;
1403 ctrl1[1] = dsp_acc;
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;
1416
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, &regs2[32], 32 * 4);
1421 dsp_pc = ctrl2[0];
1422 dsp_acc = ctrl2[1];
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];
1435DSPUpdateRegisterBanks();
1436
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
1439
1440 // Save vars
1441 memcpy(ram2, dsp_ram_8, 0x2000);
1442 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1443 memcpy(&regs2[32], dsp_reg_bank_1, 32 * 4);
1444 ctrl2[0] = dsp_pc;
1445 ctrl2[1] = dsp_acc;
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;
1458
1459 if (instr1 != lastExec)
1460 {
1461// WriteLog("\nCores diverged at instruction tick #%u!\nAttemping to synchronize...\n\n", count);
1462
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???
1467// if (1)
1468 {
1469 DSPExecP2(1); // Do one more instruction
1470
1471 // Save vars
1472 memcpy(ram2, dsp_ram_8, 0x2000);
1473 memcpy(regs2, dsp_reg_bank_0, 32 * 4);
1474 memcpy(&regs2[32], dsp_reg_bank_1, 32 * 4);
1475 ctrl2[0] = dsp_pc;
1476 ctrl2[1] = dsp_acc;
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;
1489 }
1490// else // NP ran ahead of P
1491 if (instr1 != lastExec) // Must be the other way...
1492
1493 {
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, &regs1[32], 32 * 4);
1498 dsp_pc = ctrl1[0];
1499 dsp_acc = ctrl1[1];
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];
1512DSPUpdateRegisterBanks();
1513
1514for(int k=0; k<2; k++)
1515{
1516 // Decrement cycles based on non-pipelined core...
1517 instr1 = DSPReadWord(dsp_pc, DSP);
1518 cycles -= dsp_opcode_cycles[instr1 >> 10];
1519
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
1522}
1523
1524 // Save vars
1525 memcpy(ram1, dsp_ram_8, 0x2000);
1526 memcpy(regs1, dsp_reg_bank_0, 32 * 4);
1527 memcpy(&regs1[32], dsp_reg_bank_1, 32 * 4);
1528 ctrl1[0] = dsp_pc;
1529 ctrl1[1] = dsp_acc;
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;
1542 }
1543 }
1544
1545 if (instr1 != lastExec)
1546 {
1547 WriteLog("\nCores diverged at instruction tick #%u!\nStopped!\n\n", count);
1548
1549 WriteLog("Instruction for non-pipelined core: %04X\n", instr1);
1550 WriteLog("Instruction for pipelined core: %04X\n", lastExec);
1551
1552 log_done();
1553 exit(1);
1554 }
1555
1556 count++;
1557 }
1558}
1559#endif
1560
1561
1562//
1563// DSP execution core
1564//
1565//static bool R20Set = false, tripwire = false;
1566//static uint32_t pcQueue[32], ptrPCQ = 0;
1567void DSPExec(int32_t cycles)
1568{
1569#ifdef DSP_SINGLE_STEPPING
1570 if (dsp_control & 0x18)
1571 {
1572 cycles = 1;
1573 dsp_control &= ~0x10;
1574 }
1575#endif
1576//There is *no* good reason to do this here!
1577// DSPHandleIRQs();
1578 dsp_releaseTimeSlice_flag = 0;
1579 dsp_in_exec++;
1580
1581 while (cycles > 0 && DSP_RUNNING)
1582 {
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)
1587//F1B140:
1588if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
1589{
1590 doDSPDis = true;
1591 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
1592}
1593if (dsp_pc == 0xF1B092)
1594 doDSPDis = false;//*/
1595/*if (dsp_pc == 0xF1B140)
1596 doDSPDis = true;//*/
1597
1598 if (IMASKCleared) // If IMASK was cleared,
1599 {
1600#ifdef DSP_DEBUG_IRQ
1601 WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc);
1602#endif
1603 DSPHandleIRQsNP(); // See if any other interrupts are pending!
1604 IMASKCleared = false;
1605 }
1606
1607/*if (badWrite)
1608{
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));
1612 WriteLog("\n");
1613}//*/
1614/*if (dsp_pc == 0xF1B55E)
1615{
1616 WriteLog("DSP: At $F1B55E--R15 = %08X at %u ms%s...\n", dsp_reg[15], SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1617}//*/
1618/*if (dsp_pc == 0xF1B7D2) // Start here???
1619 doDSPDis = true;
1620pcQueue[ptrPCQ++] = dsp_pc;
1621ptrPCQ %= 32;*/
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;
1626 dsp_pc += 2;
1627 dsp_opcode[index]();
1628 dsp_opcode_use[index]++;
1629 cycles -= dsp_opcode_cycles[index];
1630/*if (dsp_reg_bank_0[20] == 0xF1A100 & !R20Set)
1631{
1632 WriteLog("DSP: R20 set to $F1A100 at %u ms%s...\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1633 R20Set = true;
1634}
1635if (dsp_reg_bank_0[20] != 0xF1A100 && R20Set)
1636{
1637 WriteLog("DSP: R20 corrupted at %u ms from starting%s!\nAborting!\n", SDL_GetTicks(), (dsp_flags & IMASK ? " (inside interrupt)" : ""));
1638 DSPDumpRegisters();
1639 DSPDumpDisassembly();
1640 exit(1);
1641}
1642if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
1643{
1644 char buffer[512];
1645 WriteLog("DSP: Jumping outside of DSP RAM at %u ms. Register dump:\n", SDL_GetTicks());
1646 DSPDumpRegisters();
1647 tripwire = true;
1648 WriteLog("\nBacktrace:\n");
1649 for(int i=0; i<32; i++)
1650 {
1651 dasmjag(JAGUAR_DSP, buffer, pcQueue[(ptrPCQ + i) % 32]);
1652 WriteLog("\t%08X: %s\n", pcQueue[(ptrPCQ + i) % 32], buffer);
1653 }
1654 WriteLog("\n");
1655}*/
1656 }
1657
1658 dsp_in_exec--;
1659}
1660
1661
1662//
1663// DSP opcode handlers
1664//
1665
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 !!!
1669static void dsp_opcode_jump(void)
1670{
1671#ifdef DSP_DIS_JUMP
1672const 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" };
1677 if (doDSPDis)
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);
1679#endif
1680 // normalize flags
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;
1686
1687 if (BRANCH_CONDITION(IMM_2))
1688 {
1689#ifdef DSP_DIS_JUMP
1690 if (doDSPDis)
1691 WriteLog("Branched!\n");
1692#endif
1693 uint32_t delayed_pc = RM;
1694 DSPExec(1);
1695 dsp_pc = delayed_pc;
1696 }
1697#ifdef DSP_DIS_JUMP
1698 else
1699 if (doDSPDis)
1700 WriteLog("Branch NOT taken.\n");
1701#endif
1702}
1703
1704
1705static void dsp_opcode_jr(void)
1706{
1707#ifdef DSP_DIS_JR
1708const 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" };
1713 if (doDSPDis)
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);
1715#endif
1716 // normalize flags
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;
1722
1723 if (BRANCH_CONDITION(IMM_2))
1724 {
1725#ifdef DSP_DIS_JR
1726 if (doDSPDis)
1727 WriteLog("Branched!\n");
1728#endif
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);
1731 DSPExec(1);
1732 dsp_pc = delayed_pc;
1733 }
1734#ifdef DSP_DIS_JR
1735 else
1736 if (doDSPDis)
1737 WriteLog("Branch NOT taken.\n");
1738#endif
1739}
1740
1741
1742static void dsp_opcode_add(void)
1743{
1744#ifdef DSP_DIS_ADD
1745 if (doDSPDis)
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);
1747#endif
1748 uint32_t res = RN + RM;
1749 SET_ZNC_ADD(RN, RM, res);
1750 RN = res;
1751#ifdef DSP_DIS_ADD
1752 if (doDSPDis)
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);
1754#endif
1755}
1756
1757
1758static void dsp_opcode_addc(void)
1759{
1760#ifdef DSP_DIS_ADDC
1761 if (doDSPDis)
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);
1763#endif
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);
1769 RN = res;
1770#ifdef DSP_DIS_ADDC
1771 if (doDSPDis)
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);
1773#endif
1774}
1775
1776
1777static void dsp_opcode_addq(void)
1778{
1779#ifdef DSP_DIS_ADDQ
1780 if (doDSPDis)
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);
1782#endif
1783 uint32_t r1 = dsp_convert_zero[IMM_1];
1784 uint32_t res = RN + r1;
1785 CLR_ZNC; SET_ZNC_ADD(RN, r1, res);
1786 RN = res;
1787#ifdef DSP_DIS_ADDQ
1788 if (doDSPDis)
1789 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1790#endif
1791}
1792
1793
1794static void dsp_opcode_sub(void)
1795{
1796#ifdef DSP_DIS_SUB
1797 if (doDSPDis)
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);
1799#endif
1800 uint32_t res = RN - RM;
1801 SET_ZNC_SUB(RN, RM, res);
1802 RN = res;
1803#ifdef DSP_DIS_SUB
1804 if (doDSPDis)
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);
1806#endif
1807}
1808
1809
1810static void dsp_opcode_subc(void)
1811{
1812#ifdef DSP_DIS_SUBC
1813 if (doDSPDis)
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);
1815#endif
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);
1821 SET_ZN(RN);
1822#ifdef DSP_DIS_SUBC
1823 if (doDSPDis)
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);
1825#endif
1826}
1827
1828
1829static void dsp_opcode_subq(void)
1830{
1831#ifdef DSP_DIS_SUBQ
1832 if (doDSPDis)
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);
1834#endif
1835 uint32_t r1 = dsp_convert_zero[IMM_1];
1836 uint32_t res = RN - r1;
1837 SET_ZNC_SUB(RN, r1, res);
1838 RN = res;
1839#ifdef DSP_DIS_SUBQ
1840 if (doDSPDis)
1841 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1842#endif
1843}
1844
1845
1846static void dsp_opcode_cmp(void)
1847{
1848#ifdef DSP_DIS_CMP
1849 if (doDSPDis)
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);
1851#endif
1852 uint32_t res = RN - RM;
1853 SET_ZNC_SUB(RN, RM, res);
1854#ifdef DSP_DIS_CMP
1855 if (doDSPDis)
1856 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1857#endif
1858}
1859
1860
1861static void dsp_opcode_cmpq(void)
1862{
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 };
1865#ifdef DSP_DIS_CMPQ
1866 if (doDSPDis)
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);
1868#endif
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);
1872#ifdef DSP_DIS_CMPQ
1873 if (doDSPDis)
1874 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
1875#endif
1876}
1877
1878
1879static void dsp_opcode_and(void)
1880{
1881#ifdef DSP_DIS_AND
1882 if (doDSPDis)
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);
1884#endif
1885 RN = RN & RM;
1886 SET_ZN(RN);
1887#ifdef DSP_DIS_AND
1888 if (doDSPDis)
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);
1890#endif
1891}
1892
1893
1894static void dsp_opcode_or(void)
1895{
1896#ifdef DSP_DIS_OR
1897 if (doDSPDis)
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);
1899#endif
1900 RN = RN | RM;
1901 SET_ZN(RN);
1902#ifdef DSP_DIS_OR
1903 if (doDSPDis)
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);
1905#endif
1906}
1907
1908
1909static void dsp_opcode_xor(void)
1910{
1911#ifdef DSP_DIS_XOR
1912 if (doDSPDis)
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);
1914#endif
1915 RN = RN ^ RM;
1916 SET_ZN(RN);
1917#ifdef DSP_DIS_XOR
1918 if (doDSPDis)
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);
1920#endif
1921}
1922
1923
1924static void dsp_opcode_not(void)
1925{
1926#ifdef DSP_DIS_NOT
1927 if (doDSPDis)
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);
1929#endif
1930 RN = ~RN;
1931 SET_ZN(RN);
1932#ifdef DSP_DIS_NOT
1933 if (doDSPDis)
1934 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1935#endif
1936}
1937
1938
1939static void dsp_opcode_move_pc(void)
1940{
1941 RN = dsp_pc - 2;
1942}
1943
1944
1945static void dsp_opcode_store_r14_indexed(void)
1946{
1947#ifdef DSP_DIS_STORE14I
1948 if (doDSPDis)
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));
1950#endif
1951#ifdef DSP_CORRECT_ALIGNMENT_STORE
1952 DSPWriteLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1953#else
1954 DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1955#endif
1956}
1957
1958
1959static void dsp_opcode_store_r15_indexed(void)
1960{
1961#ifdef DSP_DIS_STORE15I
1962 if (doDSPDis)
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));
1964#endif
1965#ifdef DSP_CORRECT_ALIGNMENT_STORE
1966 DSPWriteLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1967#else
1968 DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), RN, DSP);
1969#endif
1970}
1971
1972
1973static void dsp_opcode_load_r14_ri(void)
1974{
1975#ifdef DSP_DIS_LOAD14R
1976 if (doDSPDis)
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);
1978#endif
1979#ifdef DSP_CORRECT_ALIGNMENT
1980 RN = DSPReadLong((dsp_reg[14] + RM) & 0xFFFFFFFC, DSP);
1981#else
1982 RN = DSPReadLong(dsp_reg[14] + RM, DSP);
1983#endif
1984#ifdef DSP_DIS_LOAD14R
1985 if (doDSPDis)
1986 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
1987#endif
1988}
1989
1990
1991static void dsp_opcode_load_r15_ri(void)
1992{
1993#ifdef DSP_DIS_LOAD15R
1994 if (doDSPDis)
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);
1996#endif
1997#ifdef DSP_CORRECT_ALIGNMENT
1998 RN = DSPReadLong((dsp_reg[15] + RM) & 0xFFFFFFFC, DSP);
1999#else
2000 RN = DSPReadLong(dsp_reg[15] + RM, DSP);
2001#endif
2002#ifdef DSP_DIS_LOAD15R
2003 if (doDSPDis)
2004 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2005#endif
2006}
2007
2008
2009static void dsp_opcode_store_r14_ri(void)
2010{
2011 DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
2012}
2013
2014
2015static void dsp_opcode_store_r15_ri(void)
2016{
2017 DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
2018}
2019
2020
2021static void dsp_opcode_nop(void)
2022{
2023#ifdef DSP_DIS_NOP
2024 if (doDSPDis)
2025 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", dsp_pc-2, dsp_flag_n, dsp_flag_c, dsp_flag_z);
2026#endif
2027}
2028
2029
2030static void dsp_opcode_storeb(void)
2031{
2032#ifdef DSP_DIS_STOREB
2033 if (doDSPDis)
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);
2035#endif
2036 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2037 DSPWriteLong(RM, RN & 0xFF, DSP);
2038 else
2039 JaguarWriteByte(RM, RN, DSP);
2040}
2041
2042
2043static void dsp_opcode_storew(void)
2044{
2045#ifdef DSP_DIS_STOREW
2046 if (doDSPDis)
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);
2048#endif
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);
2052 else
2053 JaguarWriteWord(RM & 0xFFFFFFFE, RN, DSP);
2054#else
2055 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2056 DSPWriteLong(RM, RN & 0xFFFF, DSP);
2057 else
2058 JaguarWriteWord(RM, RN, DSP);
2059#endif
2060}
2061
2062
2063static void dsp_opcode_store(void)
2064{
2065#ifdef DSP_DIS_STORE
2066 if (doDSPDis)
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);
2068#endif
2069#ifdef DSP_CORRECT_ALIGNMENT_STORE
2070 DSPWriteLong(RM & 0xFFFFFFFC, RN, DSP);
2071#else
2072 DSPWriteLong(RM, RN, DSP);
2073#endif
2074}
2075
2076
2077static void dsp_opcode_loadb(void)
2078{
2079#ifdef DSP_DIS_LOADB
2080 if (doDSPDis)
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);
2082#endif
2083 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2084 RN = DSPReadLong(RM, DSP) & 0xFF;
2085 else
2086 RN = JaguarReadByte(RM, DSP);
2087#ifdef DSP_DIS_LOADB
2088 if (doDSPDis)
2089 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2090#endif
2091}
2092
2093
2094static void dsp_opcode_loadw(void)
2095{
2096#ifdef DSP_DIS_LOADW
2097 if (doDSPDis)
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);
2099#endif
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;
2103 else
2104 RN = JaguarReadWord(RM & 0xFFFFFFFE, DSP);
2105#else
2106 if (RM >= DSP_WORK_RAM_BASE && RM <= (DSP_WORK_RAM_BASE + 0x1FFF))
2107 RN = DSPReadLong(RM, DSP) & 0xFFFF;
2108 else
2109 RN = JaguarReadWord(RM, DSP);
2110#endif
2111#ifdef DSP_DIS_LOADW
2112 if (doDSPDis)
2113 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2114#endif
2115}
2116
2117
2118static void dsp_opcode_load(void)
2119{
2120#ifdef DSP_DIS_LOAD
2121 if (doDSPDis)
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);
2123#endif
2124#ifdef DSP_CORRECT_ALIGNMENT
2125 RN = DSPReadLong(RM & 0xFFFFFFFC, DSP);
2126#else
2127 RN = DSPReadLong(RM, DSP);
2128#endif
2129#ifdef DSP_DIS_LOAD
2130 if (doDSPDis)
2131 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2132#endif
2133}
2134
2135
2136static void dsp_opcode_load_r14_indexed(void)
2137{
2138#ifdef DSP_DIS_LOAD14I
2139 if (doDSPDis)
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);
2141#endif
2142#ifdef DSP_CORRECT_ALIGNMENT
2143 RN = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2144#else
2145 RN = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[IMM_1] << 2), DSP);
2146#endif
2147#ifdef DSP_DIS_LOAD14I
2148 if (doDSPDis)
2149 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2150#endif
2151}
2152
2153
2154static void dsp_opcode_load_r15_indexed(void)
2155{
2156#ifdef DSP_DIS_LOAD15I
2157 if (doDSPDis)
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);
2159#endif
2160#ifdef DSP_CORRECT_ALIGNMENT
2161 RN = DSPReadLong((dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[IMM_1] << 2), DSP);
2162#else
2163 RN = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[IMM_1] << 2), DSP);
2164#endif
2165#ifdef DSP_DIS_LOAD15I
2166 if (doDSPDis)
2167 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2168#endif
2169}
2170
2171
2172static void dsp_opcode_movei(void)
2173{
2174#ifdef DSP_DIS_MOVEI
2175 if (doDSPDis)
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);
2177#endif
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);
2180 dsp_pc += 4;
2181#ifdef DSP_DIS_MOVEI
2182 if (doDSPDis)
2183 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2184#endif
2185}
2186
2187
2188static void dsp_opcode_moveta(void)
2189{
2190#ifdef DSP_DIS_MOVETA
2191 if (doDSPDis)
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);
2193#endif
2194 ALTERNATE_RN = RM;
2195#ifdef DSP_DIS_MOVETA
2196 if (doDSPDis)
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);
2198#endif
2199}
2200
2201
2202static void dsp_opcode_movefa(void)
2203{
2204#ifdef DSP_DIS_MOVEFA
2205 if (doDSPDis)
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);
2207#endif
2208 RN = ALTERNATE_RM;
2209#ifdef DSP_DIS_MOVEFA
2210 if (doDSPDis)
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);
2212#endif
2213}
2214
2215
2216static void dsp_opcode_move(void)
2217{
2218#ifdef DSP_DIS_MOVE
2219 if (doDSPDis)
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);
2221#endif
2222 RN = RM;
2223#ifdef DSP_DIS_MOVE
2224 if (doDSPDis)
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);
2226#endif
2227}
2228
2229
2230static void dsp_opcode_moveq(void)
2231{
2232#ifdef DSP_DIS_MOVEQ
2233 if (doDSPDis)
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);
2235#endif
2236 RN = IMM_1;
2237#ifdef DSP_DIS_MOVEQ
2238 if (doDSPDis)
2239 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2240#endif
2241}
2242
2243
2244static void dsp_opcode_resmac(void)
2245{
2246#ifdef DSP_DIS_RESMAC
2247 if (doDSPDis)
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));
2249#endif
2250 RN = (uint32_t)dsp_acc;
2251#ifdef DSP_DIS_RESMAC
2252 if (doDSPDis)
2253 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2254#endif
2255}
2256
2257
2258static void dsp_opcode_imult(void)
2259{
2260#ifdef DSP_DIS_IMULT
2261 if (doDSPDis)
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);
2263#endif
2264 RN = (int16_t)RN * (int16_t)RM;
2265 SET_ZN(RN);
2266#ifdef DSP_DIS_IMULT
2267 if (doDSPDis)
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);
2269#endif
2270}
2271
2272
2273static void dsp_opcode_mult(void)
2274{
2275#ifdef DSP_DIS_MULT
2276 if (doDSPDis)
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);
2278#endif
2279 RN = (uint16_t)RM * (uint16_t)RN;
2280 SET_ZN(RN);
2281#ifdef DSP_DIS_MULT
2282 if (doDSPDis)
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);
2284#endif
2285}
2286
2287
2288static void dsp_opcode_bclr(void)
2289{
2290#ifdef DSP_DIS_BCLR
2291 if (doDSPDis)
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);
2293#endif
2294 uint32_t res = RN & ~(1 << IMM_1);
2295 RN = res;
2296 SET_ZN(res);
2297#ifdef DSP_DIS_BCLR
2298 if (doDSPDis)
2299 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2300#endif
2301}
2302
2303
2304static void dsp_opcode_btst(void)
2305{
2306#ifdef DSP_DIS_BTST
2307 if (doDSPDis)
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);
2309#endif
2310 dsp_flag_z = (~RN >> IMM_1) & 1;
2311#ifdef DSP_DIS_BTST
2312 if (doDSPDis)
2313 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2314#endif
2315}
2316
2317
2318static void dsp_opcode_bset(void)
2319{
2320#ifdef DSP_DIS_BSET
2321 if (doDSPDis)
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);
2323#endif
2324 uint32_t res = RN | (1 << IMM_1);
2325 RN = res;
2326 SET_ZN(res);
2327#ifdef DSP_DIS_BSET
2328 if (doDSPDis)
2329 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2330#endif
2331}
2332
2333
2334static void dsp_opcode_subqt(void)
2335{
2336#ifdef DSP_DIS_SUBQT
2337 if (doDSPDis)
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);
2339#endif
2340 RN -= dsp_convert_zero[IMM_1];
2341#ifdef DSP_DIS_SUBQT
2342 if (doDSPDis)
2343 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2344#endif
2345}
2346
2347
2348static void dsp_opcode_addqt(void)
2349{
2350#ifdef DSP_DIS_ADDQT
2351 if (doDSPDis)
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);
2353#endif
2354 RN += dsp_convert_zero[IMM_1];
2355#ifdef DSP_DIS_ADDQT
2356 if (doDSPDis)
2357 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2358#endif
2359}
2360
2361
2362static void dsp_opcode_imacn(void)
2363{
2364#ifdef DSP_DIS_IMACN
2365 if (doDSPDis)
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);
2367#endif
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
2372 if (doDSPDis)
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));
2374#endif
2375}
2376
2377
2378static void dsp_opcode_mtoi(void)
2379{
2380 RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
2381 SET_ZN(RN);
2382}
2383
2384
2385static void dsp_opcode_normi(void)
2386{
2387 uint32_t _Rm = RM;
2388 uint32_t res = 0;
2389
2390 if (_Rm)
2391 {
2392 while ((_Rm & 0xffc00000) == 0)
2393 {
2394 _Rm <<= 1;
2395 res--;
2396 }
2397 while ((_Rm & 0xff800000) != 0)
2398 {
2399 _Rm >>= 1;
2400 res++;
2401 }
2402 }
2403 RN = res;
2404 SET_ZN(RN);
2405}
2406
2407
2408static void dsp_opcode_mmult(void)
2409{
2410 int count = dsp_matrix_control&0x0f;
2411 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
2412 int64_t accum = 0;
2413 uint32_t res;
2414
2415 if (!(dsp_matrix_control & 0x10))
2416 {
2417 for (int i = 0; i < count; i++)
2418 {
2419 int16_t a;
2420 if (i&0x01)
2421 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2422 else
2423 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2424 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2425 accum += a*b;
2426 addr += 4;
2427 }
2428 }
2429 else
2430 {
2431 for (int i = 0; i < count; i++)
2432 {
2433 int16_t a;
2434 if (i&0x01)
2435 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
2436 else
2437 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
2438 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
2439 accum += a*b;
2440 addr += 4 * count;
2441 }
2442 }
2443 RN = res = (int32_t)accum;
2444 // carry flag to do
2445//NOTE: The flags are set based upon the last add/multiply done...
2446 SET_ZN(RN);
2447}
2448
2449
2450static void dsp_opcode_abs(void)
2451{
2452#ifdef DSP_DIS_ABS
2453 if (doDSPDis)
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);
2455#endif
2456 uint32_t _Rn = RN;
2457 uint32_t res;
2458
2459 if (_Rn == 0x80000000)
2460 dsp_flag_n = 1;
2461 else
2462 {
2463 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
2464 res = RN = (_Rn & 0x80000000 ? -_Rn : _Rn);
2465 CLR_ZN; SET_Z(res);
2466 }
2467#ifdef DSP_DIS_ABS
2468 if (doDSPDis)
2469 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2470#endif
2471}
2472
2473
2474static void dsp_opcode_div(void)
2475{
2476#if 0
2477 if (RM)
2478 {
2479 if (dsp_div_control & 0x01) // 16.16 division
2480 {
2481 dsp_remain = ((uint64_t)RN << 16) % RM;
2482 RN = ((uint64_t)RN << 16) / RM;
2483 }
2484 else
2485 {
2486 // We calculate the remainder first because we destroy RN after
2487 // this by assigning it to itself.
2488 dsp_remain = RN % RM;
2489 RN = RN / RM;
2490 }
2491
2492 }
2493 else
2494 {
2495 // This is what happens according to SCPCD. NYAN!
2496 RN = 0xFFFFFFFF;
2497 dsp_remain = 0;
2498 }
2499#else
2500 // Real algorithm, courtesy of SCPCD: NYAN!
2501 uint32_t q = RN;
2502 uint32_t r = 0;
2503
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;
2508
2509 for(int i=0; i<32; i++)
2510 {
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);
2516 }
2517
2518 RN = q;
2519 dsp_remain = r;
2520#endif
2521}
2522
2523
2524static void dsp_opcode_imultn(void)
2525{
2526#ifdef DSP_DIS_IMULTN
2527 if (doDSPDis)
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);
2529#endif
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;
2533 SET_ZN(res);
2534#ifdef DSP_DIS_IMULTN
2535 if (doDSPDis)
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));
2537#endif
2538}
2539
2540
2541static void dsp_opcode_neg(void)
2542{
2543#ifdef DSP_DIS_NEG
2544 if (doDSPDis)
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);
2546#endif
2547 uint32_t res = -RN;
2548 SET_ZNC_SUB(0, RN, res);
2549 RN = res;
2550#ifdef DSP_DIS_NEG
2551 if (doDSPDis)
2552 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2553#endif
2554}
2555
2556
2557static void dsp_opcode_shlq(void)
2558{
2559#ifdef DSP_DIS_SHLQ
2560 if (doDSPDis)
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);
2562#endif
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;
2567 RN = res;
2568#ifdef DSP_DIS_SHLQ
2569 if (doDSPDis)
2570 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2571#endif
2572}
2573
2574
2575static void dsp_opcode_shrq(void)
2576{
2577#ifdef DSP_DIS_SHRQ
2578 if (doDSPDis)
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);
2580#endif
2581 int32_t r1 = dsp_convert_zero[IMM_1];
2582 uint32_t res = RN >> r1;
2583 SET_ZN(res); dsp_flag_c = RN & 1;
2584 RN = res;
2585#ifdef DSP_DIS_SHRQ
2586 if (doDSPDis)
2587 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2588#endif
2589}
2590
2591
2592static void dsp_opcode_ror(void)
2593{
2594#ifdef DSP_DIS_ROR
2595 if (doDSPDis)
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);
2597#endif
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;
2601 RN = res;
2602#ifdef DSP_DIS_ROR
2603 if (doDSPDis)
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);
2605#endif
2606}
2607
2608
2609static void dsp_opcode_rorq(void)
2610{
2611#ifdef DSP_DIS_RORQ
2612 if (doDSPDis)
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);
2614#endif
2615 uint32_t r1 = dsp_convert_zero[IMM_1 & 0x1F];
2616 uint32_t r2 = RN;
2617 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
2618 RN = res;
2619 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
2620#ifdef DSP_DIS_RORQ
2621 if (doDSPDis)
2622 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2623#endif
2624}
2625
2626
2627static void dsp_opcode_sha(void)
2628{
2629 int32_t sRm=(int32_t)RM;
2630 uint32_t _Rn=RN;
2631
2632 if (sRm<0)
2633 {
2634 uint32_t shift=-sRm;
2635 if (shift>=32) shift=32;
2636 dsp_flag_c=(_Rn&0x80000000)>>31;
2637 while (shift)
2638 {
2639 _Rn<<=1;
2640 shift--;
2641 }
2642 }
2643 else
2644 {
2645 uint32_t shift=sRm;
2646 if (shift>=32) shift=32;
2647 dsp_flag_c=_Rn&0x1;
2648 while (shift)
2649 {
2650 _Rn=((int32_t)_Rn)>>1;
2651 shift--;
2652 }
2653 }
2654 RN = _Rn;
2655 SET_ZN(RN);
2656}
2657
2658
2659static void dsp_opcode_sharq(void)
2660{
2661#ifdef DSP_DIS_SHARQ
2662 if (doDSPDis)
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);
2664#endif
2665 uint32_t res = (int32_t)RN >> dsp_convert_zero[IMM_1];
2666 SET_ZN(res); dsp_flag_c = RN & 0x01;
2667 RN = res;
2668#ifdef DSP_DIS_SHARQ
2669 if (doDSPDis)
2670 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2671#endif
2672}
2673
2674
2675static void dsp_opcode_sh(void)
2676{
2677 int32_t sRm=(int32_t)RM;
2678 uint32_t _Rn=RN;
2679
2680 if (sRm<0)
2681 {
2682 uint32_t shift=(-sRm);
2683 if (shift>=32) shift=32;
2684 dsp_flag_c=(_Rn&0x80000000)>>31;
2685 while (shift)
2686 {
2687 _Rn<<=1;
2688 shift--;
2689 }
2690 }
2691 else
2692 {
2693 uint32_t shift=sRm;
2694 if (shift>=32) shift=32;
2695 dsp_flag_c=_Rn&0x1;
2696 while (shift)
2697 {
2698 _Rn>>=1;
2699 shift--;
2700 }
2701 }
2702 RN = _Rn;
2703 SET_ZN(RN);
2704}
2705
2706void dsp_opcode_addqmod(void)
2707{
2708#ifdef DSP_DIS_ADDQMOD
2709 if (doDSPDis)
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);
2711#endif
2712 uint32_t r1 = dsp_convert_zero[IMM_1];
2713 uint32_t r2 = RN;
2714 uint32_t res = r2 + r1;
2715 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2716 RN = res;
2717 SET_ZNC_ADD(r2, r1, res);
2718#ifdef DSP_DIS_ADDQMOD
2719 if (doDSPDis)
2720 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN);
2721#endif
2722}
2723
2724void dsp_opcode_subqmod(void)
2725{
2726 uint32_t r1 = dsp_convert_zero[IMM_1];
2727 uint32_t r2 = RN;
2728 uint32_t res = r2 - r1;
2729 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
2730 RN = res;
2731
2732 SET_ZNC_SUB(r2, r1, res);
2733}
2734
2735void dsp_opcode_mirror(void)
2736{
2737 uint32_t r1 = RN;
2738 RN = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
2739 SET_ZN(RN);
2740}
2741
2742void dsp_opcode_sat32s(void)
2743{
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;
2747 RN = res;
2748 SET_ZN(res);
2749}
2750
2751void dsp_opcode_sat16s(void)
2752{
2753 int32_t r2 = RN;
2754 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
2755 RN = res;
2756 SET_ZN(res);
2757}
2758
2759void dsp_opcode_illegal(void)
2760{
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);
2763}
2764
2765//
2766// New pipelined DSP core
2767//
2768
2769static void DSP_abs(void);
2770static void DSP_add(void);
2771static void DSP_addc(void);
2772static void DSP_addq(void);
2773static void DSP_addqmod(void);
2774static void DSP_addqt(void);
2775static void DSP_and(void);
2776static void DSP_bclr(void);
2777static void DSP_bset(void);
2778static void DSP_btst(void);
2779static void DSP_cmp(void);
2780static void DSP_cmpq(void);
2781static void DSP_div(void);
2782static void DSP_imacn(void);
2783static void DSP_imult(void);
2784static void DSP_imultn(void);
2785static void DSP_illegal(void);
2786static void DSP_jr(void);
2787static void DSP_jump(void);
2788static void DSP_load(void);
2789static void DSP_loadb(void);
2790static void DSP_loadw(void);
2791static void DSP_load_r14_i(void);
2792static void DSP_load_r14_r(void);
2793static void DSP_load_r15_i(void);
2794static void DSP_load_r15_r(void);
2795static void DSP_mirror(void);
2796static void DSP_mmult(void);
2797static void DSP_move(void);
2798static void DSP_movefa(void);
2799static void DSP_movei(void);
2800static void DSP_movepc(void);
2801static void DSP_moveq(void);
2802static void DSP_moveta(void);
2803static void DSP_mtoi(void);
2804static void DSP_mult(void);
2805static void DSP_neg(void);
2806static void DSP_nop(void);
2807static void DSP_normi(void);
2808static void DSP_not(void);
2809static void DSP_or(void);
2810static void DSP_resmac(void);
2811static void DSP_ror(void);
2812static void DSP_rorq(void);
2813static void DSP_sat16s(void);
2814static void DSP_sat32s(void);
2815static void DSP_sh(void);
2816static void DSP_sha(void);
2817static void DSP_sharq(void);
2818static void DSP_shlq(void);
2819static void DSP_shrq(void);
2820static void DSP_store(void);
2821static void DSP_storeb(void);
2822static void DSP_storew(void);
2823static void DSP_store_r14_i(void);
2824static void DSP_store_r14_r(void);
2825static void DSP_store_r15_i(void);
2826static void DSP_store_r15_r(void);
2827static void DSP_sub(void);
2828static void DSP_subc(void);
2829static void DSP_subq(void);
2830static void DSP_subqmod(void);
2831static void DSP_subqt(void);
2832static void DSP_xor(void);
2833
2834void (* DSPOpcode[64])() =
2835{
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,
2840
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,
2845
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,
2850
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
2855};
2856
2857bool readAffected[64][2] =
2858{
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},
2863
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},
2868
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},
2873
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}
2878};
2879
2880bool isLoadStore[65] =
2881{
2882 false, false, false, false, false, false, false, false,
2883 false, false, false, false, false, false, false, false,
2884
2885 false, false, false, false, false, false, false, false,
2886 false, false, false, false, false, false, false, false,
2887
2888 false, false, false, false, false, false, false, true,
2889 true, true, false, true, true, true, true, true,
2890
2891 false, true, true, false, false, false, false, false,
2892 false, false, true, true, true, true, false, false, false
2893};
2894
2895void FlushDSPPipeline(void)
2896{
2897 plPtrFetch = 3, plPtrRead = 2, plPtrExec = 1, plPtrWrite = 0;
2898
2899 for(int i=0; i<4; i++)
2900 pipeline[i].opcode = PIPELINE_STALL;
2901
2902 for(int i=0; i<32; i++)
2903 scoreboard[i] = 0;
2904}
2905
2906//
2907// New pipelined DSP execution core
2908//
2909/*void DSPExecP(int32_t cycles)
2910{
2911// bool inhibitFetch = false;
2912
2913 dsp_releaseTimeSlice_flag = 0;
2914 dsp_in_exec++;
2915
2916 while (cycles > 0 && DSP_RUNNING)
2917 {
2918WriteLog("DSPExecP: Pipeline status...\n");
2919WriteLog("\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);
2920WriteLog("\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);
2921WriteLog("\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);
2922WriteLog("\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);
2923WriteLog(" --> Scoreboard: ");
2924for(int i=0; i<32; i++)
2925 WriteLog("%s ", scoreboard[i] ? "T" : "F");
2926WriteLog("\n");
2927 // Stage 1: Instruction fetch
2928// if (!inhibitFetch)
2929// {
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);
2937// }
2938// else
2939// inhibitFetch = false;
2940WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrFetch].instruction, dsp_pc);
2941
2942WriteLog("DSPExecP: Pipeline status (after stage 1)...\n");
2943WriteLog("\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);
2944WriteLog("\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);
2945WriteLog("\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);
2946WriteLog("\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...
2953{
2954//This is crappy, crappy CRAPPY! And it doesn't work! !!! FIX !!!
2955// dsp_pc -= (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
2956WriteLog(" --> Stalling pipeline: scoreboard = %s\n", scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
2957 pipeline[plPtrFetch] = pipeline[plPtrRead];
2958 pipeline[plPtrRead].opcode = PIPELINE_STALL;
2959}
2960 else
2961 {
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
2965
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);
2974 }
2975
2976WriteLog("DSPExecP: Pipeline status (after stage 2)...\n");
2977WriteLog("\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);
2978WriteLog("\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);
2979WriteLog("\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);
2980WriteLog("\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);
2981 // Stage 3: Execute
2982 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
2983 {
2984WriteLog("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];
2988 }
2989 else
2990 cycles--;
2991
2992WriteLog("DSPExecP: Pipeline status (after stage 3)...\n");
2993WriteLog("\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);
2994WriteLog("\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);
2995WriteLog("\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);
2996WriteLog("\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)
2999 {
3000 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3001 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3002
3003 scoreboard[pipeline[plPtrWrite].operand1]
3004 = scoreboard[pipeline[plPtrWrite].operand2] = false;
3005 }
3006
3007 // Push instructions through the pipeline...
3008 plPtrFetch = (++plPtrFetch) & 0x03;
3009 plPtrRead = (++plPtrRead) & 0x03;
3010 plPtrExec = (++plPtrExec) & 0x03;
3011 plPtrWrite = (++plPtrWrite) & 0x03;
3012 }
3013
3014 dsp_in_exec--;
3015}*/
3016
3017
3018//Problems: JR and any other instruction that relies on DSP_PC is getting WRONG values!
3019//!!! FIX !!!
3020// Should be fixed now. Another problem is figuring how to do the sequence following
3021// a branch followed with the JR & JUMP instructions...
3022//
3023// There are two conflicting problems:
3024
3025/*
3026F1B236: LOAD (R31), R03 [NCZ:000, R31=00F1CFDC, R03=00F14000] -> [NCZ:000, R03=00F1B084]
3027F1B238: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3028F1B23A: ADDQ #2, R03 [NCZ:000, R03=00F1B084] -> [NCZ:000, R03=00F1B086]
3029F1B23C: SUBQ #1, R17 [NCZ:000, R17=00000040] -> [NCZ:000, R17=0000003F]
3030F1B23E: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3031F1B244: JR z, F1B254 [NCZ:000] Branch NOT taken.
3032F1B246: BSET #10, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004431]
3033F1B248: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1A148] -> [NCZ:000, R01=00F1A100]
3034F1B24E: STORE R00, (R01) [NCZ:000, R00=00004431, R01=00F1A100]
3035DSP: Writing 00004431 to DSP_FLAGS by DSP...
3036DSP: 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)!
3039F1B250: JUMP T, (R03) [NCZ:001, R03=00000000] Branched!
3040F1B252: NOP [NCZ:001]
3041*/
3042
3043// The other is when you see this at the end of an IRQ:
3044
3045/*
3046JUMP T, (R29) ; R29 = Previous stack + 2
3047STORE R28, (R30) ; R28 = Modified flags register, R30 = $F1A100
3048
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
3054
3055JUMP 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!
3057*/
3058
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...
3061
3062
3063/*
3064Small problem here: The return address when INT0 comes up is $F1B088, but when INT1
3065follows it, the JUMP out of the previous interrupt is bypassed immediately--this is
3066because the STORE instruction writes back on stage #2 of the pipeline instead of stage #3...
3067If it were done properly, the STORE write back would occur *after* (well, technically,
3068during) the execution of the the JUMP that follows it.
3069
3070!!! FIX !!! [DONE]
3071
3072F1B08A: JR z, F1B082 [NCZ:001] Branched!
3073F1B08A: NOP [NCZ:001]
3074[STALL...]
3075F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3076[STALL...]
3077[STALL...]
3078F1B086: LOAD (R00), R01 [NCZ:001, R00=00F1B178, R01=00000000] -> [NCZ:001, R01=00000000]
3079[STALL...]
3080[STALL...]
3081F1B088: OR R01, R01 [NCZ:001, R01=00000000, R01=00000000] -> [NCZ:001, R01=00000000, R01=00000000]
3082F1B08A: JR z, F1B082 [NCZ:001] Branched!
3083F1B08A: NOP [NCZ:001]
3084[STALL...]
3085F1B080: MOVEI #$00F1B178, R00 [NCZ:001, R00=00F1B178] -> [NCZ:001, R00=00F1B178]
3086[STALL...]
3087[STALL...]
3088Write to DSP CTRL: 00002301 --> Starting to run at 00F1B088 by M68K...
3089DSP: CPU -> DSP interrupt
3090DSP: Generating interrupt #0... [PC will return to 00F1B088, R31 = 00F1CFE0]
3091Write to DSP CTRL: 00000001 --> Starting to run at 00F1B000 by M68K...
3092[STALL...]
3093F1B000: MOVEI #$00F1B0D4, R30 [NCZ:001, R30=00F1B000] -> [NCZ:001, R30=00F1B0D4]
3094[STALL...]
3095[STALL...]
3096F1B006: JUMP T, (R30) [NCZ:001, R30=00F1B0D4] Branched!
3097F1B006: NOP [NCZ:001]
3098[STALL...]
3099F1B0D4: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3100[STALL...]
3101[STALL...]
3102F1B0DA: LOAD (R01), R00 [NCZ:001, R01=00F1A100, R00=00004431] -> [NCZ:001, R00=00004039]
3103F1B0DC: MOVEI #$00F1B0C8, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1B0C8]
3104[STALL...]
3105[STALL...]
3106F1B0E2: LOAD (R01), R02 [NCZ:001, R01=00F1B0C8, R02=00000000] -> [NCZ:001, R02=00000001]
3107F1B0E4: MOVEI #$00F1B0CC, R01 [NCZ:001, R01=00F1B0C8] -> [NCZ:001, R01=00F1B0CC]
3108[STALL...]
3109[STALL...]
3110F1B0EA: LOAD (R01), R03 [NCZ:001, R01=00F1B0CC, R03=00F1B086] -> [NCZ:001, R03=00000064]
3111F1B0EC: MOVEI #$00F1B0D0, R01 [NCZ:001, R01=00F1B0CC] -> [NCZ:001, R01=00F1B0D0]
3112[STALL...]
3113[STALL...]
3114F1B0F2: LOAD (R01), R04 [NCZ:001, R01=00F1B0D0, R04=00000000] -> [NCZ:001, R04=00000008]
3115F1B0F4: MOVEI #$00F1B0BC, R01 [NCZ:001, R01=00F1B0D0] -> [NCZ:001, R01=00F1B0BC]
3116[STALL...]
3117[STALL...]
3118F1B0FA: ADD R04, R01 [NCZ:001, R04=00000008, R01=00F1B0BC] -> [NCZ:000, R04=00000008, R01=00F1B0C4]
3119[STALL...]
3120[STALL...]
3121F1B0FC: LOAD (R01), R01 [NCZ:000, R01=00F1B0C4, R01=00F1B0C4] -> [NCZ:000, R01=00F1B12E]
3122[STALL...]
3123[STALL...]
3124F1B0FE: JUMP T, (R01) [NCZ:000, R01=00F1B12E] Branched!
3125F1B0FE: NOP [NCZ:000]
3126[STALL...]
3127F1B12E: MOVE R02, R08 [NCZ:000, R02=00000001, R08=00000000] -> [NCZ:000, R02=00000001, R08=00000001]
3128[STALL...]
3129[STALL...]
3130F1B132: MOVEI #$00F1B102, R01 [NCZ:000, R01=00F1B12E] -> [NCZ:000, R01=00F1B102]
3131[STALL...]
3132[STALL...]
3133F1B138: JUMP T, (R01) [NCZ:000, R01=00F1B102] Branched!
3134F1B138: NOP [NCZ:000]
3135[STALL...]
3136F1B102: MOVEI #$00F1B0C8, R01 [NCZ:000, R01=00F1B102] -> [NCZ:000, R01=00F1B0C8]
3137[STALL...]
3138[STALL...]
3139F1B108: STORE R08, (R01) [NCZ:000, R08=00000000, R01=00F1B0C8]
3140F1B10A: MOVEI #$00F1B0D0, R01 [NCZ:000, R01=00F1B0C8] -> [NCZ:000, R01=00F1B0D0]
3141F1B110: MOVEQ #0, R04 [NCZ:000, R04=00000008] -> [NCZ:000, R04=00000000]
3142[STALL...]
3143[STALL...]
3144F1B112: STORE R04, (R01) [NCZ:000, R04=00000000, R01=00F1B0D0]
3145F1B114: BCLR #3, R00 [NCZ:000, R00=00004039] -> [NCZ:000, R00=00004031]
3146[STALL...]
3147[STALL...]
3148F1B116: BSET #9, R00 [NCZ:000, R00=00004031] -> [NCZ:000, R00=00004231]
3149F1B118: LOAD (R31), R04 [NCZ:000, R31=00F1CFDC, R04=00000000] -> [NCZ:000, R04=00F1B086]
3150F1B11A: MOVEI #$00F1CFE0, R31 [NCZ:000, R31=00F1CFDC] -> [NCZ:000, R31=00F1CFE0]
3151[STALL...]
3152F1B120: ADDQ #2, R04 [NCZ:000, R04=00F1B086] -> [NCZ:000, R04=00F1B088]
3153F1B122: MOVEI #$00F1A100, R01 [NCZ:000, R01=00F1B0D0] -> [NCZ:000, R01=00F1A100]
3154[STALL...]
3155[STALL...]
3156F1B128: STORE R00, (R01) [NCZ:000, R00=00004231, R01=00F1A100]
3157DSP: Writing 00004231 to DSP_FLAGS by DSP (REGPAGE is set)...
3158DSP: Finished interrupt.
3159DSP: Generating interrupt #1... [PC will return to 00F1B12A, R31 = 00F1CFE0]
3160[STALL...]
3161F1B010: MOVEI #$00F1B1FC, R30 [NCZ:001, R30=00F1B010] -> [NCZ:001, R30=00F1B1FC]
3162[STALL...]
3163[STALL...]
3164F1B016: JUMP T, (R30) [NCZ:001, R30=00F1B1FC] Branched!
3165F1B016: NOP [NCZ:001]
3166[STALL...]
3167F1B1FC: MOVEI #$00F1A100, R01 [NCZ:001, R01=00F1A100] -> [NCZ:001, R01=00F1A100]
3168*/
3169
3170uint32_t pcQueue1[0x400];
3171uint32_t pcQPtr1 = 0;
3172static uint32_t prevR1;
3173//Let's try a 3 stage pipeline....
3174//Looks like 3 stage is correct, otherwise bad things happen...
3175void DSPExecP2(int32_t cycles)
3176{
3177 dsp_releaseTimeSlice_flag = 0;
3178 dsp_in_exec++;
3179
3180 while (cycles > 0 && DSP_RUNNING)
3181 {
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)
3186//F1B140:
3187if (totalFrames >= 377 && GET16(dsp_ram_8, 0x0002F6) == 0xAC38 && dsp_pc == 0xF1B140)
3188{
3189 doDSPDis = true;
3190 WriteLog("Starting disassembly at frame #%u...\n", totalFrames);
3191}
3192if (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];
3205
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]
3208
3209
3210pcQueue1[pcQPtr1++] = dsp_pc;
3211pcQPtr1 &= 0x3FF;
3212
3213#ifdef DSP_DEBUG_PL2
3214if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF) && !doDSPDis)
3215{
3216 WriteLog("DSP: PC has stepped out of bounds...\n\nBacktrace:\n\n");
3217 doDSPDis = true;
3218
3219 char buffer[512];
3220
3221 for(int i=0; i<0x400; i++)
3222 {
3223 dasmjag(JAGUAR_DSP, buffer, pcQueue1[(i + pcQPtr1) & 0x3FF]);
3224 WriteLog("\t%08X: %s\n", pcQueue1[(i + pcQPtr1) & 0x3FF], buffer);
3225 }
3226 WriteLog("\n");
3227}//*/
3228#endif
3229
3230 if (IMASKCleared) // If IMASK was cleared,
3231 {
3232#ifdef DSP_DEBUG_IRQ
3233 WriteLog("DSP: Finished interrupt.\n");
3234#endif
3235 DSPHandleIRQs(); // See if any other interrupts are pending!
3236 IMASKCleared = false;
3237 }
3238
3239//if (dsp_flags & REGPAGE)
3240// WriteLog(" --> REGPAGE has just been set!\n");
3241#ifdef DSP_DEBUG_PL2
3242if (doDSPDis)
3243{
3244WriteLog("DSPExecP: Pipeline status [PC=%08X]...\n", dsp_pc);
3245WriteLog("\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]);
3246WriteLog("\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]);
3247WriteLog("\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]);
3248WriteLog(" --> Scoreboard: ");
3249for(int i=0; i<32; i++)
3250 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3251WriteLog("\n");
3252}
3253#endif
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
3263if (doDSPDis)
3264{
3265WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3266WriteLog("DSPExecP: Pipeline status (after stage 1a) [PC=%08X]...\n", dsp_pc);
3267WriteLog("\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]);
3268WriteLog("\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]);
3269WriteLog("\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]);
3270}
3271#endif
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 !!!
3275//Ugly, but [DONE]
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
3283//work--somewhat...
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
3287{
3288if (doDSPDis)
3289{
3290WriteLog(" --> Stalling pipeline: ");
3291if (readAffected[pipeline[plPtrRead].opcode][0])
3292 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3293if (readAffected[pipeline[plPtrRead].opcode][1])
3294 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3295WriteLog("\n");
3296}
3297#endif
3298 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3299#ifdef DSP_DEBUG_PL2
3300}
3301#endif
3302 else
3303 {
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
3307
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];
3312#else
3313//Hopefully this will fix the dual MOVEQ # problem...
3314 scoreboard[pipeline[plPtrRead].operand2] += (affectsScoreboard[pipeline[plPtrRead].opcode] ? 1 : 0);
3315#endif
3316
3317//Advance PC here??? Yes.
3318 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3319 }
3320
3321#ifdef DSP_DEBUG_PL2
3322if (doDSPDis)
3323{
3324WriteLog("DSPExecP: Pipeline status (after stage 1b) [PC=%08X]...\n", dsp_pc);
3325WriteLog("\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]);
3326WriteLog("\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]);
3327WriteLog("\tW -> %02u, %02u, %02u; r1=%08X, r2= %08X, res=%08X, wb=%u (%s)\n", pipeline[plPtrWrite].opcode, pipeline[plPtrWrite].operand1, pipeline[plPtrWrite].operand2, pipeline[plPtrWrite].reg1, pipeline[plPtrWrite].reg2, pipeline[plPtrWrite].result, pipeline[plPtrWrite].writebackRegister, dsp_opcode_str[pipeline[plPtrWrite].opcode]);
3328}
3329#endif
3330 // Stage 2: Execute
3331 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3332 {
3333#ifdef DSP_DEBUG_PL2
3334if (doDSPDis)
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"));
3336
3337if (doDSPDis)
3338{
3339WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3340}
3341#endif
3342//CC only!
3343#ifdef DSP_DEBUG_CC
3344lastExec = pipeline[plPtrExec].instruction;
3345//WriteLog("[lastExec = %04X]\n", lastExec);
3346#endif
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);
3351 }
3352 else
3353{
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
3363if (doDSPDis)
3364 WriteLog("[STALL... DSP_PC = %08X]\n", dsp_pc);
3365#endif
3366}
3367
3368#ifdef DSP_DEBUG_PL2
3369if (doDSPDis)
3370{
3371WriteLog("DSPExecP: Pipeline status (after stage 2) [PC=%08X]...\n", dsp_pc);
3372WriteLog("\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]);
3373WriteLog("\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]);
3374WriteLog("\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]);
3375WriteLog("\n");
3376}
3377#endif
3378 // Stage 3: Write back register/memory address
3379 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3380 {
3381/*if (pipeline[plPtrWrite].writebackRegister == 3
3382 && (pipeline[plPtrWrite].result < 0xF14000 || pipeline[plPtrWrite].result > 0xF1CFFF)
3383 && !doDSPDis)
3384{
3385 WriteLog("DSP: Register R03 has stepped out of bounds...\n\n");
3386 doDSPDis = true;
3387}//*/
3388 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3389 {
3390 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3391 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3392 else
3393 {
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);
3398 else
3399 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3400 }
3401 }
3402
3403#ifndef NEW_SCOREBOARD
3404 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3405 scoreboard[pipeline[plPtrWrite].operand2] = false;
3406#else
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]--;
3411#endif
3412 }
3413
3414 // Push instructions through the pipeline...
3415 plPtrRead = (++plPtrRead) & 0x03;
3416 plPtrExec = (++plPtrExec) & 0x03;
3417 plPtrWrite = (++plPtrWrite) & 0x03;
3418 }
3419
3420 dsp_in_exec--;
3421}
3422
3423
3424
3425/*
3426//#define DSP_DEBUG_PL3
3427//Let's try a 2 stage pipeline....
3428void DSPExecP3(int32_t cycles)
3429{
3430 dsp_releaseTimeSlice_flag = 0;
3431 dsp_in_exec++;
3432
3433 while (cycles > 0 && DSP_RUNNING)
3434 {
3435//if (dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFF)
3436// doDSPDis = true;
3437#ifdef DSP_DEBUG_PL3
3438WriteLog("DSPExecP: Pipeline status...\n");
3439WriteLog("\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]);
3440WriteLog("\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]);
3441WriteLog(" --> Scoreboard: ");
3442for(int i=0; i<32; i++)
3443 WriteLog("%s ", scoreboard[i] ? "T" : "F");
3444WriteLog("\n");
3445#endif
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
3455WriteLog("DSPExecP: Fetching instruction (%04X) from DSP_PC = %08X...\n", pipeline[plPtrRead].instruction, dsp_pc);
3456WriteLog("DSPExecP: Pipeline status (after stage 1a)...\n");
3457WriteLog("\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]);
3458WriteLog("\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]);
3459#endif
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
3465{
3466WriteLog(" --> Stalling pipeline: ");
3467if (readAffected[pipeline[plPtrRead].opcode][0])
3468 WriteLog("scoreboard[%u] = %s (reg 1) ", pipeline[plPtrRead].operand1, scoreboard[pipeline[plPtrRead].operand1] ? "true" : "false");
3469if (readAffected[pipeline[plPtrRead].opcode][1])
3470 WriteLog("scoreboard[%u] = %s (reg 2)", pipeline[plPtrRead].operand2, scoreboard[pipeline[plPtrRead].operand2] ? "true" : "false");
3471WriteLog("\n");
3472#endif
3473 pipeline[plPtrRead].opcode = PIPELINE_STALL;
3474#ifdef DSP_DEBUG_PL3
3475}
3476#endif
3477 else
3478 {
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
3482
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];
3486
3487//Advance PC here??? Yes.
3488 dsp_pc += (pipeline[plPtrRead].opcode == 38 ? 6 : 2);
3489 }
3490
3491#ifdef DSP_DEBUG_PL3
3492WriteLog("DSPExecP: Pipeline status (after stage 1b)...\n");
3493WriteLog("\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]);
3494WriteLog("\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]);
3495#endif
3496 // Stage 2a: Execute
3497 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3498 {
3499#ifdef DSP_DEBUG_PL3
3500WriteLog("DSPExecP: About to execute opcode %s...\n", dsp_opcode_str[pipeline[plPtrExec].opcode]);
3501#endif
3502 DSPOpcode[pipeline[plPtrExec].opcode]();
3503 dsp_opcode_use[pipeline[plPtrExec].opcode]++;
3504 cycles -= dsp_opcode_cycles[pipeline[plPtrExec].opcode];
3505 }
3506 else
3507 cycles--;
3508
3509#ifdef DSP_DEBUG_PL3
3510WriteLog("DSPExecP: Pipeline status (after stage 2a)...\n");
3511WriteLog("\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]);
3512WriteLog("\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]);
3513WriteLog("\n");
3514#endif
3515 // Stage 2b: Write back register
3516 if (pipeline[plPtrExec].opcode != PIPELINE_STALL)
3517 {
3518 if (pipeline[plPtrExec].writebackRegister != 0xFF)
3519 dsp_reg[pipeline[plPtrExec].writebackRegister] = pipeline[plPtrExec].result;
3520
3521 if (affectsScoreboard[pipeline[plPtrExec].opcode])
3522 scoreboard[pipeline[plPtrExec].operand2] = false;
3523 }
3524
3525 // Push instructions through the pipeline...
3526 plPtrRead = (++plPtrRead) & 0x03;
3527 plPtrExec = (++plPtrExec) & 0x03;
3528 }
3529
3530 dsp_in_exec--;
3531}*/
3532
3533//
3534// DSP pipelined opcode handlers
3535//
3536
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
3547
3548static void DSP_abs(void)
3549{
3550#ifdef DSP_DIS_ABS
3551 if (doDSPDis)
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);
3553#endif
3554 uint32_t _Rn = PRN;
3555
3556 if (_Rn == 0x80000000)
3557 dsp_flag_n = 1;
3558 else
3559 {
3560 dsp_flag_c = ((_Rn & 0x80000000) >> 31);
3561 PRES = (_Rn & 0x80000000 ? -_Rn : _Rn);
3562 CLR_ZN; SET_Z(PRES);
3563 }
3564#ifdef DSP_DIS_ABS
3565 if (doDSPDis)
3566 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3567#endif
3568}
3569
3570static void DSP_add(void)
3571{
3572#ifdef DSP_DIS_ADD
3573 if (doDSPDis)
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);
3575#endif
3576 uint32_t res = PRN + PRM;
3577 SET_ZNC_ADD(PRN, PRM, res);
3578 PRES = res;
3579#ifdef DSP_DIS_ADD
3580 if (doDSPDis)
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);
3582#endif
3583}
3584
3585static void DSP_addc(void)
3586{
3587#ifdef DSP_DIS_ADDC
3588 if (doDSPDis)
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);
3590#endif
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);
3596 PRES = res;
3597#ifdef DSP_DIS_ADDC
3598 if (doDSPDis)
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);
3600#endif
3601}
3602
3603static void DSP_addq(void)
3604{
3605#ifdef DSP_DIS_ADDQ
3606 if (doDSPDis)
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);
3608#endif
3609 uint32_t r1 = dsp_convert_zero[PIMM1];
3610 uint32_t res = PRN + r1;
3611 CLR_ZNC; SET_ZNC_ADD(PRN, r1, res);
3612 PRES = res;
3613#ifdef DSP_DIS_ADDQ
3614 if (doDSPDis)
3615 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3616#endif
3617}
3618
3619static void DSP_addqmod(void)
3620{
3621#ifdef DSP_DIS_ADDQMOD
3622 if (doDSPDis)
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);
3624#endif
3625 uint32_t r1 = dsp_convert_zero[PIMM1];
3626 uint32_t r2 = PRN;
3627 uint32_t res = r2 + r1;
3628 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
3629 PRES = res;
3630 SET_ZNC_ADD(r2, r1, res);
3631#ifdef DSP_DIS_ADDQMOD
3632 if (doDSPDis)
3633 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3634#endif
3635}
3636
3637static void DSP_addqt(void)
3638{
3639#ifdef DSP_DIS_ADDQT
3640 if (doDSPDis)
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);
3642#endif
3643 PRES = PRN + dsp_convert_zero[PIMM1];
3644#ifdef DSP_DIS_ADDQT
3645 if (doDSPDis)
3646 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3647#endif
3648}
3649
3650static void DSP_and(void)
3651{
3652#ifdef DSP_DIS_AND
3653 if (doDSPDis)
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);
3655#endif
3656 PRES = PRN & PRM;
3657 SET_ZN(PRES);
3658#ifdef DSP_DIS_AND
3659 if (doDSPDis)
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);
3661#endif
3662}
3663
3664static void DSP_bclr(void)
3665{
3666#ifdef DSP_DIS_BCLR
3667 if (doDSPDis)
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);
3669#endif
3670 PRES = PRN & ~(1 << PIMM1);
3671 SET_ZN(PRES);
3672#ifdef DSP_DIS_BCLR
3673 if (doDSPDis)
3674 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3675#endif
3676}
3677
3678static void DSP_bset(void)
3679{
3680#ifdef DSP_DIS_BSET
3681 if (doDSPDis)
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);
3683#endif
3684 PRES = PRN | (1 << PIMM1);
3685 SET_ZN(PRES);
3686#ifdef DSP_DIS_BSET
3687 if (doDSPDis)
3688 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
3689#endif
3690}
3691
3692static void DSP_btst(void)
3693{
3694#ifdef DSP_DIS_BTST
3695 if (doDSPDis)
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);
3697#endif
3698 dsp_flag_z = (~PRN >> PIMM1) & 1;
3699 NO_WRITEBACK;
3700#ifdef DSP_DIS_BTST
3701 if (doDSPDis)
3702 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
3703#endif
3704}
3705
3706static void DSP_cmp(void)
3707{
3708#ifdef DSP_DIS_CMP
3709 if (doDSPDis)
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);
3711#endif
3712 uint32_t res = PRN - PRM;
3713 SET_ZNC_SUB(PRN, PRM, res);
3714 NO_WRITEBACK;
3715#ifdef DSP_DIS_CMP
3716 if (doDSPDis)
3717 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3718#endif
3719}
3720
3721static void DSP_cmpq(void)
3722{
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 };
3725#ifdef DSP_DIS_CMPQ
3726 if (doDSPDis)
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);
3728#endif
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);
3732 NO_WRITEBACK;
3733#ifdef DSP_DIS_CMPQ
3734 if (doDSPDis)
3735 WriteLog("[NCZ:%u%u%u]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z);
3736#endif
3737}
3738
3739static void DSP_div(void)
3740{
3741 uint32_t _Rm = PRM, _Rn = PRN;
3742
3743 if (_Rm)
3744 {
3745 if (dsp_div_control & 1)
3746 {
3747 dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
3748 if (dsp_remain & 0x80000000)
3749 dsp_remain -= _Rm;
3750 PRES = (((uint64_t)_Rn) << 16) / _Rm;
3751 }
3752 else
3753 {
3754 dsp_remain = _Rn % _Rm;
3755 if (dsp_remain & 0x80000000)
3756 dsp_remain -= _Rm;
3757 PRES = PRN / _Rm;
3758 }
3759 }
3760 else
3761 PRES = 0xFFFFFFFF;
3762}
3763
3764static void DSP_imacn(void)
3765{
3766#ifdef DSP_DIS_IMACN
3767 if (doDSPDis)
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);
3769#endif
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???
3773 NO_WRITEBACK;
3774#ifdef DSP_DIS_IMACN
3775 if (doDSPDis)
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));
3777#endif
3778}
3779
3780static void DSP_imult(void)
3781{
3782#ifdef DSP_DIS_IMULT
3783 if (doDSPDis)
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);
3785#endif
3786 PRES = (int16_t)PRN * (int16_t)PRM;
3787 SET_ZN(PRES);
3788#ifdef DSP_DIS_IMULT
3789 if (doDSPDis)
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);
3791#endif
3792}
3793
3794static void DSP_imultn(void)
3795{
3796#ifdef DSP_DIS_IMULTN
3797 if (doDSPDis)
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);
3799#endif
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;
3803 SET_ZN(res);
3804 NO_WRITEBACK;
3805#ifdef DSP_DIS_IMULTN
3806 if (doDSPDis)
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));
3808#endif
3809}
3810
3811static void DSP_illegal(void)
3812{
3813#ifdef DSP_DIS_ILLEGAL
3814 if (doDSPDis)
3815 WriteLog("%06X: ILLEGAL [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
3816#endif
3817 NO_WRITEBACK;
3818}
3819
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...
3825static void DSP_jr(void)
3826{
3827#ifdef DSP_DIS_JR
3828const 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" };
3833 if (doDSPDis)
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);
3836#endif
3837 // KLUDGE: Used by BRANCH_CONDITION macro
3838 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3839
3840 if (BRANCH_CONDITION(PIMM2))
3841 {
3842#ifdef DSP_DIS_JR
3843 if (doDSPDis)
3844 WriteLog("Branched!\n");
3845#endif
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);
3850
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
3853 // the new PC.
3854
3855 // Step 1: Handle writebacks at stage 3 of pipeline
3856/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3857 {
3858 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3859 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3860
3861 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3862 scoreboard[pipeline[plPtrWrite].operand2] = false;
3863 }//*/
3864 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3865 {
3866 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3867 {
3868 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3869 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3870 else
3871 {
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);
3876 else
3877 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3878 }
3879 }
3880
3881#ifndef NEW_SCOREBOARD
3882 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3883 scoreboard[pipeline[plPtrWrite].operand2] = false;
3884#else
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]--;
3889#endif
3890 }
3891
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
3898 // the case!)...
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)
3904 {
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
3912 }//*/
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];
3917
3918 // Step 3: Flush pipeline & set new PC
3919 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
3920 dsp_pc = newPC;
3921 }
3922 else
3923#ifdef DSP_DIS_JR
3924 {
3925 if (doDSPDis)
3926 WriteLog("Branch NOT taken.\n");
3927#endif
3928 NO_WRITEBACK;
3929#ifdef DSP_DIS_JR
3930 }
3931#endif
3932// WriteLog(" --> DSP_PC: %08X\n", dsp_pc);
3933}
3934
3935static void DSP_jump(void)
3936{
3937#ifdef DSP_DIS_JUMP
3938const 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" };
3943 if (doDSPDis)
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);
3945#endif
3946 // KLUDGE: Used by BRANCH_CONDITION macro
3947 uint32_t jaguar_flags = (dsp_flag_n << 2) | (dsp_flag_c << 1) | dsp_flag_z;
3948
3949 if (BRANCH_CONDITION(PIMM2))
3950 {
3951#ifdef DSP_DIS_JUMP
3952 if (doDSPDis)
3953 WriteLog("Branched!\n");
3954#endif
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
3958 // the new PC.
3959
3960 // Step 1: Handle writebacks at stage 3 of pipeline
3961/* if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3962 {
3963 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3964 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3965
3966 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3967 scoreboard[pipeline[plPtrWrite].operand2] = false;
3968 }//*/
3969 if (pipeline[plPtrWrite].opcode != PIPELINE_STALL)
3970 {
3971 if (pipeline[plPtrWrite].writebackRegister != 0xFF)
3972 {
3973 if (pipeline[plPtrWrite].writebackRegister != 0xFE)
3974 dsp_reg[pipeline[plPtrWrite].writebackRegister] = pipeline[plPtrWrite].result;
3975 else
3976 {
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);
3981 else
3982 JaguarWriteLong(pipeline[plPtrWrite].address, pipeline[plPtrWrite].value);
3983 }
3984 }
3985
3986#ifndef NEW_SCOREBOARD
3987 if (affectsScoreboard[pipeline[plPtrWrite].opcode])
3988 scoreboard[pipeline[plPtrWrite].operand2] = false;
3989#else
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]--;
3994#endif
3995 }
3996
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
4003 // the case!)...
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)
4010 {
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
4018 }//*/
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];
4023
4024 // Step 3: Flush pipeline & set new PC
4025 pipeline[plPtrRead].opcode = pipeline[plPtrExec].opcode = PIPELINE_STALL;
4026 dsp_pc = PCSave;
4027 }
4028 else
4029#ifdef DSP_DIS_JUMP
4030 {
4031 if (doDSPDis)
4032 WriteLog("Branch NOT taken.\n");
4033#endif
4034 NO_WRITEBACK;
4035#ifdef DSP_DIS_JUMP
4036 }
4037#endif
4038}
4039
4040static void DSP_load(void)
4041{
4042#ifdef DSP_DIS_LOAD
4043 if (doDSPDis)
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);
4045#endif
4046#ifdef DSP_CORRECT_ALIGNMENT
4047 PRES = DSPReadLong(PRM & 0xFFFFFFFC, DSP);
4048#else
4049 PRES = DSPReadLong(PRM, DSP);
4050#endif
4051#ifdef DSP_DIS_LOAD
4052 if (doDSPDis)
4053 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4054#endif
4055}
4056
4057static void DSP_loadb(void)
4058{
4059#ifdef DSP_DIS_LOADB
4060 if (doDSPDis)
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);
4062#endif
4063 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4064 PRES = DSPReadLong(PRM, DSP) & 0xFF;
4065 else
4066 PRES = JaguarReadByte(PRM, DSP);
4067#ifdef DSP_DIS_LOADB
4068 if (doDSPDis)
4069 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4070#endif
4071}
4072
4073static void DSP_loadw(void)
4074{
4075#ifdef DSP_DIS_LOADW
4076 if (doDSPDis)
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);
4078#endif
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;
4082 else
4083 PRES = JaguarReadWord(PRM & 0xFFFFFFFE, DSP);
4084#else
4085 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4086 PRES = DSPReadLong(PRM, DSP) & 0xFFFF;
4087 else
4088 PRES = JaguarReadWord(PRM, DSP);
4089#endif
4090#ifdef DSP_DIS_LOADW
4091 if (doDSPDis)
4092 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4093#endif
4094}
4095
4096static void DSP_load_r14_i(void)
4097{
4098#ifdef DSP_DIS_LOAD14I
4099 if (doDSPDis)
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);
4101#endif
4102#ifdef DSP_CORRECT_ALIGNMENT
4103 PRES = DSPReadLong((dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4104#else
4105 PRES = DSPReadLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), DSP);
4106#endif
4107#ifdef DSP_DIS_LOAD14I
4108 if (doDSPDis)
4109 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4110#endif
4111}
4112
4113static void DSP_load_r14_r(void)
4114{
4115#ifdef DSP_DIS_LOAD14R
4116 if (doDSPDis)
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);
4118#endif
4119#ifdef DSP_CORRECT_ALIGNMENT
4120 PRES = DSPReadLong((dsp_reg[14] + PRM) & 0xFFFFFFFC, DSP);
4121#else
4122 PRES = DSPReadLong(dsp_reg[14] + PRM, DSP);
4123#endif
4124#ifdef DSP_DIS_LOAD14R
4125 if (doDSPDis)
4126 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4127#endif
4128}
4129
4130static void DSP_load_r15_i(void)
4131{
4132#ifdef DSP_DIS_LOAD15I
4133 if (doDSPDis)
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);
4135#endif
4136#ifdef DSP_CORRECT_ALIGNMENT
4137 PRES = DSPReadLong((dsp_reg[15] &0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2), DSP);
4138#else
4139 PRES = DSPReadLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), DSP);
4140#endif
4141#ifdef DSP_DIS_LOAD15I
4142 if (doDSPDis)
4143 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4144#endif
4145}
4146
4147static void DSP_load_r15_r(void)
4148{
4149#ifdef DSP_DIS_LOAD15R
4150 if (doDSPDis)
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);
4152#endif
4153#ifdef DSP_CORRECT_ALIGNMENT
4154 PRES = DSPReadLong((dsp_reg[15] + PRM) & 0xFFFFFFFC, DSP);
4155#else
4156 PRES = DSPReadLong(dsp_reg[15] + PRM, DSP);
4157#endif
4158#ifdef DSP_DIS_LOAD15R
4159 if (doDSPDis)
4160 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4161#endif
4162}
4163
4164static void DSP_mirror(void)
4165{
4166 uint32_t r1 = PRN;
4167 PRES = (mirror_table[r1 & 0xFFFF] << 16) | mirror_table[r1 >> 16];
4168 SET_ZN(PRES);
4169}
4170
4171static void DSP_mmult(void)
4172{
4173 int count = dsp_matrix_control&0x0f;
4174 uint32_t addr = dsp_pointer_to_matrix; // in the dsp ram
4175 int64_t accum = 0;
4176 uint32_t res;
4177
4178 if (!(dsp_matrix_control & 0x10))
4179 {
4180 for (int i = 0; i < count; i++)
4181 {
4182 int16_t a;
4183 if (i&0x01)
4184 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4185 else
4186 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4187 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4188 accum += a*b;
4189 addr += 4;
4190 }
4191 }
4192 else
4193 {
4194 for (int i = 0; i < count; i++)
4195 {
4196 int16_t a;
4197 if (i&0x01)
4198 a=(int16_t)((dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]>>16)&0xffff);
4199 else
4200 a=(int16_t)(dsp_alternate_reg[dsp_opcode_first_parameter + (i>>1)]&0xffff);
4201 int16_t b=((int16_t)DSPReadWord(addr + 2, DSP));
4202 accum += a*b;
4203 addr += 4 * count;
4204 }
4205 }
4206
4207 PRES = res = (int32_t)accum;
4208 // carry flag to do
4209//NOTE: The flags are set based upon the last add/multiply done...
4210 SET_ZN(PRES);
4211}
4212
4213static void DSP_move(void)
4214{
4215#ifdef DSP_DIS_MOVE
4216 if (doDSPDis)
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);
4218#endif
4219 PRES = PRM;
4220#ifdef DSP_DIS_MOVE
4221 if (doDSPDis)
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);
4223#endif
4224}
4225
4226static void DSP_movefa(void)
4227{
4228#ifdef DSP_DIS_MOVEFA
4229 if (doDSPDis)
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);
4232#endif
4233// PRES = ALTERNATE_RM;
4234 PRES = dsp_alternate_reg[PIMM1];
4235#ifdef DSP_DIS_MOVEFA
4236 if (doDSPDis)
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);
4239#endif
4240}
4241
4242static void DSP_movei(void)
4243{
4244#ifdef DSP_DIS_MOVEI
4245 if (doDSPDis)
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);
4247#endif
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);
4250// dsp_pc += 4;
4251#ifdef DSP_DIS_MOVEI
4252 if (doDSPDis)
4253 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4254#endif
4255}
4256
4257static void DSP_movepc(void)
4258{
4259#ifdef DSP_DIS_MOVEPC
4260 if (doDSPDis)
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);
4262#endif
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
4268 if (doDSPDis)
4269 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4270#endif
4271}
4272
4273static void DSP_moveq(void)
4274{
4275#ifdef DSP_DIS_MOVEQ
4276 if (doDSPDis)
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);
4278#endif
4279 PRES = PIMM1;
4280#ifdef DSP_DIS_MOVEQ
4281 if (doDSPDis)
4282 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4283#endif
4284}
4285
4286static void DSP_moveta(void)
4287{
4288#ifdef DSP_DIS_MOVETA
4289 if (doDSPDis)
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]);
4292#endif
4293// ALTERNATE_RN = PRM;
4294 dsp_alternate_reg[PIMM2] = PRM;
4295 NO_WRITEBACK;
4296#ifdef DSP_DIS_MOVETA
4297 if (doDSPDis)
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]);
4300#endif
4301}
4302
4303static void DSP_mtoi(void)
4304{
4305 PRES = (((int32_t)PRM >> 8) & 0xFF800000) | (PRM & 0x007FFFFF);
4306 SET_ZN(PRES);
4307}
4308
4309static void DSP_mult(void)
4310{
4311#ifdef DSP_DIS_MULT
4312 if (doDSPDis)
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);
4314#endif
4315 PRES = (uint16_t)PRM * (uint16_t)PRN;
4316 SET_ZN(PRES);
4317#ifdef DSP_DIS_MULT
4318 if (doDSPDis)
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);
4320#endif
4321}
4322
4323static void DSP_neg(void)
4324{
4325#ifdef DSP_DIS_NEG
4326 if (doDSPDis)
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);
4328#endif
4329 uint32_t res = -PRN;
4330 SET_ZNC_SUB(0, PRN, res);
4331 PRES = res;
4332#ifdef DSP_DIS_NEG
4333 if (doDSPDis)
4334 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4335#endif
4336}
4337
4338static void DSP_nop(void)
4339{
4340#ifdef DSP_DIS_NOP
4341 if (doDSPDis)
4342 WriteLog("%06X: NOP [NCZ:%u%u%u]\n", DSP_PPC, dsp_flag_n, dsp_flag_c, dsp_flag_z);
4343#endif
4344 NO_WRITEBACK;
4345}
4346
4347static void DSP_normi(void)
4348{
4349 uint32_t _Rm = PRM;
4350 uint32_t res = 0;
4351
4352 if (_Rm)
4353 {
4354 while ((_Rm & 0xffc00000) == 0)
4355 {
4356 _Rm <<= 1;
4357 res--;
4358 }
4359 while ((_Rm & 0xff800000) != 0)
4360 {
4361 _Rm >>= 1;
4362 res++;
4363 }
4364 }
4365 PRES = res;
4366 SET_ZN(PRES);
4367}
4368
4369static void DSP_not(void)
4370{
4371#ifdef DSP_DIS_NOT
4372 if (doDSPDis)
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);
4374#endif
4375 PRES = ~PRN;
4376 SET_ZN(PRES);
4377#ifdef DSP_DIS_NOT
4378 if (doDSPDis)
4379 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4380#endif
4381}
4382
4383static void DSP_or(void)
4384{
4385#ifdef DSP_DIS_OR
4386 if (doDSPDis)
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);
4388#endif
4389 PRES = PRN | PRM;
4390 SET_ZN(PRES);
4391#ifdef DSP_DIS_OR
4392 if (doDSPDis)
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);
4394#endif
4395}
4396
4397static void DSP_resmac(void)
4398{
4399#ifdef DSP_DIS_RESMAC
4400 if (doDSPDis)
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));
4402#endif
4403 PRES = (uint32_t)dsp_acc;
4404#ifdef DSP_DIS_RESMAC
4405 if (doDSPDis)
4406 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRN);
4407#endif
4408}
4409
4410static void DSP_ror(void)
4411{
4412#ifdef DSP_DIS_ROR
4413 if (doDSPDis)
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);
4415#endif
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;
4419 PRES = res;
4420#ifdef DSP_DIS_ROR
4421 if (doDSPDis)
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);
4423#endif
4424}
4425
4426static void DSP_rorq(void)
4427{
4428#ifdef DSP_DIS_RORQ
4429 if (doDSPDis)
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);
4431#endif
4432 uint32_t r1 = dsp_convert_zero[PIMM1 & 0x1F];
4433 uint32_t r2 = PRN;
4434 uint32_t res = (r2 >> r1) | (r2 << (32 - r1));
4435 PRES = res;
4436 SET_ZN(res); dsp_flag_c = (r2 >> 31) & 0x01;
4437#ifdef DSP_DIS_RORQ
4438 if (doDSPDis)
4439 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4440#endif
4441}
4442
4443static void DSP_sat16s(void)
4444{
4445 int32_t r2 = PRN;
4446 uint32_t res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2;
4447 PRES = res;
4448 SET_ZN(res);
4449}
4450
4451static void DSP_sat32s(void)
4452{
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;
4456 PRES = res;
4457 SET_ZN(res);
4458}
4459
4460static void DSP_sh(void)
4461{
4462 int32_t sRm = (int32_t)PRM;
4463 uint32_t _Rn = PRN;
4464
4465 if (sRm < 0)
4466 {
4467 uint32_t shift = -sRm;
4468
4469 if (shift >= 32)
4470 shift = 32;
4471
4472 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4473
4474 while (shift)
4475 {
4476 _Rn <<= 1;
4477 shift--;
4478 }
4479 }
4480 else
4481 {
4482 uint32_t shift = sRm;
4483
4484 if (shift >= 32)
4485 shift = 32;
4486
4487 dsp_flag_c = _Rn & 0x1;
4488
4489 while (shift)
4490 {
4491 _Rn >>= 1;
4492 shift--;
4493 }
4494 }
4495
4496 PRES = _Rn;
4497 SET_ZN(PRES);
4498}
4499
4500static void DSP_sha(void)
4501{
4502 int32_t sRm = (int32_t)PRM;
4503 uint32_t _Rn = PRN;
4504
4505 if (sRm < 0)
4506 {
4507 uint32_t shift = -sRm;
4508
4509 if (shift >= 32)
4510 shift = 32;
4511
4512 dsp_flag_c = (_Rn & 0x80000000) >> 31;
4513
4514 while (shift)
4515 {
4516 _Rn <<= 1;
4517 shift--;
4518 }
4519 }
4520 else
4521 {
4522 uint32_t shift = sRm;
4523
4524 if (shift >= 32)
4525 shift = 32;
4526
4527 dsp_flag_c = _Rn & 0x1;
4528
4529 while (shift)
4530 {
4531 _Rn = ((int32_t)_Rn) >> 1;
4532 shift--;
4533 }
4534 }
4535
4536 PRES = _Rn;
4537 SET_ZN(PRES);
4538}
4539
4540static void DSP_sharq(void)
4541{
4542#ifdef DSP_DIS_SHARQ
4543 if (doDSPDis)
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);
4545#endif
4546 uint32_t res = (int32_t)PRN >> dsp_convert_zero[PIMM1];
4547 SET_ZN(res); dsp_flag_c = PRN & 0x01;
4548 PRES = res;
4549#ifdef DSP_DIS_SHARQ
4550 if (doDSPDis)
4551 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4552#endif
4553}
4554
4555static void DSP_shlq(void)
4556{
4557#ifdef DSP_DIS_SHLQ
4558 if (doDSPDis)
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);
4560#endif
4561 int32_t r1 = 32 - PIMM1;
4562 uint32_t res = PRN << r1;
4563 SET_ZN(res); dsp_flag_c = (PRN >> 31) & 1;
4564 PRES = res;
4565#ifdef DSP_DIS_SHLQ
4566 if (doDSPDis)
4567 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4568#endif
4569}
4570
4571static void DSP_shrq(void)
4572{
4573#ifdef DSP_DIS_SHRQ
4574 if (doDSPDis)
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);
4576#endif
4577 int32_t r1 = dsp_convert_zero[PIMM1];
4578 uint32_t res = PRN >> r1;
4579 SET_ZN(res); dsp_flag_c = PRN & 1;
4580 PRES = res;
4581#ifdef DSP_DIS_SHRQ
4582 if (doDSPDis)
4583 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4584#endif
4585}
4586
4587static void DSP_store(void)
4588{
4589#ifdef DSP_DIS_STORE
4590 if (doDSPDis)
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);
4592#endif
4593// DSPWriteLong(PRM, PRN, DSP);
4594// NO_WRITEBACK;
4595#ifdef DSP_CORRECT_ALIGNMENT_STORE
4596 pipeline[plPtrExec].address = PRM & 0xFFFFFFFC;
4597#else
4598 pipeline[plPtrExec].address = PRM;
4599#endif
4600 pipeline[plPtrExec].value = PRN;
4601 pipeline[plPtrExec].type = TYPE_DWORD;
4602 WRITEBACK_ADDR;
4603}
4604
4605static void DSP_storeb(void)
4606{
4607#ifdef DSP_DIS_STOREB
4608 if (doDSPDis)
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);
4610#endif
4611// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4612// DSPWriteLong(PRM, PRN & 0xFF, DSP);
4613// else
4614// JaguarWriteByte(PRM, PRN, DSP);
4615//
4616// NO_WRITEBACK;
4617 pipeline[plPtrExec].address = PRM;
4618
4619 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4620 {
4621 pipeline[plPtrExec].value = PRN & 0xFF;
4622 pipeline[plPtrExec].type = TYPE_DWORD;
4623 }
4624 else
4625 {
4626 pipeline[plPtrExec].value = PRN;
4627 pipeline[plPtrExec].type = TYPE_BYTE;
4628 }
4629
4630 WRITEBACK_ADDR;
4631}
4632
4633static void DSP_storew(void)
4634{
4635#ifdef DSP_DIS_STOREW
4636 if (doDSPDis)
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);
4638#endif
4639// if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4640// DSPWriteLong(PRM, PRN & 0xFFFF, DSP);
4641// else
4642// JaguarWriteWord(PRM, PRN, DSP);
4643//
4644// NO_WRITEBACK;
4645#ifdef DSP_CORRECT_ALIGNMENT_STORE
4646 pipeline[plPtrExec].address = PRM & 0xFFFFFFFE;
4647#else
4648 pipeline[plPtrExec].address = PRM;
4649#endif
4650
4651 if (PRM >= DSP_WORK_RAM_BASE && PRM <= (DSP_WORK_RAM_BASE + 0x1FFF))
4652 {
4653 pipeline[plPtrExec].value = PRN & 0xFFFF;
4654 pipeline[plPtrExec].type = TYPE_DWORD;
4655 }
4656 else
4657 {
4658 pipeline[plPtrExec].value = PRN;
4659 pipeline[plPtrExec].type = TYPE_WORD;
4660 }
4661 WRITEBACK_ADDR;
4662}
4663
4664static void DSP_store_r14_i(void)
4665{
4666#ifdef DSP_DIS_STORE14I
4667 if (doDSPDis)
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));
4669#endif
4670// DSPWriteLong(dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4671// NO_WRITEBACK;
4672#ifdef DSP_CORRECT_ALIGNMENT_STORE
4673 pipeline[plPtrExec].address = (dsp_reg[14] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4674#else
4675 pipeline[plPtrExec].address = dsp_reg[14] + (dsp_convert_zero[PIMM1] << 2);
4676#endif
4677 pipeline[plPtrExec].value = PRN;
4678 pipeline[plPtrExec].type = TYPE_DWORD;
4679 WRITEBACK_ADDR;
4680}
4681
4682static void DSP_store_r14_r(void)
4683{
4684// DSPWriteLong(dsp_reg[14] + PRM, PRN, DSP);
4685// NO_WRITEBACK;
4686#ifdef DSP_CORRECT_ALIGNMENT_STORE
4687 pipeline[plPtrExec].address = (dsp_reg[14] + PRM) & 0xFFFFFFFC;
4688#else
4689 pipeline[plPtrExec].address = dsp_reg[14] + PRM;
4690#endif
4691 pipeline[plPtrExec].value = PRN;
4692 pipeline[plPtrExec].type = TYPE_DWORD;
4693 WRITEBACK_ADDR;
4694}
4695
4696static void DSP_store_r15_i(void)
4697{
4698#ifdef DSP_DIS_STORE15I
4699 if (doDSPDis)
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));
4701#endif
4702// DSPWriteLong(dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2), PRN, DSP);
4703// NO_WRITEBACK;
4704#ifdef DSP_CORRECT_ALIGNMENT_STORE
4705 pipeline[plPtrExec].address = (dsp_reg[15] & 0xFFFFFFFC) + (dsp_convert_zero[PIMM1] << 2);
4706#else
4707 pipeline[plPtrExec].address = dsp_reg[15] + (dsp_convert_zero[PIMM1] << 2);
4708#endif
4709 pipeline[plPtrExec].value = PRN;
4710 pipeline[plPtrExec].type = TYPE_DWORD;
4711 WRITEBACK_ADDR;
4712}
4713
4714static void DSP_store_r15_r(void)
4715{
4716// DSPWriteLong(dsp_reg[15] + PRM, PRN, DSP);
4717// NO_WRITEBACK;
4718#ifdef DSP_CORRECT_ALIGNMENT_STORE
4719 pipeline[plPtrExec].address = (dsp_reg[15] + PRM) & 0xFFFFFFFC;
4720#else
4721 pipeline[plPtrExec].address = dsp_reg[15] + PRM;
4722#endif
4723 pipeline[plPtrExec].value = PRN;
4724 pipeline[plPtrExec].type = TYPE_DWORD;
4725 WRITEBACK_ADDR;
4726}
4727
4728static void DSP_sub(void)
4729{
4730#ifdef DSP_DIS_SUB
4731 if (doDSPDis)
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);
4733#endif
4734 uint32_t res = PRN - PRM;
4735 SET_ZNC_SUB(PRN, PRM, res);
4736 PRES = res;
4737#ifdef DSP_DIS_SUB
4738 if (doDSPDis)
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);
4740#endif
4741}
4742
4743static void DSP_subc(void)
4744{
4745#ifdef DSP_DIS_SUBC
4746 if (doDSPDis)
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);
4748#endif
4749 uint32_t res = PRN - PRM - dsp_flag_c;
4750 uint32_t borrow = dsp_flag_c;
4751 SET_ZNC_SUB(PRN - borrow, PRM, res);
4752 PRES = res;
4753#ifdef DSP_DIS_SUBC
4754 if (doDSPDis)
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);
4756#endif
4757}
4758
4759static void DSP_subq(void)
4760{
4761#ifdef DSP_DIS_SUBQ
4762 if (doDSPDis)
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);
4764#endif
4765 uint32_t r1 = dsp_convert_zero[PIMM1];
4766 uint32_t res = PRN - r1;
4767 SET_ZNC_SUB(PRN, r1, res);
4768 PRES = res;
4769#ifdef DSP_DIS_SUBQ
4770 if (doDSPDis)
4771 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4772#endif
4773}
4774
4775static void DSP_subqmod(void)
4776{
4777 uint32_t r1 = dsp_convert_zero[PIMM1];
4778 uint32_t r2 = PRN;
4779 uint32_t res = r2 - r1;
4780 res = (res & (~dsp_modulo)) | (r2 & dsp_modulo);
4781 PRES = res;
4782 SET_ZNC_SUB(r2, r1, res);
4783}
4784
4785static void DSP_subqt(void)
4786{
4787#ifdef DSP_DIS_SUBQT
4788 if (doDSPDis)
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);
4790#endif
4791 PRES = PRN - dsp_convert_zero[PIMM1];
4792#ifdef DSP_DIS_SUBQT
4793 if (doDSPDis)
4794 WriteLog("[NCZ:%u%u%u, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, PIMM2, PRES);
4795#endif
4796}
4797
4798static void DSP_xor(void)
4799{
4800#ifdef DSP_DIS_XOR
4801 if (doDSPDis)
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);
4803#endif
4804 PRES = PRN ^ PRM;
4805 SET_ZN(PRES);
4806#ifdef DSP_DIS_XOR
4807 if (doDSPDis)
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);
4809#endif
4810}