]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/m68000/m68kinterface.c
Minor update to debugger; added autoupdating to CPU/MEM windows.
[virtualjaguar] / src / m68000 / m68kinterface.c
index 5292ca56fee82b9d31e45ca80be2cecce807cddb..d896cdfe10ac3361fd909ff4ebd315d9c58bc2e9 100644 (file)
@@ -1,10 +1,10 @@
 //
 // m68kinterface.c: Code interface to the UAE 68000 core and support code
 //
-// by James L. Hammons
+// by James Hammons
 // (C) 2011 Underground Software
 //
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
 // ---  ----------  -------------------------------------------------------------
 //
 
 #include "m68kinterface.h"
+//#include <pthread.h>
 #include "cpudefs.h"
 #include "inlines.h"
 #include "cpuextra.h"
 #include "readcpu.h"
 
-
 // Exception Vectors handled by emulation
 #define EXCEPTION_BUS_ERROR                2 /* This one is not emulated! */
 #define EXCEPTION_ADDRESS_ERROR            3 /* This one is partially emulated (doesn't stack a proper frame yet) */
@@ -45,20 +45,26 @@ extern const struct cputbl op_smalltbl_4_ff[];      /* 68000 */
 extern const struct cputbl op_smalltbl_5_ff[]; /* 68000 slow but compatible.  */
 
 // Externs, supplied by the user...
-extern int irq_ack_handler(int);
+//extern int irq_ack_handler(int);
 
 // Function prototypes...
 STATIC_INLINE void m68ki_check_interrupts(void);
-void m68ki_exception_interrupt(uint intLevel);
+void m68ki_exception_interrupt(uint32_t intLevel);
 STATIC_INLINE uint32_t m68ki_init_exception(void);
-STATIC_INLINE void m68ki_stack_frame_3word(uint pc, uint sr);
+STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr);
 unsigned long IllegalOpcode(uint32_t opcode);
 void BuildCPUFunctionTable(void);
+void m68k_set_irq2(unsigned int intLevel);
 
 // Local "Global" vars
 static int32_t initialCycles;
 cpuop_func * cpuFunctionTable[65536];
 
+// By virtue of the fact that m68k_set_irq() can be called asychronously by
+// another thread, we need something along the lines of this:
+static int checkForIRQToHandle = 0;
+//static pthread_mutex_t executionLock = PTHREAD_MUTEX_INITIALIZER;
+static int IRQLevelToHandle = 0;
 
 #if 0
 #define ADD_CYCLES(A)    m68ki_remaining_cycles += (A)
@@ -77,9 +83,13 @@ cpuop_func * cpuFunctionTable[65536];
 #endif
 
 #define CPU_DEBUG
+
+
 void Dasm(uint32_t offset, uint32_t qt)
 {
 #ifdef CPU_DEBUG
+// back up a few instructions...
+//offset -= 100;
        static char buffer[2048];//, mem[64];
        int pc = offset, oldpc;
        uint32_t i;
@@ -101,14 +111,43 @@ void Dasm(uint32_t offset, uint32_t qt)
 }
 
 
+#ifdef CPU_DEBUG
+void DumpRegisters(void)
+{
+       uint32_t i;
+
+       for(i=0; i<16; i++)
+       {
+               printf("%s%i: %08X ", (i < 8 ? "D" : "A"), i & 0x7, regs.regs[i]);
+
+               if ((i & 0x03) == 3)
+                       printf("\n");
+       }
+}
+#endif
+
+
+void M68KDebugHalt(void)
+{
+       regs.spcflags |= SPCFLAG_DEBUGGER;
+}
+
+
+void M68KDebugResume(void)
+{
+       regs.spcflags &= ~SPCFLAG_DEBUGGER;
+}
+
+
 void m68k_set_cpu_type(unsigned int type)
 {
 }
 
+
 // Pulse the RESET line on the CPU
 void m68k_pulse_reset(void)
 {
-       static uint emulation_initialized = 0;
+       static uint32_t emulation_initialized = 0;
 
        // The first call to this function initializes the opcode handler jump table
        if (!emulation_initialized)
@@ -160,6 +199,8 @@ void m68k_pulse_reset(void)
        REG_PC = m68ki_read_imm_32();
        m68ki_jump(REG_PC);
 #else
+       checkForIRQToHandle = 0;
+       regs.spcflags = 0;
        regs.stopped = 0;
        regs.remainingCycles = 0;
        
@@ -173,19 +214,9 @@ void m68k_pulse_reset(void)
 #endif
 }
 
