]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/jaguar.cpp
2.0.2 release.
[virtualjaguar] / src / jaguar.cpp
index 0cd84112cace49ef9b8aba93d3df11951e05278a..e6fd3b60df6efd83a0edc69d68be8e5711fb1f19 100644 (file)
@@ -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,6 +939,8 @@ 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))
        {
@@ -953,6 +989,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))
        {
@@ -1051,6 +1089,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,6 +1105,8 @@ 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))
        {
@@ -1088,6 +1130,10 @@ 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))
@@ -1107,6 +1153,8 @@ 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))
        {
@@ -1154,6 +1202,13 @@ 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))
@@ -1184,6 +1239,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 +1255,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 +1285,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);
@@ -1650,8 +1725,10 @@ 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
 
        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 +1737,7 @@ void JaguarInit(void)
 }
 
 //New timer based code stuffola...
-void ScanlineCallback(void);
+void HalflineCallback(void);
 void RenderCallback(void);
 void JaguarReset(void)
 {
@@ -1683,12 +1760,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 +1894,8 @@ void JaguarDone(void)
 /*     WriteLog("\n\nM68000 disassembly at $4000...\n");
        JaguarDasm(0x4000, 10000);
        WriteLog("\n");//*/
+//     WriteLog("\n\nM68000 disassembly at $802000...\n");
+//     JaguarDasm(0x800830, 0x1000);
 }
 
 //
@@ -1899,7 +1978,7 @@ if (effect_start)
 
 //if (start_logging)
 //     WriteLog("About to execute OP (%u)...\n", i);
-               TOMExecScanline(i, render);
+               TOMExecHalfline(i, render);
        }
 }
 
@@ -1953,49 +2032,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 +2070,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 +2097,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 +2109,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
 }