]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/jaguar.cpp
Fixes for the 68K IRQ system. There's probably a little more to do though.
[virtualjaguar] / src / jaguar.cpp
index 796d9ee839786f0f96bdfcb3230f9e4d5bd36403..98adae1bb8300ae86b4f851c3ceec7a14857f07e 100644 (file)
@@ -25,7 +25,6 @@
 #include "eeprom.h"
 #include "event.h"
 #include "gpu.h"
-//#include "gui.h"
 #include "jerry.h"
 #include "joystick.h"
 #include "log.h"
@@ -34,7 +33,6 @@
 #include "mmu.h"
 #include "settings.h"
 #include "tom.h"
-#include "video.h"
 
 #define CPU_DEBUG
 //Do this in makefile??? Yes! Could, but it's easier to define here...
@@ -43,6 +41,7 @@
 #define ABORT_ON_ILLEGAL_INSTRUCTIONS
 //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION
 #define CPU_DEBUG_MEMORY
+//#define LOG_CD_BIOS_CALLS
 
 // Private function prototypes
 
@@ -67,6 +66,8 @@ uint32 jaguarMainROMCRC32, jaguarROMSize, jaguarRunAddress;
 bool BIOSLoaded = false;
 bool CDBIOSLoaded = false;
 
+uint32 * backbuffer;
+
 #ifdef CPU_DEBUG_MEMORY
 uint8 writeMemMax[0x400000], writeMemMin[0x400000];
 uint8 readMem[0x400000];
@@ -243,6 +244,8 @@ if (m68kPC == 0x802058) start = true;
                WriteLog("--> [Calling BusWrite2] D2: %08X\n", m68k_get_reg(NULL, M68K_REG_D2));
 //             m68k_set_reg(M68K_REG_D2, 0x12345678);
        }//*/
+
+#ifdef LOG_CD_BIOS_CALLS
 /*
 CD_init::      -> $3000
 BIOS_VER::     -> $3004
@@ -308,7 +311,8 @@ CD_switch:: -> $306C
                WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X, D1=%08X, D2=%08X\n",
                        m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
                        m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
-//*/
+#endif
+
 #ifdef ABORT_ON_ILLEGAL_INSTRUCTIONS
        if (!m68k_is_valid_instruction(m68k_read_memory_16(m68kPC), M68K_CPU_TYPE_68000))
        {
@@ -345,6 +349,33 @@ CD_switch::        -> $306C
                exit(0);
        }//*/
 #endif
+
+#if 0
+//001A0110: move.w  #$0, $F000E2.l             ; Restore Blitter/GPU bus priorities
+//001A015C: rte                                                        ; Return from the interrupt
+static bool disassembleGo = false;
+       if (m68kPC == 0x1A0110)
+       {
+               static char buffer[2048];
+               m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
+               WriteLog("--> [M68K IRQ Routine start] %08X: %s", m68kPC, buffer);
+               WriteLog("\t\tA0=%08X, A1=%08X, D0=%08X(cmd), D1=%08X(# bytes), D2=%08X\n",
+                       m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1),
+                       m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
+               disassembleGo = true;
+       }
+       else if (m68kPC == 0x1A015C)
+               WriteLog("--> [M68K IRQ Routine end]\n");
+
+       if (disassembleGo)
+       {
+               static char buffer[2048];
+               m68k_disassemble(buffer, m68kPC, M68K_CPU_TYPE_68000);
+               WriteLog("%08X: %s", m68kPC, buffer);
+               WriteLog("\tD0=$%08X, D1=$%08X, D2=$%08X\n",
+                       m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2));
+       }
+#endif
 }
 
 #if 0
@@ -776,19 +807,84 @@ uint32 ReadDWord(uint32 adddress)
 // Musashi 68000 read/write/IRQ functions
 //
 