+
 int m68k_execute(int num_cycles)
 {
-#if 0
-       /* Make sure we're not stopped */
-       if (CPU_STOPPED)
-       {
-               /* We get here if the CPU is stopped or halted */
-               SET_CYCLES(0);
-               CPU_INT_CYCLES = 0;
-
-               return num_cycles;
-       }
-#else
        if (regs.stopped)
        {
                regs.remainingCycles = 0;       // int32_t
@@ -193,7 +224,6 @@ int m68k_execute(int num_cycles)
 
                return num_cycles;
        }
-#endif
 
 #if 0
        /* Set our pool of clock cycles available */
@@ -217,6 +247,17 @@ int m68k_execute(int num_cycles)
        /* Main loop.  Keep going until we run out of clock cycles */
        do
        {
+               // This is so our debugging code can break in on a dime.
+               // Otherwise, this is just extra slow down :-P
+               if (regs.spcflags & SPCFLAG_DEBUGGER)
+               {
+                       // Not sure this is correct... :-P
+                       num_cycles = initialCycles - regs.remainingCycles;
+                       regs.remainingCycles = 0;       // int32_t
+                       regs.interruptCycles = 0;       // uint32_t
+
+                       return num_cycles;
+               }
 #if 0
                /* Set tracing accodring to T1. (T0 is done inside instruction) */
                m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
@@ -261,18 +302,58 @@ else if (regs.pc == 0x803422)
 
 if (inRoutine)
        instSeen++;
+#endif
+// AvP testing... (problem was: 32 bit addresses on 24 bit address cpu--FIXED)
+#if 0
+       static int go = 0;
+
+       if (regs.pc == 0x94BA)
+       {
+               go = 1;
+               printf("\n");
+       }
+
+       if (regs.pc == 0x94C6)
+               go = 0;
+
+//     if (regs.regs[10] == 0xFFFFFFFF && go)
+       if (go)
+       {
+//             printf("A2=-1, PC=%08X\n", regs.pc);
+//             go = 0;
+//             Dasm(regs.pc, 130);
+               Dasm(regs.pc, 1);
+               DumpRegisters();
+       }
+//94BA: 2468 0000                MOVEA.L       (A0,$0000) == $0002328A, A2
+//94BE: 200A                     MOVE.L        A2, D0
+//94C0: 6A02                     BPL.B $94C4
+//94C2: 2452                     MOVEA.L       (A2), A2                        ; <--- HERE
+//94C4: 4283                     CLR.L D3
+#endif
+//             pthread_mutex_lock(&executionLock);
+               if (checkForIRQToHandle)
+               {
+                       checkForIRQToHandle = 0;
+                       m68k_set_irq2(IRQLevelToHandle);
+               }
+
+#ifdef M68K_HOOK_FUNCTION
+               M68KInstructionHook();
 #endif
                uint32_t opcode = get_iword(0);
+//if ((opcode & 0xFFF8) == 0x31C0)
+//{
+//     printf("MOVE.W D%i, EA\n", opcode & 0x07);
+//}
                int32_t cycles = (int32_t)(*cpuFunctionTable[opcode])(opcode);
                regs.remainingCycles -= cycles;
+//             pthread_mutex_unlock(&executionLock);
+
 //printf("Executed opcode $%04X (%i cycles)...\n", opcode, cycles);
 #endif
        }
-#if 0
-       while (GET_CYCLES() > 0);
-#else
        while (regs.remainingCycles > 0);
-#endif
 
 #if 0
        /* set previous PC to current PC for the next entry into the loop */
@@ -293,20 +374,29 @@ if (inRoutine)
 #endif
 }
 
-/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
+
 void m68k_set_irq(unsigned int intLevel)
 {
-#if 0
-       uint old_level = CPU_INT_LEVEL;
-       CPU_INT_LEVEL = int_level << 8;
+       // We need to check for stopped state as well...
+       if (regs.stopped)
+       {
+               m68k_set_irq2(intLevel);
+               return;
+       }
+
+       // Since this can be called asynchronously, we need to fix it so that it
+       // doesn't fuck up the main execution loop.
+       IRQLevelToHandle = intLevel;
+       checkForIRQToHandle = 1;
+}
+
+
+/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
+void m68k_set_irq2(unsigned int intLevel)
+{
+//     pthread_mutex_lock(&executionLock);
+//             printf("m68k_set_irq: Could not get the lock!!!\n");
 
-       /* A transition from < 7 to 7 always interrupts (NMI) */
-       /* Note: Level 7 can also level trigger like a normal IRQ */
-       if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
-               m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
-       else
-               m68ki_check_interrupts(); /* Level triggered (IRQ) */
-#else
        int oldLevel = regs.intLevel;
        regs.intLevel = intLevel;
 
@@ -316,9 +406,11 @@ void m68k_set_irq(unsigned int intLevel)
                m68ki_exception_interrupt(7);           // Edge triggered level 7 (NMI)
        else
                m68ki_check_interrupts();                       // Level triggered (IRQ)
-#endif
+
+//     pthread_mutex_unlock(&executionLock);
 }
 
+
 // Check for interrupts
 STATIC_INLINE void m68ki_check_interrupts(void)
 {
@@ -331,8 +423,9 @@ STATIC_INLINE void m68ki_check_interrupts(void)
 #endif
 }
 
