#include <SDL.h> // Used only for SDL_GetTicks...
#include <stdlib.h>
+#include <time.h>
#include "dac.h"
#include "gpu.h"
#include "jagdasm.h"
#include "jaguar.h"
#include "jerry.h"
#include "log.h"
-#include "m68k.h"
+#include "m68000/m68kinterface.h"
//#include "memory.h"
#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
-uint32 dsp_convert_zero[32] = { 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 };
-uint8 * dsp_branch_condition_table = NULL;
-static uint16 * mirror_table = NULL;
+uint32 dsp_convert_zero[32] = {
+ 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+};
+uint8 dsp_branch_condition_table[32 * 8];
+static uint16 mirror_table[65536];
static uint8 dsp_ram_8[0x2000];
#define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)]
void dsp_build_branch_condition_table(void)
{
- // Allocate the mirror table
- if (!mirror_table)
- mirror_table = (uint16 *)malloc(65536 * sizeof(uint16));
-
// Fill in the mirror table
- if (mirror_table)
- for(int i=0; i<65536; i++)
- mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) |
- ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) |
- ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) |
- ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) |
- ((i << 1) & 0x0100) | ((i << 3) & 0x0200) |
- ((i << 5) & 0x0400) | ((i << 7) & 0x0800) |
- ((i << 9) & 0x1000) | ((i << 11) & 0x2000) |
- ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
-
- if (!dsp_branch_condition_table)
+ for(int i=0; i<65536; i++)
{
- dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8));
+ mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002)
+ | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008)
+ | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020)
+ | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080)
+ | ((i << 1) & 0x0100) | ((i << 3) & 0x0200)
+ | ((i << 5) & 0x0400) | ((i << 7) & 0x0800)
+ | ((i << 9) & 0x1000) | ((i << 11) & 0x2000)
+ | ((i << 13) & 0x4000) | ((i << 15) & 0x8000);
+ }
- // Fill in the condition table
- if (dsp_branch_condition_table)
+ // Fill in the condition table
+ for(int i=0; i<8; i++)
+ {
+ for(int j=0; j<32; j++)
{
- for(int i=0; i<8; i++)
- {
- for(int j=0; j<32; j++)
- {
- int result = 1;
- if (j & 1)
- if (i & ZERO_FLAG)
- result = 0;
- if (j & 2)
- if (!(i & ZERO_FLAG))
- result = 0;
- if (j & 4)
- if (i & (CARRY_FLAG << (j >> 4)))
- result = 0;
- if (j & 8)
- if (!(i & (CARRY_FLAG << (j >> 4))))
- result = 0;
- dsp_branch_condition_table[i * 32 + j] = result;
- }
- }
+ int result = 1;
+
+ if ((j & 1) && (i & ZERO_FLAG))
+ result = 0;
+
+ if ((j & 2) && (!(i & ZERO_FLAG)))
+ result = 0;
+
+ if ((j & 4) && (i & (CARRY_FLAG << (j >> 4))))
+ result = 0;
+
+ if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4)))))
+ result = 0;
+
+ dsp_branch_condition_table[i * 32 + j] = result;
}
}
}
case 0x00:
{
#ifdef DSP_DEBUG
- WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %s)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "set" : "not set"));
+ WriteLog("DSP: Writing %08X to DSP_FLAGS by %s (REGPAGE is %sset)...\n", data, whoName[who], (dsp_flags & REGPAGE ? "" : "not "));
#endif
// bool IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
IMASKCleared = (dsp_flags & IMASK) && !(data & IMASK);
// interrupt, so that's what we check for here. Just know that this approach
// can be easily fooled!
// Note also that if both interrupts are enabled, the I2S freq will win. :-P
+
+// Further Note:
+// The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
+// audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
+// So, while this works, it's a by-product of the lame way in which audio is currently
+// handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
+// go away of its own accord. :-P
+// Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
+// weird is going on here...
+// Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
+// So subsequent interrupts come into the chip, but they're never serviced but the
+// I2S subsystem keeps going.
+// After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
+// IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
+// It seems that it's only stable for values of SCLK <= 9.
+
+// All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
+// that we don't actually need this stuff anymore. :-D
+#if 0
if (data & INT_ENA1) // I2S interrupt
{
int freq = GetCalculatedFrequency();
// WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
DACSetNewFrequency(freq);
}
+#endif
/* if (IMASKCleared) // If IMASK was cleared,
#ifdef DSP_DEBUG_IRQ
case 0x14:
{
//#ifdef DSP_DEBUG
-WriteLog("Write to DSP CTRL by %s: %08X\n", whoName[who], data);
+WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, dsp_pc);
//#endif
bool wasRunning = DSP_RUNNING;
// uint32 dsp_was_running = DSP_RUNNING;
// GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
}
+bool DSPIsRunning(void)
+{
+ return (DSP_RUNNING ? true : false);
+}
+
void DSPInit(void)
{
// memory_malloc_secure((void **)&dsp_ram_8, 0x2000, "DSP work RAM");
dsp_build_branch_condition_table();
DSPReset();
+ srand(time(NULL)); // For randomizing local RAM
}
void DSPReset(void)
IMASKCleared = false;
FlushDSPPipeline();
dsp_reset_stats();
- memset(dsp_ram_8, 0xFF, 0x2000);
+// memset(dsp_ram_8, 0xFF, 0x2000);
+ // Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
+ for(uint32 i=0; i<8192; i+=4)
+ {
+ *((uint32 *)(&dsp_ram_8[i])) = rand();
+ }
}
void DSPDumpDisassembly(void)
WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
uint32 j = 0xF1B000;
+
while (j <= 0xF1CFFF)
{
uint32 oldj = j;
//Shoud add modulus, etc to dump here...
WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc);
WriteLog("\nRegisters bank 0\n");
+
for(int j=0; j<8; j++)
{
WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
(j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
(j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
}
+
WriteLog("Registers bank 1\n");
+
for(int j=0; j<8; j++)
{
WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n",
void DSPDone(void)
{
int i, j;
- WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't"));
+ WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't"));
WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not "));
// get the active interrupt bits
(mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""),
(mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : ""));
WriteLog("\nRegisters bank 0\n");
+
for(int j=0; j<8; j++)
{
WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
(j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2],
(j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]);
}
+
WriteLog("\nRegisters bank 1\n");
+
for (j=0; j<8; j++)
{
WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n",
(j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1],
(j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2],
(j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]);
-
}
+ WriteLog("\n");
+
static char buffer[512];
j = DSP_WORK_RAM_BASE;
- while (j <= 0xF1BFFF)
+
+ while (j <= 0xF1CFFF)
{
uint32 oldj = j;
j += dasmjag(JAGUAR_DSP, buffer, j);
}//*/
WriteLog("DSP opcodes use:\n");
+
for (i=0;i<64;i++)
{
if (dsp_opcode_use[i])
// memory_free(dsp_ram_8);
// memory_free(dsp_reg_bank_0);
// memory_free(dsp_reg_bank_1);
- if (dsp_branch_condition_table)
- free(dsp_branch_condition_table);
+// if (dsp_branch_condition_table)
+// free(dsp_branch_condition_table);
- if (mirror_table)
- free(mirror_table);
+// if (mirror_table)
+// free(mirror_table);
}