+#if 0
+IRQs:
+=-=-=
+
+      IPL         Name           Vector            Control
+   ---------+---------------+---------------+---------------
+       2      VBLANK IRQ         $100         INT1 bit #0 
+       2      GPU IRQ            $100         INT1 bit #1
+       2      HBLANK IRQ         $100         INT1 bit #2
+       2      Timer IRQ          $100         INT1 bit #3
+
+   Note: Both timer interrupts (JPIT && PIT) are on the same INT1 bit.
+         and are therefore indistinguishable.
+
+   A typical way to install a LEVEL2 handler for the 68000 would be 
+   something like this, you gotta supply "last_line" and "handler".
+   Note that the interrupt is auto vectored thru $100 (not $68)
+
+
+   V_AUTO   = $100
+   VI       = $F004E
+   INT1     = $F00E0
+   INT2     = $F00E2
+   
+   IRQS_HANDLED=$909                ;; VBLANK and TIMER
+
+         move.w   #$2700,sr         ;; no IRQs please
+         move.l   #handler,V_AUTO   ;; install our routine
+
+         move.w   #last_line,VI     ;; scanline where IRQ should occur
+                                    ;; should be 'odd' BTW
+         move.w   #IRQS_HANDLE&$FF,INT1  ;; enable VBLANK + TIMER
+         move.w   #$2100,sr         ;; enable IRQs on the 68K
+         ...
+
+handler:
+         move.w   d0,-(a7)
+         move.w   INT1,d0
+         btst.b   #0,d0
+         bne.b    .no_blank
+
+         ...
+
+.no_blank:
+         btst.b   #3,d0
+         beq.b    .no_timer
+      
+         ...
+
+.no_timer:
+         move.w   #IRQS_HANDLED,INT1      ; clear latch, keep IRQ alive
+         move.w   #0,INT2                 ; let GPU run again
+         move.w   (a7)+,d0
+         rte
+
+   As you can see, if you have multiple INT1 interrupts coming in,
+   you need to check the lower byte of INT1, to see which interrupt
+   happened.
+#endif
 int irq_ack_handler(int level)
 {
-       int vector = M68K_INT_ACK_AUTOVECTOR;
+       // Tracing the IPL lines on the Jaguar schematic yields the following:
+       // 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 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.
 
        // 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 == 7)
+       if (level == 2)
        {
-               m68k_set_irq(0);                                                // Clear the IRQ...
-               vector = 64;                                                    // Set user interrupt #0
+               m68k_set_irq(0);                                                // Clear the IRQ (NOTE: Without this, the BIOS fails)...
+               return 64;                                                              // Set user interrupt #0
        }
 
-       return vector;
+       return M68K_INT_ACK_AUTOVECTOR;
 }
 
 //#define USE_NEW_MMU
@@ -1114,16 +1210,24 @@ void M68K_show_context(void)
 
        if (TOMIRQEnabled(IRQ_VBLANK))
        {
-               WriteLog("vblank int: enabled\n");
+               WriteLog("video int: enabled\n");
                JaguarDasm(JaguarGetHandler(64), 0x200);
        }
        else
-               WriteLog("vblank int: disabled\n");
+               WriteLog("video int: disabled\n");
 
        WriteLog("..................\n");
 
        for(int i=0; i<256; i++)
-               WriteLog("handler %03i at $%08X\n", i, (unsigned int)JaguarGetHandler(i));
+       {
+               WriteLog("handler %03i at ", i);//$%08X\n", i, (unsigned int)JaguarGetHandler(i));
+               uint32 address = (uint32)JaguarGetHandler(i);
+
+               if (address == 0)
+                       WriteLog(".........\n");
+               else
+                       WriteLog("$%08X\n", address);
+       }
 }
 
 //