+
 // Service an interrupt request and start exception processing
-void m68ki_exception_interrupt(uint intLevel)
+void m68ki_exception_interrupt(uint32_t intLevel)
 {
 #if 0
        uint vector;
@@ -397,12 +490,14 @@ void m68ki_exception_interrupt(uint intLevel)
        CPU_INT_LEVEL = 0;
 #endif /* M68K_EMULATE_INT_ACK */
 #else
-       // Turn off the stopped state
+       // Turn off the stopped state (N.B.: normal 68K behavior!)
        regs.stopped = 0;
 
 //JLH: need to add halt state?
+// prolly, for debugging/alpine mode... :-/
+// but then again, this should be handled already by the main execution loop :-P
        // If we are halted, don't do anything
-//     if (CPU_STOPPED)
+//     if (regs.halted)
 //             return;
 
        // Acknowledge the interrupt (NOTE: This is a user supplied function!)
@@ -428,9 +523,24 @@ void m68ki_exception_interrupt(uint intLevel)
        // Set the interrupt mask to the level of the one being serviced
        regs.intmask = intLevel;
 
+#if 0
+extern int startM68KTracing;
+if (startM68KTracing)
+{
+       printf("IRQ: old PC=%06X, ", regs.pc);
+}
+#endif
+
        // Get the new PC
        uint32_t newPC = m68k_read_memory_32(vector << 2);
 
+#if 0
+if (startM68KTracing)
+{
+       printf("new PC=%06X, vector=%u, ", newPC, vector);
+}
+#endif
+
        // If vector is uninitialized, call the uninitialized interrupt vector
        if (newPC == 0)
                newPC = m68k_read_memory_32(EXCEPTION_UNINITIALIZED_INTERRUPT << 2);
@@ -439,6 +549,12 @@ void m68ki_exception_interrupt(uint intLevel)
        m68ki_stack_frame_3word(regs.pc, sr);
 
        m68k_setpc(newPC);
+#if 0
+if (startM68KTracing)
+{
+       printf("(PC=%06X)\n", regs.pc);
+}
+#endif
 
        // Defer cycle counting until later
        regs.interruptCycles += 56;     // NOT ACCURATE-- !!! FIX !!!
@@ -446,6 +562,7 @@ void m68ki_exception_interrupt(uint intLevel)
 #endif
 }
 
+
 // Initiate exception processing
 STATIC_INLINE uint32_t m68ki_init_exception(void)
 {
@@ -469,6 +586,7 @@ STATIC_INLINE uint32_t m68ki_init_exception(void)
 #endif
 }
 
+
 // 3 word stack frame (68000 only)
 STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr)
 {
@@ -485,6 +603,7 @@ STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr)
 #endif
 }
 
+
 unsigned int m68k_get_reg(void * context, m68k_register_t reg)
 {
        if (reg <= M68K_REG_A7)
@@ -502,6 +621,7 @@ unsigned int m68k_get_reg(void * context, m68k_register_t reg)
        return 0;
 }
 
+
 void m68k_set_reg(m68k_register_t reg, unsigned int value)
 {
        if (reg <= M68K_REG_A7)
@@ -517,6 +637,7 @@ void m68k_set_reg(m68k_register_t reg, unsigned int value)
                regs.regs[15] = value;
 }
 
+
 //
 // Check if the instruction is a valid one
 //
@@ -530,6 +651,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
        return 1;
 }
 
+
 // Dummy functions, for now, until we prove the concept here. :-)
 
 // Temp, while we're using the Musashi disassembler...
@@ -542,9 +664,16 @@ unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu
 
 int m68k_cycles_run(void) {}              /* Number of cycles run so far */
 int m68k_cycles_remaining(void) {}        /* Number of cycles left */
-void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */
+//void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */
 //void m68k_end_timeslice(void) {}          /* End timeslice now */
 
+
+void m68k_modify_timeslice(int cycles)
+{
+       regs.remainingCycles = cycles;
+}
+
+
 void m68k_end_timeslice(void)
 {
 #if 0
@@ -588,11 +717,14 @@ void BuildCPUFunctionTable(void)
        unsigned long opcode;
 
        // We're only using the "fast" 68000 emulation here, not the "compatible"
+       // ("fast" doesn't throw exceptions, so we're using "compatible" now :-P)
 #if 0
        const struct cputbl * tbl = (currprefs.cpu_compatible
                ? op_smalltbl_5_ff : op_smalltbl_4_ff);
 #else
-       const struct cputbl * tbl = op_smalltbl_4_ff;
+//let's try "compatible" and see what happens here...
+//     const struct cputbl * tbl = op_smalltbl_4_ff;
+       const struct cputbl * tbl = op_smalltbl_5_ff;
 #endif
 
 //     Log_Printf(LOG_DEBUG, "Building CPU function table (%d %d %d).\n",