]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/jaguar.cpp
Preliminary fixes for memory accesses between $200000 and $7FFFFF, proper
[virtualjaguar] / src / jaguar.cpp
index 0cd84112cace49ef9b8aba93d3df11951e05278a..bb940718ba9122a4fbbc2358f0cf8f4f6c4654a0 100644 (file)
@@ -3,11 +3,11 @@
 //
 // Originally by David Raingeard (Cal2)
 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
-// Cleanups and endian wrongness amelioration by James L. Hammons
+// Cleanups and endian wrongness amelioration by James Hammons
 // Note: Endian wrongness probably stems from the MAME origins of this emu and
 //       the braindead way in which MAME handled memory when this was written. :-)
 //
-// JLH = James L. Hammons
+// JLH = James Hammons
 //
 // WHO  WHEN        WHAT
 // ---  ----------  -----------------------------------------------------------
@@ -68,6 +68,7 @@ uint32 jaguar_active_memory_dumps = 0;
 
 uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
 bool jaguarCartInserted = false;
+bool lowerField = false;
 
 #ifdef CPU_DEBUG_MEMORY
 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
@@ -817,6 +818,39 @@ uint32 ReadDWord(uint32 adddress)
 }
 #endif
 
+void ShowM68KContext(void)
+{
+       printf("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
+
+       for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
+       {
+               printf("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
+
+               if (i == M68K_REG_D3 || i == M68K_REG_D7)
+                       printf("\n");
+       }
+
+       for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
+       {
+               printf("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
+
+               if (i == M68K_REG_A3 || i == M68K_REG_A7)
+                       printf("\n");
+       }
+
+       uint32_t currpc = m68k_get_reg(NULL, M68K_REG_PC);
+       uint32_t disPC = currpc - 30;
+       char buffer[128];
+
+       do
+       {
+               uint32_t oldpc = disPC;
+               disPC += m68k_disassemble(buffer, disPC, 0);
+               printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
+       }
+       while (disPC < (currpc + 10));
+}
+
 //
 // Musashi 68000 read/write/IRQ functions
 //
@@ -905,8 +939,11 @@ int irq_ack_handler(int level)
 
 unsigned int m68k_read_memory_8(unsigned int address)
 {
+       // Musashi does this automagically for you, UAE core does not :-P
+       address &= 0x00FFFFFF;
 #ifdef CPU_DEBUG_MEMORY
-       if ((address >= 0x000000) && (address <= 0x3FFFFF))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFF))
        {
                if (startMemLog)
                        readMem[address] = 1;
@@ -920,7 +957,8 @@ unsigned int m68k_read_memory_8(unsigned int address)
 #ifndef USE_NEW_MMU
        unsigned int retVal = 0;
 
-       if ((address >= 0x000000) && (address <= 0x3FFFFF))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFF))
                retVal = jaguarMainRAM[address];
 //     else if ((address >= 0x800000) && (address <= 0xDFFFFF))
        else if ((address >= 0x800000) && (address <= 0xDFFEFF))
@@ -953,6 +991,8 @@ void gpu_dump_registers(void);
 
 unsigned int m68k_read_memory_16(unsigned int address)
 {
+       // Musashi does this automagically for you, UAE core does not :-P
+       address &= 0x00FFFFFF;
 #ifdef CPU_DEBUG_MEMORY
 /*     if ((address >= 0x000000) && (address <= 0x3FFFFE))
        {
@@ -1016,7 +1056,8 @@ unsigned int m68k_read_memory_16(unsigned int address)
 #ifndef USE_NEW_MMU
     unsigned int retVal = 0;
 
-       if ((address >= 0x000000) && (address <= 0x3FFFFE))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFE))
 //             retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1];
                retVal = GET16(jaguarMainRAM, address);
 //     else if ((address >= 0x800000) && (address <= 0xDFFFFE))
@@ -1051,6 +1092,8 @@ unsigned int m68k_read_memory_16(unsigned int address)
 
 unsigned int m68k_read_memory_32(unsigned int address)
 {
+       // 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.
 /*     if (address == 0x51136 || address == 0xFB074 || address == 0x1AF05E)
                WriteLog("[RM32  PC=%08X] Addr: %08X, val: %08X\n", m68k_get_reg(NULL, M68K_REG_PC), address, (m68k_read_memory_16(address) << 16) | m68k_read_memory_16(address + 2));//*/
@@ -1065,8 +1108,11 @@ unsigned int m68k_read_memory_32(unsigned int address)
 
 void m68k_write_memory_8(unsigned int address, unsigned int value)
 {
+       // Musashi does this automagically for you, UAE core does not :-P
+       address &= 0x00FFFFFF;
 #ifdef CPU_DEBUG_MEMORY
-       if ((address >= 0x000000) && (address <= 0x3FFFFF))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFF))
        {
                if (startMemLog)
                {
@@ -1088,9 +1134,14 @@ void m68k_write_memory_8(unsigned int address, unsigned int value)
 //$53D0
 /*if (address >= 0x53D0 && address <= 0x53FF)
        printf("M68K: Writing byte $%02X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
+//Testing AvP on UAE core...
+//000075A0: FFFFF80E B6320220 (BITMAP)
+/*if (address == 0x75A0 && value == 0xFF)
+       printf("M68K: (8) Tripwire hit...\n");//*/
 
 #ifndef USE_NEW_MMU
-       if ((address >= 0x000000) && (address <= 0x3FFFFF))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFF))
                jaguarMainRAM[address] = value;
        else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF))
                CDROMWriteByte(address, value, M68K);
