#include "dsp.h"
#include "eeprom.h"
#include "event.h"
+#include "foooked.h"
#include "gpu.h"
#include "jerry.h"
#include "joystick.h"
#include "log.h"
#include "m68000/m68kinterface.h"
//#include "memory.h"
+#include "memtrack.h"
#include "mmu.h"
#include "settings.h"
#include "tom.h"
#define CPU_DEBUG_MEMORY
//#define LOG_CD_BIOS_CALLS
#define CPU_DEBUG_TRACING
+#define ALPINE_FUNCTIONS
// Private function prototypes
#endif
uint32_t pcQueue[0x400];
+uint32_t a0Queue[0x400];
+uint32_t a1Queue[0x400];
+uint32_t a2Queue[0x400];
+uint32_t a3Queue[0x400];
+uint32_t a4Queue[0x400];
+uint32_t a5Queue[0x400];
+uint32_t a6Queue[0x400];
+uint32_t a7Queue[0x400];
+uint32_t d0Queue[0x400];
+uint32_t d1Queue[0x400];
+uint32_t d2Queue[0x400];
+uint32_t d3Queue[0x400];
+uint32_t d4Queue[0x400];
+uint32_t d5Queue[0x400];
+uint32_t d6Queue[0x400];
+uint32_t d7Queue[0x400];
+uint32_t srQueue[0x400];
uint32_t pcQPtr = 0;
bool startM68KTracing = false;
+// Breakpoint on memory access vars (exported)
+bool bpmActive = false;
+uint32_t bpmAddress1;
+
+
//
// Callback function to detect illegal instructions
//
// For tracebacks...
// Ideally, we'd save all the registers as well...
- pcQueue[pcQPtr++] = m68kPC;
+ pcQueue[pcQPtr] = m68kPC;
+ a0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A0);
+ a1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A1);
+ a2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A2);
+ a3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A3);
+ a4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A4);
+ a5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A5);
+ a6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A6);
+ a7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_A7);
+ d0Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D0);
+ d1Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D1);
+ d2Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D2);
+ d3Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D3);
+ d4Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D4);
+ d5Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D5);
+ d6Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D6);
+ d7Queue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_D7);
+ srQueue[pcQPtr] = m68k_get_reg(NULL, M68K_REG_SR);
+ pcQPtr++;
pcQPtr &= 0x3FF;
if (m68kPC & 0x01) // Oops! We're fetching an odd address!
{
- WriteLog("M68K: Attempted to execute from an odd adress!\n\nBacktrace:\n\n");
+ WriteLog("M68K: Attempted to execute from an odd address!\n\nBacktrace:\n\n");
static char buffer[2048];
for(int i=0; i<0x400; i++)
{
+// WriteLog("[A2=%08X, D0=%08X]\n", a2Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF]);
+ WriteLog("[A0=%08X, A1=%08X, A2=%08X, A3=%08X, A4=%08X, A5=%08X, A6=%08X, A7=%08X, D0=%08X, D1=%08X, D2=%08X, D3=%08X, D4=%08X, D5=%08X, D6=%08X, D7=%08X, SR=%04X]\n", a0Queue[(pcQPtr + i) & 0x3FF], a1Queue[(pcQPtr + i) & 0x3FF], a2Queue[(pcQPtr + i) & 0x3FF], a3Queue[(pcQPtr + i) & 0x3FF], a4Queue[(pcQPtr + i) & 0x3FF], a5Queue[(pcQPtr + i) & 0x3FF], a6Queue[(pcQPtr + i) & 0x3FF], a7Queue[(pcQPtr + i) & 0x3FF], d0Queue[(pcQPtr + i) & 0x3FF], d1Queue[(pcQPtr + i) & 0x3FF], d2Queue[(pcQPtr + i) & 0x3FF], d3Queue[(pcQPtr + i) & 0x3FF], d4Queue[(pcQPtr + i) & 0x3FF], d5Queue[(pcQPtr + i) & 0x3FF], d6Queue[(pcQPtr + i) & 0x3FF], d7Queue[(pcQPtr + i) & 0x3FF], srQueue[(pcQPtr + i) & 0x3FF]);
m68k_disassemble(buffer, pcQueue[(pcQPtr + i) & 0x3FF], 0);//M68K_CPU_TYPE_68000);
WriteLog("\t%08X: %s\n", pcQueue[(pcQPtr + i) & 0x3FF], buffer);
}
; // Do nothing
}
+
void WriteWord(uint32_t adddress, uint16_t word)
{
}
+
void WriteDWord(uint32_t adddress, uint32_t dword)
{
}
+
uint8_t ReadByte(uint32_t adddress)
{
}
+
uint16_t ReadWord(uint32_t adddress)
{
}
+
uint32_t ReadDWord(uint32_t adddress)
{
}
#endif
+
void ShowM68KContext(void)
{
printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
while (disPC < (currpc + 10));
}
+
//
// Custom UAE 68000 read/write/IRQ functions
//
// IPL1 is connected to INTL on TOM (OUT to 68K)
// IPL0-2 are also tied to Vcc via 4.7K resistors!
// (DINT on TOM goes into DINT on JERRY (IN Tom from Jerry))
- // There doesn't seem to be any other path to IPL0 or 2 on the schematic, which means
- // that *all* IRQs to the 68K are routed thru TOM at level 2. Which means they're all maskable.
+ // There doesn't seem to be any other path to IPL0 or 2 on the schematic,
+ // which means that *all* IRQs to the 68K are routed thru TOM at level 2.
+ // Which means they're all maskable.
- // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work OK...
+ // The GPU/DSP/etc are probably *not* issuing an NMI, but it seems to work
+ // OK...
// They aren't, and this causes problems with a, err, specific ROM. :-D
if (level == 2)
return M68K_INT_ACK_AUTOVECTOR;
}
+
//#define USE_NEW_MMU
unsigned int m68k_read_memory_8(unsigned int address)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
#ifdef CPU_DEBUG_MEMORY
#endif
}
+
void gpu_dump_disassembly(void);
void gpu_dump_registers(void);
unsigned int m68k_read_memory_16(unsigned int address)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
#ifdef CPU_DEBUG_MEMORY
retVal = GET16(jaguarMainRAM, address);
// else if ((address >= 0x800000) && (address <= 0xDFFFFE))
else if ((address >= 0x800000) && (address <= 0xDFFEFE))
- retVal = (jaguarMainROM[address - 0x800000] << 8) | jaguarMainROM[address - 0x800000 + 1];
+ {
+ // Memory Track reading...
+ if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
+ {
+ retVal = MTReadWord(address);
+ }
+ else
+ retVal = (jaguarMainROM[address - 0x800000] << 8)
+ | jaguarMainROM[address - 0x800000 + 1];
+ }
else if ((address >= 0xE00000) && (address <= 0xE3FFFE))
// retVal = (jaguarBootROM[address - 0xE00000] << 8) | jaguarBootROM[address - 0xE00000 + 1];
// retVal = (jaguarDevBootROM1[address - 0xE00000] << 8) | jaguarDevBootROM1[address - 0xE00000 + 1];
#endif
}
+
unsigned int m68k_read_memory_32(unsigned int address)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
//; So, it seems that it stores the returned DWORD at $51136 and $FB074.
//WriteLog("--> [RM32]\n");
#ifndef USE_NEW_MMU
- return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
+ uint32_t retVal = 0;
+
+ if ((address >= 0x800000) && (address <= 0xDFFEFE))
+ {
+ // Memory Track reading...
+ if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
+ retVal = MTReadLong(address);
+ else
+ retVal = GET32(jaguarMainROM, address - 0x800000);
+
+ return retVal;
+ }
+
+ return (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2);
#else
return MMURead32(address, M68K);
#endif
}
+
void m68k_write_memory_8(unsigned int address, unsigned int value)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
#ifdef CPU_DEBUG_MEMORY
#endif
}
+
void m68k_write_memory_16(unsigned int address, unsigned int value)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
#ifdef CPU_DEBUG_MEMORY
jaguar_mainRam[address + 1] = value & 0xFF;*/
SET16(jaguarMainRAM, address, value);
}
+ // Memory Track device writes....
+ else if ((address >= 0x800000) && (address <= 0x87FFFE))
+ {
+ if (((TOMGetMEMCON1() & 0x0006) == (2 << 1)) && (jaguarMainROMCRC32 == 0xFDF37F47))
+ MTWriteWord(address, value);
+ }
else if ((address >= 0xDFFF00) && (address <= 0xDFFFFE))
CDROMWriteWord(address, value, M68K);
else if ((address >= 0xF00000) && (address <= 0xF0FFFE))
#endif
}
+
void m68k_write_memory_32(unsigned int address, unsigned int value)
{
+#ifdef ALPINE_FUNCTIONS
+ // Check if breakpoint on memory is active, and deal with it
+ if (bpmActive && address == bpmAddress1)
+ M68KDebugHalt();
+#endif
+
// Musashi does this automagically for you, UAE core does not :-P
address &= 0x00FFFFFF;
/*if (address == 0x4E00)
return JaguarReadLong(i * 4);
}
+
bool JaguarInterruptHandlerIsValid(uint32_t i) // Debug use only...
{
uint32_t handler = JaguarGetHandler(i);
return (handler && (handler != 0xFFFFFFFF) ? true : false);
}
+
void M68K_show_context(void)
{
WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
}
}
+
//
// Unknown read/write byte/word routines
//
-// It's hard to believe that developers would be sloppy with their memory writes, yet in
-// some cases the developers screwed up royal. E.g., Club Drive has the following code:
+// It's hard to believe that developers would be sloppy with their memory
+// writes, yet in some cases the developers screwed up royal. E.g., Club Drive
+// has the following code:
//
// 807EC4: movea.l #$f1b000, A1
// 807ECA: movea.l #$8129e0, A0
// 807EDC: move.l (A0)+, (A1)+
// 807EDE: dbra D1, 807edc
//
-// The problem is at $807ED0--instead of putting A0 into D0, they really meant to put A1
-// in. This mistake causes it to try and overwrite approximately $700000 worth of address
-// space! (That is, unless the 68K causes a bus error...)
+// The problem is at $807ED0--instead of putting A0 into D0, they really meant
+// to put A1 in. This mistake causes it to try and overwrite approximately
+// $700000 worth of address space! (That is, unless the 68K causes a bus
+// error...)
void jaguar_unknown_writebyte(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
{
#endif
}
+
void jaguar_unknown_writeword(unsigned address, unsigned data, uint32_t who/*=UNKNOWN*/)
{
#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
#endif
}
+
unsigned jaguar_unknown_readbyte(unsigned address, uint32_t who/*=UNKNOWN*/)
{
#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
return 0xFF;
}
+
unsigned jaguar_unknown_readword(unsigned address, uint32_t who/*=UNKNOWN*/)
{
#ifdef LOG_UNMAPPED_MEMORY_ACCESSES
return 0xFFFF;
}
+
//
// Disassemble M68K instructions at the given offset
//
return m68k_read_memory_8(address);
}
+
unsigned int m68k_read_disassembler_16(unsigned int address)
{
return m68k_read_memory_16(address);
}
+
unsigned int m68k_read_disassembler_32(unsigned int address)
{
return m68k_read_memory_32(address);
}
+
void JaguarDasm(uint32_t offset, uint32_t qt)
{
#ifdef CPU_DEBUG
#endif
}
+
uint8_t JaguarReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
uint8_t data = 0x00;
return data;
}
+
uint16_t JaguarReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
offset &= 0xFFFFFF;
return jaguar_unknown_readword(offset, who);
}
+
void JaguarWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
{
+/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
+ {
+ WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);
+ }//*/
/* if (offset >= 0x4E00 && offset < 0x4E04)
WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
//Need to check for writes in the range of $18FA70 + 8000...
jaguar_unknown_writebyte(offset, data, who);
}
+
uint32_t starCount;
void JaguarWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
{
+/* if ((offset & 0x1FFFFF) >= 0xE00 && (offset & 0x1FFFFF) < 0xE18)
+ {
+ WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);
+ WriteLog(" GPU PC = $%06X\n", GPUReadLong(0xF02110, DEBUG));
+ }//*/
/* if (offset >= 0x4E00 && offset < 0x4E04)
WriteLog("JWW: Word %04X written at %08X by %s\n", data, offset, whoName[who]);//*/
/*if (offset == 0x0100)//64*4)
jaguar_unknown_writeword(offset, data, who);
}
+
// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
uint32_t JaguarReadLong(uint32_t offset, uint32_t who/*=UNKNOWN*/)
{
return (JaguarReadWord(offset, who) << 16) | JaguarReadWord(offset+2, who);
}
+
// We really should re-do this so that it does *real* 32-bit access... !!! FIX !!!
void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who/*=UNKNOWN*/)
{
JaguarWriteWord(offset+2, data & 0xFFFF, who);
}
+
void JaguarSetScreenBuffer(uint32_t * buffer)
{
// This is in TOM, but we set it here...
screenBuffer = buffer;
}
+
void JaguarSetScreenPitch(uint32_t pitch)
{
// This is in TOM, but we set it here...
screenPitch = pitch;
}
+
//
// Jaguar console initialization
//
//NOTE: This *doesn't* fix FlipOut...
//Or does it? Hmm...
//Seems to want $01010101... Dunno why. Investigate!
- memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
+// memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s...
// memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs...
lowerField = false; // Reset the lower field flag
//temp, for crappy crap that sux
memset(jaguarMainRAM + 0x804, 0xFF, 4);
-// m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit
GPUInit();
DSPInit();
void RenderCallback(void);
void JaguarReset(void)
{
+ // Only problem with this approach: It wipes out RAM loaded files...!
// Contents of local RAM are quasi-stable; we simulate this by randomizing RAM contents
- for(uint32_t i=0; i<0x200000; i+=4)
+ for(uint32_t i=8; i<0x200000; i+=4)
*((uint32_t *)(&jaguarMainRAM[i])) = rand();
// New timer base code stuffola...
M68K_show_context();
//#endif
-#if 0 // This is drawn already...
- WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
- for(uint32_t i=0x64; i<=0x7C; i+=4)
- WriteLog(" #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
-#endif
-
CDROMDone();
GPUDone();
DSPDone();
if (fp == NULL)
return;
- fwrite(jaguarMainRAM, 1, 0x400000, fp);
+ fwrite(jaguarMainRAM, 1, 0x200000, fp);
fclose(fp);
}
}
-#define USE_CORRECT_PAL_TIMINGS
-// A lot of confusion comes from here...
-// The thing to keep in mind is that the VC is advanced every HALF line, regardless
-// of whether the display is interlaced or not. The only difference with an
-// interlaced display is that the high bit of VC will be set when the lower
-// field is being rendered. (NB: The high bit of VC is ALWAYS set on the lower field,
-// regardless of whether it's in interlace mode or not.
-// NB2: Seems it doens't always, not sure what the constraint is...)
+//
+// The thing to keep in mind is that the VC is advanced every HALF line,
+// regardless of whether the display is interlaced or not. The only difference
+// with an interlaced display is that the high bit of VC will be set when the
+// lower field is being rendered. (NB: The high bit of VC is ALWAYS set on the
+// lower field, regardless of whether it's in interlace mode or not.
+// NB2: Seems it doesn't always, not sure what the constraint is...)
//
// Normally, TVs will render a full frame in 1/30s (NTSC) or 1/25s (PAL) by
// rendering two fields that are slighty vertically offset from each other.
// We execute a half frame in each timeslice (1/60s NTSC, 1/50s PAL).
// Since the number of lines in a FULL frame is 525 for NTSC, 625 for PAL,
// it will be half this number for a half frame. BUT, since we're counting
-// HALF lines, we double this number and we're back at 525 for NTSC, 625 for PAL.
+// HALF lines, we double this number and we're back at 525 for NTSC, 625 for
+// PAL.
//
// Scanline times are 63.5555... μs in NTSC and 64 μs in PAL
// Half line times are, naturally, half of this. :-P
+//
void HalflineCallback(void)
{
-//OK, this is hardwired to run in NTSC, and for who knows how long.
-//Need to fix this so that it does a half-line in the correct amount of time
-//and number of lines, depending on which mode we're in. [FIXED]
uint16_t vc = TOMReadWord(0xF00006, JAGUAR);
uint16_t vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
uint16_t vi = TOMReadWord(0xF0004E, JAGUAR);
// uint16_t vbb = TOMReadWord(0xF00040, JAGUAR);
vc++;
-#ifdef USE_CORRECT_PAL_TIMINGS
// Each # of lines is for a full frame == 1/30s (NTSC), 1/25s (PAL).
// So we cut the number of half-lines in a frame in half. :-P
uint16_t numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
if ((vc & 0x7FF) >= numHalfLines)
-#else
- if ((vc & 0x7FF) >= vp)
-#endif
{
- vc = 0;
-// lowerField = !lowerField;
-
- // If we're rendering the lower field, set the high bit (#12, counting
- // from 1) of VC
- if (lowerField)
- vc = 0x0800;
+ lowerField = !lowerField;
+ // If we're rendering the lower field, set the high bit (#11, counting
+ // from 0) of VC
+ vc = (lowerField ? 0x0800 : 0x0000);
}
-//WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
+//WriteLog("HLC: Currently on line %u (VP=%u)...\n", vc, vp);
TOMWriteWord(0xF00006, vc, JAGUAR);
-//This is a crappy kludge, but maybe it'll work for now...
-//Maybe it's not so bad, since the IRQ happens on a scanline boundary...
- if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
+ // Time for Vertical Interrupt?
+ if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO))
{
// We don't have to worry about autovectors & whatnot because the Jaguar
// tells you through its HW registers who sent the interrupt...
frameDone = true;
}//*/
-#ifdef USE_CORRECT_PAL_TIMINGS
SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
-#else
-// SetCallbackTime(HalflineCallback, 63.5555);
- SetCallbackTime(HalflineCallback, 31.77775);
-#endif
}
-
-// This isn't currently used, but maybe it should be...
-/*
-Nah, the scanline based code is good enough, and runs in 1 frame. The GUI
-handles all the rest, so this isn't needed. :-P
-*/
-void RenderCallback(void)
-{
-// SetCallbackTime(RenderCallback, 33303.082); // # Scanlines * scanline time
- SetCallbackTime(RenderCallback, 16651.541); // # Scanlines * scanline time
-}