@@ -1511,12 +1615,15 @@ void RenderCallback(void);
 //extern uint32 * backbuffer;
 void JaguarReset(void)
 {
-//NOTE: This causes a (virtual) crash if this is set in the config but not found... !!! FIX !!!
-       if (vjs.useJaguarBIOS)
+       // Only use the system BIOS if it's available...!
+       if (vjs.useJaguarBIOS && (biosAvailable & (BIOS_NORMAL | BIOS_STUB1 | BIOS_STUB2)))
                memcpy(jaguarMainRAM, jaguarBootROM, 8);
        else
                SET32(jaguarMainRAM, 4, jaguarRunAddress);
 
+       if (vjs.useJaguarBIOS && !(biosAvailable & (BIOS_NORMAL | BIOS_STUB1 | BIOS_STUB2)))
+               WriteLog("Jaguar: Requested BIOS, but none available.\n");
+
 //     WriteLog("jaguar_reset():\n");
        TOMReset();
        JERRYReset();
@@ -1609,16 +1716,52 @@ void JaguarDone(void)
        WriteLog("\n");//*/
 
 //     WriteLog("Jaguar: CD BIOS version %04X\n", JaguarReadWord(0x3004));
-       WriteLog("Jaguar: Interrupt enable = %02X\n", TOMReadByte(0xF000E1) & 0x1F);
-       WriteLog("Jaguar: VBL interrupt is %s\n", ((TOMIRQEnabled(IRQ_VBLANK)) && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled");
+       WriteLog("Jaguar: Interrupt enable = $%02X\n", TOMReadByte(0xF000E1, JAGUAR) & 0x1F);
+       WriteLog("Jaguar: Video interrupt is %s (line=%u)\n", ((TOMIRQEnabled(IRQ_VBLANK))
+               && (JaguarInterruptHandlerIsValid(64))) ? "enabled" : "disabled", TOMReadWord(0xF0004E, JAGUAR));
        M68K_show_context();
 //#endif
 
+#if 0  // This is drawn already...
+       WriteLog("Jaguar: 68K AutoVector table:\n", JaguarReadWord(0x3004));
+       for(uint32 i=0x64; i<=0x7C; i+=4)
+               WriteLog("  #%u: %08X\n", (i-0x64)/4, JaguarReadLong(i));
+#endif
+
        CDROMDone();
        GPUDone();
        DSPDone();
        TOMDone();
        JERRYDone();
+
+       // temp, until debugger is in place
+//00802016: jsr     $836F1A.l
+//0080201C: jsr     $836B30.l
+//00802022: jsr     $836B18.l
+//00802028: jsr     $8135F0.l
+//00813C1E: jsr     $813F76.l
+//00802038: jsr     $836D00.l
+//00802098: jsr     $8373A4.l
+//008020A2: jsr     $83E24A.l
+//008020BA: jsr     $83E156.l
+//008020C6: jsr     $83E19C.l
+//008020E6: jsr     $8445E8.l
+//008020EC: jsr     $838C20.l
+//0080211A: jsr     $838ED6.l
+//00802124: jsr     $89CA56.l
+//0080212A: jsr     $802B48.l
+#if 0
+       WriteLog("-------------------------------------------\n");
+       JaguarDasm(0x8445E8, 0x200);
+       WriteLog("-------------------------------------------\n");
+       JaguarDasm(0x838C20, 0x200);
+       WriteLog("-------------------------------------------\n");
+       JaguarDasm(0x838ED6, 0x200);
+       WriteLog("-------------------------------------------\n");
+       JaguarDasm(0x89CA56, 0x200);
+       WriteLog("-------------------------------------------\n");
+       JaguarDasm(0x802B48, 0x200);
+#endif
 }
 
 //
@@ -1626,18 +1769,18 @@ void JaguarDone(void)
 //
 void JaguarExecute(uint32 * backbuffer, bool render)
 {
-       uint16 vp = TOMReadWord(0xF0003E) + 1;
-       uint16 vi = TOMReadWord(0xF0004E);
+       uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
+       uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
 //Using WO registers is OK, since we're the ones controlling access--there's nothing wrong here! ;-)
 //Though we shouldn't be able to do it using TOMReadWord... !!! FIX !!!
 
-//     uint16 vdb = TOMReadWord(0xF00046);
+//     uint16 vdb = TOMReadWord(0xF00046, JAGUAR);
 //Note: This is the *definite* end of the display, though VDE *might* be less than this...
-//     uint16 vbb = TOMReadWord(0xF00040);
+//     uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
 //It seems that they mean it when they say that VDE is the end of object processing.
 //However, we need to be able to tell the OP (or TOM) that we've reached the end of the
 //buffer and not to write any more pixels... !!! FIX !!!
-//     uint16 vde = TOMReadWord(0xF00048);
+//     uint16 vde = TOMReadWord(0xF00048, JAGUAR);
 
        uint16 refreshRate = (vjs.hardwareTypeNTSC ? 60 : 50);
        uint32 m68kClockRate = (vjs.hardwareTypeNTSC ? M68K_CLOCK_RATE_NTSC : M68K_CLOCK_RATE_PAL);
@@ -1657,9 +1800,9 @@ if (effect_start)
        for(uint16 i=0; i<vp; i++)
        {
                // Increment the horizontal count (why? RNG? Besides which, this is *NOT* cycle accurate!)
-               TOMWriteWord(0xF00004, (TOMReadWord(0xF00004) + 1) & 0x7FF);
+               TOMWriteWord(0xF00004, (TOMReadWord(0xF00004, JAGUAR) + 1) & 0x7FF, JAGUAR);
 
-               TOMWriteWord(0xF00006, i);                                      // Write the VC
+               TOMWriteWord(0xF00006, i, JAGUAR);                      // Write the VC
 
 //             if (i == vi)                                                            // Time for Vertical Interrupt?
 //Not sure if this is correct...
@@ -1670,7 +1813,7 @@ if (effect_start)
                        // We don't have to worry about autovectors & whatnot because the Jaguar
                        // tells you through its HW registers who sent the interrupt...
                        TOMSetPendingVideoInt();
-                       m68k_set_irq(7);
+                       m68k_set_irq(2);
                }
 
 //if (start_logging)
@@ -1772,17 +1915,17 @@ void JaguarExecuteNew(void)
 
 void ScanlineCallback(void)
 {
-       uint16 vc = TOMReadWord(0xF00006);
-       uint16 vp = TOMReadWord(0xF0003E) + 1;
-       uint16 vi = TOMReadWord(0xF0004E);
-//     uint16 vbb = TOMReadWord(0xF00040);
+       uint16 vc = TOMReadWord(0xF00006, JAGUAR);
+       uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
+       uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
+//     uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
        vc++;
 
        if (vc >= vp)
                vc = 0;
 
 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
-       TOMWriteWord(0xF00006, vc);
+       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...
@@ -1791,7 +1934,7 @@ void ScanlineCallback(void)
                // We don't have to worry about autovectors & whatnot because the Jaguar
                // tells you through its HW registers who sent the interrupt...
                tom_set_pending_video_int();
-               m68k_set_irq(7);
+               m68k_set_irq(2);
        }
 
        TOMExecScanline(vc, true);
@@ -1861,17 +2004,17 @@ void JaguarExecuteNew(void)
 
 void ScanlineCallback(void)
 {
-       uint16 vc = TOMReadWord(0xF00006);
-       uint16 vp = TOMReadWord(0xF0003E) + 1;
-       uint16 vi = TOMReadWord(0xF0004E);
-//     uint16 vbb = TOMReadWord(0xF00040);
+       uint16 vc = TOMReadWord(0xF00006, JAGUAR);
+       uint16 vp = TOMReadWord(0xF0003E, JAGUAR) + 1;
+       uint16 vi = TOMReadWord(0xF0004E, JAGUAR);
+//     uint16 vbb = TOMReadWord(0xF00040, JAGUAR);
        vc++;
 
        if (vc >= vp)
                vc = 0;
 
 //WriteLog("SLC: Currently on line %u (VP=%u)...\n", vc, vp);
-       TOMWriteWord(0xF00006, vc);
+       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...
@@ -1880,7 +2023,7 @@ void ScanlineCallback(void)
                // We don't have to worry about autovectors & whatnot because the Jaguar
                // tells you through its HW registers who sent the interrupt...
                TOMSetPendingVideoInt();
-               m68k_set_irq(7);
+               m68k_set_irq(2);
        }
 
        TOMExecScanline(vc, true);
@@ -1909,7 +2052,7 @@ void ScanlineCallback(void)
 // This isn't currently used, but maybe it should be...
 void RenderCallback(void)
 {
-       RenderBackbuffer();
+//     RenderBackbuffer();
        TOMResetBackbuffer(backbuffer);
 //     SetCallbackTime(RenderCallback, 33303.082);     // # Scanlines * scanline time
        SetCallbackTime(RenderCallback, 16651.541);     // # Scanlines * scanline time