@@ -1107,8 +1158,11 @@ void m68k_write_memory_8(unsigned int address, unsigned int value)
 
 void m68k_write_memory_16(unsigned int address, unsigned int value)
 {
+       // Musashi does this automagically for you, UAE core does not :-P
+       address &= 0x00FFFFFF;
 #ifdef CPU_DEBUG_MEMORY
-       if ((address >= 0x000000) && (address <= 0x3FFFFE))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFE))
        {
                if (startMemLog)
                {
@@ -1154,9 +1208,17 @@ if (address == 0xF02110)
 //$53D0
 /*if (address >= 0x53D0 && address <= 0x53FF)
        printf("M68K: Writing word $%04X at $%08X, PC=$%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
+//Testing AvP on UAE core...
+//000075A0: FFFFF80E B6320220 (BITMAP)
+/*if (address == 0x75A0 && value == 0xFFFF)
+{
+       printf("\nM68K: (16) Tripwire hit...\n");
+       ShowM68KContext();
+}//*/
 
 #ifndef USE_NEW_MMU
-       if ((address >= 0x000000) && (address <= 0x3FFFFE))
+       // Note that the Jaguar only has 2M of RAM, not 4!
+       if ((address >= 0x000000) && (address <= 0x1FFFFE))
        {
 /*             jaguar_mainRam[address] = value >> 8;
                jaguar_mainRam[address + 1] = value & 0xFF;*/
@@ -1184,6 +1246,8 @@ if (address == 0xF02110)
 
 void m68k_write_memory_32(unsigned int address, unsigned int value)
 {
+       // Musashi does this automagically for you, UAE core does not :-P
+       address &= 0x00FFFFFF;
 /*if (address == 0x4E00)
        WriteLog("M68K: Writing %02X at %08X, PC=%08X\n", value, address, m68k_get_reg(NULL, M68K_REG_PC));//*/
 //WriteLog("--> [WM32]\n");
@@ -1198,6 +1262,13 @@ if (address == 0xF03214 && value == 0x88E30047)
        doGPUDis = true;//*/
 /*     if (address == 0x51136 || address == 0xFB074)
                WriteLog("[WM32  PC=%08X] Addr: %08X, val: %02X\n", m68k_get_reg(NULL, M68K_REG_PC), address, value);//*/
+//Testing AvP on UAE core...
+//000075A0: FFFFF80E B6320220 (BITMAP)
+/*if (address == 0x75A0 && (value & 0xFFFF0000) == 0xFFFF0000)
+{
+       printf("\nM68K: (32) Tripwire hit...\n");
+       ShowM68KContext();
+}//*/
 
 #ifndef USE_NEW_MMU
        m68k_write_memory_16(address, value >> 16);
@@ -1221,12 +1292,23 @@ bool JaguarInterruptHandlerIsValid(uint32 i) // Debug use only...
 
 void M68K_show_context(void)
 {
-       WriteLog("\t68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
+       WriteLog("68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC));
+
        for(int i=M68K_REG_D0; i<=M68K_REG_D7; i++)
-               WriteLog("\tD%i = %08X\n", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
-       WriteLog("\n");
+       {
+               WriteLog("D%i = %08X ", i-M68K_REG_D0, m68k_get_reg(NULL, (m68k_register_t)i));
+
+               if (i == M68K_REG_D3 || i == M68K_REG_D7)
+                       WriteLog("\n");
+       }
+
        for(int i=M68K_REG_A0; i<=M68K_REG_A7; i++)
-               WriteLog("\tA%i = %08X\n", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
+       {
+               WriteLog("A%i = %08X ", i-M68K_REG_A0, m68k_get_reg(NULL, (m68k_register_t)i));
+
+               if (i == M68K_REG_A3 || i == M68K_REG_A7)
+                       WriteLog("\n");
+       }
 
        WriteLog("68K disasm\n");
 //     jaguar_dasm(s68000readPC()-0x1000,0x20000);
@@ -1383,7 +1465,7 @@ uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
        uint8 data = 0x00;
 
        offset &= 0xFFFFFF;
-       if (offset < 0x400000)
+       if (offset < 0x200000)
                data = jaguarMainRAM[offset & 0x3FFFFF];
        else if ((offset >= 0x800000) && (offset < 0xC00000))
                data = jaguarMainROM[offset - 0x800000];
@@ -1406,9 +1488,9 @@ uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
 uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
 {
        offset &= 0xFFFFFF;
-       if (offset <= 0x3FFFFE)
+       if (offset <= 0x1FFFFE)
        {
-               return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF];
+               return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF];
        }
        else if ((offset >= 0x800000) && (offset <= 0xBFFFFE))
        {
@@ -1440,9 +1522,9 @@ void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
                WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/
 
        offset &= 0xFFFFFF;
-       if (offset < 0x400000)
+       if (offset < 0x200000)
        {
-               jaguarMainRAM[offset & 0x3FFFFF] = data;
+               jaguarMainRAM[offset & 0x1FFFFF] = data;
                return;
        }
        else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF))
@@ -1484,7 +1566,7 @@ if (offset == 0x0102)//64*4)
 
        offset &= 0xFFFFFF;
 
-       if (offset <= 0x3FFFFE)
+       if (offset <= 0x1FFFFE)
        {
 /*
 GPU Table (CD BIOS)
@@ -1572,8 +1654,8 @@ if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638))
 if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A)
        WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/
 
-               jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8;
-               jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF;
+               jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8;
+               jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF;
                return;
        }
        else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE)
@@ -1642,7 +1724,7 @@ void JaguarInit(void)
        memset(writeMemMin, 0xFF, 0x400000);
        memset(writeMemMax, 0x00, 0x400000);
 #endif
-       memset(jaguarMainRAM, 0x00, 0x400000);
+       memset(jaguarMainRAM, 0x00, 0x200000);
 //     memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs...
 //     memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s...
 //NOTE: This *doesn't* fix FlipOut...
@@ -1650,8 +1732,12 @@ void JaguarInit(void)
 //Seems to want $01010101... Dunno why. Investigate!
        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();
        TOMInit();
@@ -1660,7 +1746,7 @@ void JaguarInit(void)
 }
 
 //New timer based code stuffola...
-void ScanlineCallback(void);
+void HalflineCallback(void);
 void RenderCallback(void);
 void JaguarReset(void)
 {
@@ -1683,12 +1769,12 @@ void JaguarReset(void)
     m68k_pulse_reset();                                                                // Reset the 68000
        WriteLog("Jaguar: 68K reset. PC=%06X SP=%08X\n", m68k_get_reg(NULL, M68K_REG_PC), m68k_get_reg(NULL, M68K_REG_A7));
 
+       lowerField = false;                                                             // Reset the lower field flag
        // New timer base code stuffola...
        InitializeEventList();
 //     SetCallbackTime(ScanlineCallback, 63.5555);
-       SetCallbackTime(ScanlineCallback, 31.77775);
-//     SetCallbackTime(RenderCallback, 33303.082);     // # Scanlines * scanline time
-//     SetCallbackTime(RenderCallback, 16651.541);     // # Scanlines * scanline time
+//     SetCallbackTime(ScanlineCallback, 31.77775);
+       SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
 }
 
 void JaguarDone(void)
@@ -1817,6 +1903,12 @@ void JaguarDone(void)
 /*     WriteLog("\n\nM68000 disassembly at $4000...\n");
        JaguarDasm(0x4000, 10000);
        WriteLog("\n");//*/
+//     WriteLog("\n\nM68000 disassembly at $802000...\n");
+//     JaguarDasm(0x802000, 0x1000);
+//     WriteLog("\n\nM68000 disassembly at $4100...\n");
+//     JaguarDasm(0x4100, 200);
+//     WriteLog("\n\nM68000 disassembly at $800800...\n");
+//     JaguarDasm(0x800800, 0x1000);
 }
 
 //
@@ -1899,7 +1991,7 @@ if (effect_start)
 
 //if (start_logging)
 //     WriteLog("About to execute OP (%u)...\n", i);
-               TOMExecScanline(i, render);
+               TOMExecHalfline(i, render);
        }
 }
 
@@ -1953,49 +2045,29 @@ void JaguarExecuteNew(void)
        while (!frameDone);
 }
 
-/*
-BIG NOTE: NEED TO FIX THIS TO RUN ON ABSOLUTE TIMINGS BASED ON SCANLINES,
-          *NOT* ON THE VERTICAL PERIOD!!!
-
-<Zerosquare> scanlines are 64 µs in PAL
-<Zerosquare> and 63.5555... µs in NTSC
-
-Also: 625 lines per frame in PAL, 525 in NTSC
-
-So... can use
-#define RISC_CYCLE_IN_USEC        0.03760684198
-#define M68K_CYCLE_IN_USEC        (RISC_CYCLE_IN_USEC * 2)
-
-#define HORIZ_PERIOD_IN_USEC_NTSC 63.555555555
-#define HORIZ_PERIOD_IN_USEC_PAL  64.0
-
-#define USEC_TO_RISC_CYCLES(u) (uint32)(((u) / RISC_CYCLE_IN_USEC) + 0.5)
-#define USEC_TO_M68K_CYCLES(u) (uint32)(((u) / M68K_CYCLE_IN_USEC) + 0.5)
-
-to figure cycles per half-line...
-
-USEC_TO_RISC_CYCLES(HORIZ_PERIOD_IN_USEC_NTSC) / 2
-USEC_TO_M68K_CYCLES(HORIZ_PERIOD_IN_USEC_NTSC) / 2
-USEC_TO_RISC_CYCLES(HORIZ_PERIOD_IN_USEC_PAL) / 2
-USEC_TO_M68K_CYCLES(HORIZ_PERIOD_IN_USEC_PAL) / 2
-
-// Full lines here, divide by two for half-lines...
-which gives the following: 1690, 845 (NTSC), 1702, 851 (PAL)
-So, for a full frame, that would yield:
-887250 (NTSC), 1063750 (PAL)
-one second:
-26617500 (NTSC), 26593750 (PAL)
-
-Which is off a little bit for NTSC...
-#define M68K_CLOCK_RATE_PAL            13296950
-#define M68K_CLOCK_RATE_NTSC   13295453
-#define RISC_CLOCK_RATE_PAL            26593900
-#define RISC_CLOCK_RATE_NTSC   26590906
-
-*/
-
 #define USE_CORRECT_PAL_TIMINGS
-void ScanlineCallback(void)
+// 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...)
+//
+// 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.
+// Each field is created in 1/60s (NTSC) or 1/50s (PAL), and every other line
+// is rendered in this mode so that each field, when overlaid on each other,
+// will yield the final picture at the full resolution for the full frame.
+//
+// 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.
+//
+// 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
@@ -2011,18 +2083,26 @@ void ScanlineCallback(void)
        // So we cut the number of half-lines in a frame in half. :-P
        uint16 numHalfLines = ((vjs.hardwareTypeNTSC ? 525 : 625) * 2) / 2;
 
-       if (vc >= numHalfLines)
+       if ((vc & 0x7FF) >= numHalfLines)
 #else
-       if (vc >= vp)
+       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;
+       }
 
 //WriteLog("SLC: 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 == vi && vc > 0 && TOMIRQEnabled(IRQ_VIDEO))     // Time for Vertical Interrupt?
+       if ((vc & 0x7FF) == vi && (vc & 0x7FF) > 0 && TOMIRQEnabled(IRQ_VIDEO)) // Time for Vertical Interrupt?
        {
                // We don't have to worry about autovectors & whatnot because the Jaguar
                // tells you through its HW registers who sent the interrupt...
@@ -2030,11 +2110,11 @@ void ScanlineCallback(void)
                m68k_set_irq(2);
        }
 
-       TOMExecScanline(vc, true);
+       TOMExecHalfline(vc, true);
 
 //Change this to VBB???
 //Doesn't seem to matter (at least for Flip Out & I-War)
-       if (vc == 0)
+       if ((vc & 0x7FF) == 0)
 //     if (vc == vbb)
        {
                JoystickExec();
@@ -2042,10 +2122,10 @@ void ScanlineCallback(void)
        }//*/
 
 #ifdef USE_CORRECT_PAL_TIMINGS
-       SetCallbackTime(ScanlineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
+       SetCallbackTime(HalflineCallback, (vjs.hardwareTypeNTSC ? 31.777777777 : 32.0));
 #else
-//     SetCallbackTime(ScanlineCallback, 63.5555);
-       SetCallbackTime(ScanlineCallback, 31.77775);
+//     SetCallbackTime(HalflineCallback, 63.5555);
+       SetCallbackTime(HalflineCallback, 31.77775);
 #endif
 }