Annotation of hatari/src/m68000.c, revision 1.1.1.3

1.1       root        1: /*
                      2:   Hatari
                      3: 
                      4:   M68000 - CPU. This handles exception handling as well as a few OpCode's such as Line-F and Line-A.
                      5:   We also have a function to save off the last 'x' instruction ran which is very handy for debugging
                      6:   as we can see what code was run before a crash etc...
                      7:   (Other CPU functions can be found in 'decode.asm/.inc')
                      8: */
                      9: 
                     10: #include "main.h"
                     11: #include "bios.h"
                     12: #include "cart.h"
                     13: #include "debug.h"
                     14: #include "decode.h"
                     15: #include "fdc.h"
                     16: #include "gemdos.h"
                     17: #include "ikbd.h"
                     18: #include "int.h"
                     19: #include "m68000.h"
                     20: #include "memAlloc.h"
                     21: #include "memorySnapShot.h"
                     22: #include "mfp.h"
                     23: #include "misc.h"
                     24: #include "psg.h"
                     25: #include "screen.h"
                     26: #include "stMemory.h"
                     27: #include "tos.h"
                     28: #include "vdi.h"
                     29: #include "view.h"
                     30: #include "xbios.h"
                     31: 
                     32: 
                     33: /* Taken from Decode.asm - Thothy */
                     34: /* These should be replaced with UAE's CPU core equivalents one day */
                     35: unsigned short SR_Before;
                     36: unsigned long ExceptionVector;
                     37: short int PendingInterruptFlag;
                     38: void *PendingInterruptFunction;
                     39: short int PendingInterruptCount;
                     40: int SoundCycles;
                     41: BOOL bInSuperMode;
                     42: unsigned long EmuCCode;
                     43: unsigned long BusAddressLocation;
                     44: 
                     45: 
                     46: /* Use these if want to bring up any bus/address error, else uses 68000 vector handler */
                     47: #ifndef FINAL_VERSION
                     48: //  #define TRAP_BUSERROR_HISTORY                 // Output history on true Bus Error(bombs display)
                     49: //  #define TRAP_ADDRESSERROR_HISTORY             // Or Address Error
                     50: //  #define TRAP_ILLEGALINSTRUCTIONERROR_HISTORY  // Or Illegal Instruction
                     51: #endif
                     52: 
                     53: BOOL bDoTraceException;          /* Do TRACE? */
                     54: 
                     55: 
1.1.1.3 ! root       56: /*-----------------------------------------------------------------------*/
1.1       root       57: /*
                     58:   Reset CPU 68000 variables
                     59: */
                     60: void M68000_Reset(BOOL bCold)
                     61: {
                     62:   int i;
                     63: 
1.1.1.3 ! root       64:   /* Clear registers, set PC, SR and stack pointers */
1.1       root       65:   if (bCold) {
                     66:     for(i=0; i<(16+1); i++)
                     67:       Regs[i] = 0;
                     68:   }
                     69:   PC = TOSAddress;                            /* Start of TOS image, 0xfc0000 or 0xe00000 */
                     70:   SR = 0x2700;                                /* Starting status register */
1.1.1.3 ! root       71:   MakeFromSR();
1.1       root       72:   bDoTraceException = FALSE;                  /* No TRACE exceptions */
                     73:   bInSuperMode = TRUE;                        /* We begin in supervisor mode */
                     74:   Regs[REG_A7] = Regs[REG_A8] = 0x0000f000;   /* Stack default */
1.1.1.2   root       75:   PendingInterruptFlag = 0;                   /* Clear pending flag */
1.1       root       76: 
1.1.1.3 ! root       77:   /* Read Supervisor Stack/PC for warm reset */
1.1       root       78:   if (!bCold) {
                     79:     Regs[REG_A8] = STMemory_ReadLong(0x00000000);
                     80:     PC = STMemory_ReadLong(0x00000004);
                     81:   }
                     82: 
1.1.1.3 ! root       83:   /* Hold display for extended VDI resolutions(under init our VDI) */
1.1       root       84:   bHoldScreenDisplay = TRUE;
                     85: }
                     86: 
1.1.1.3 ! root       87: 
        !            88: /*-----------------------------------------------------------------------*/
1.1       root       89: /*
                     90:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                     91: */
                     92: void M68000_MemorySnapShot_Capture(BOOL bSave)
                     93: {
1.1.1.3 ! root       94:   /* Save/Restore details */
1.1       root       95:   MemorySnapShot_Store(&bDoTraceException,sizeof(bDoTraceException));
                     96: }
                     97: 
1.1.1.3 ! root       98: 
        !            99: /*-----------------------------------------------------------------------*/
1.1       root      100: /*
                    101:   Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    102:   This is for 'decode.asm' variables - as cannot use 'decode.c' as will overwrite assembler .obj file!
                    103: */
                    104: void M68000_Decode_MemorySnapShot_Capture(BOOL bSave)
                    105: {
                    106:   int ID;
                    107: 
1.1.1.3 ! root      108:   /* Save/Restore details */
1.1       root      109:   MemorySnapShot_Store(Regs,sizeof(Regs));
                    110:   MemorySnapShot_Store(&STRamEnd,sizeof(STRamEnd));
                    111:   MemorySnapShot_Store(&STRamEnd_BusErr,sizeof(STRamEnd_BusErr));
                    112:   MemorySnapShot_Store(&PendingInterruptCount,sizeof(PendingInterruptCount));
                    113:   MemorySnapShot_Store(&PendingInterruptFlag,sizeof(PendingInterruptFlag));
                    114:   if (bSave) {
1.1.1.3 ! root      115:     /* Convert function to ID */
1.1       root      116:     ID = Int_HandlerFunctionToID(PendingInterruptFunction);
                    117:     MemorySnapShot_Store(&ID,sizeof(int));
                    118:   }
                    119:   else {
1.1.1.3 ! root      120:     /* Convert ID to function */
1.1       root      121:     MemorySnapShot_Store(&ID,sizeof(int));
                    122:     PendingInterruptFunction = Int_IDToHandlerFunction(ID);
                    123:   }
                    124:   MemorySnapShot_Store(&PC,sizeof(PC));
                    125:   MemorySnapShot_Store(&SR,sizeof(SR));
                    126:   MemorySnapShot_Store(&SR_Before,sizeof(SR_Before));
                    127:   MemorySnapShot_Store(&bInSuperMode,sizeof(bInSuperMode));
1.1.1.2   root      128:   /*MemorySnapShot_Store(&Reg_SuperSP,sizeof(Reg_SuperSP));*//*FIXME*/
                    129:   /*MemorySnapShot_Store(&Reg_UserSP,sizeof(Reg_UserSP));*/
1.1       root      130:   MemorySnapShot_Store(&EmuCCode,sizeof(EmuCCode));
                    131:   MemorySnapShot_Store(&ExceptionVector,sizeof(ExceptionVector));  
                    132: }
                    133: 
                    134: 
1.1.1.3 ! root      135: /*-----------------------------------------------------------------------*/
1.1       root      136: /*
                    137:   BUSERROR - Access outside valid memory range
                    138: */
                    139: void M68000_BusError(unsigned long addr)
                    140: {
1.1.1.3 ! root      141:   /* Reset PC's stack to normal(as may have done many calls) so return to
        !           142:      correct level after exception.
        !           143:      Enter here with 'ebp' as address we tried to access */
        !           144:   if(addr!=0xff8a00)
        !           145:     fprintf(stderr, "M68000_BusError at address $%lx\n", (long)addr);
        !           146:   BusAddressLocation=addr;               /* Store for exception frame */
        !           147:   ExceptionVector = EXCEPTION_BUSERROR;  /* Handler */
        !           148:   M68000_Exception();                    /* Cause trap */
1.1       root      149: }
                    150: 
1.1.1.3 ! root      151: 
        !           152: /*-----------------------------------------------------------------------*/
1.1       root      153: /*
                    154:   ADDRESSERROR - Access incorrect memory boundary, eg byte offset for a word access
                    155: */
                    156: void M68000_AddressError(unsigned long addr)
                    157: {
1.1.1.3 ! root      158:   fprintf(stderr, "M68000_AddressError at address $%lx\n", (long)addr);
        !           159:   BusAddressLocation=addr;              /* Store for exception frame */
        !           160:   ExceptionVector=EXCEPTION_ADDRERROR;  /* Handler */
        !           161:   M68000_Exception();                   /* Cause trap */
1.1       root      162: }
                    163: 
1.1.1.3 ! root      164: 
        !           165: /*-----------------------------------------------------------------------*/
1.1       root      166: /*
                    167:   See if in user/super mode and if need to swap SP
                    168: */
1.1.1.3 ! root      169: #if 0  /* Not needed for Hatari at the moment */
1.1       root      170: void M68000_CheckUserSuperToggle(void)
                    171: {
                    172:   unsigned long *TempReg;
                    173:   unsigned long TempSP;
                    174: 
1.1.1.3 ! root      175:   /* Have we swapped mode? */
1.1       root      176:   if ( (SR_Before&SR_SUPERMODE)!=(SR&SR_SUPERMODE) ) {
1.1.1.3 ! root      177:     /* Yes, swap to ST's REG_A8! */
1.1       root      178:     TempSP = Regs[REG_A7];
                    179:     Regs[REG_A7] = Regs[REG_A8];
                    180:     Regs[REG_A8] = TempSP;
                    181: 
1.1.1.3 ! root      182:     /* Swap super flag */
1.1       root      183:     bInSuperMode^=TRUE;
                    184:   }
                    185: 
1.1.1.3 ! root      186:   /* Set/Clear trace mode */
1.1       root      187:   if (SR&SR_TRACEMODE) {
1.1.1.3 ! root      188:     /* Have we set the TRACE bit for the FIRST time? Don't let exception occur until NEXT instruction */
        !           189:     /* NOTE Sometimes the TRACE bit can be set many times, so only skip exception on FIRST one */
1.1       root      190:     if ((PendingInterruptFlag&PENDING_INTERRUPT_FLAG_TRACE)==0) {
                    191:       PendingInterruptFlag |= PENDING_INTERRUPT_FLAG_TRACE;
                    192:       bDoTraceException = FALSE;
                    193:     }
                    194:   }
                    195:   else
                    196:     PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_TRACE;
                    197: }
1.1.1.3 ! root      198: #endif
        !           199: 
1.1       root      200: 
1.1.1.3 ! root      201: /*-----------------------------------------------------------------------*/
1.1       root      202: /*
                    203:   Called when TRACE bit is set. This causes 'exception' after each instruction, BUT
                    204:   it does not execute after the FIRST 'move SR,xxxx' to set the bit
                    205: */
                    206: void M68000_TraceModeTriggered(void)
                    207: {
                    208: /*
                    209:   __asm {
                    210:     cmp    [bDoTraceException],FALSE    // First time around? Skip exception
                    211:     je    dont_need_expection
                    212: 
                    213:     mov    [ExceptionVector],EXCEPTION_TRACE  // Handler
                    214:     SAVE_ASSEM_REGS            // Save assembly registers
                    215:     call  M68000_Exception        // Cause trap
                    216:     RESTORE_ASSEM_REGS          // Restore assembly registers
                    217: 
                    218: dont_need_expection:;
                    219:     mov    [bDoTraceException],TRUE    // Do TRACE exception next time around
                    220:     ret
                    221:   }
                    222: */
                    223: }
                    224: 
1.1.1.3 ! root      225: 
        !           226: /*-----------------------------------------------------------------------*/
1.1       root      227: /*
                    228:   Exception handler
                    229: */
                    230: void M68000_Exception(void)
                    231: {
                    232:   unsigned long Vector,MFPBaseVector;
                    233:   BOOL bRet=FALSE;
                    234: 
1.1.1.2   root      235:   /* Was the CPU stopped, i.e. by a STOP instruction? */
                    236:   regs.stopped = 0;
                    237:   unset_special (SPCFLAG_STOP);   /* All is go,go,go! */
                    238: 
1.1       root      239:   /* At the moment, this functions ist just a wrapper to Exception() of the UAE CPU - Thothy */
                    240:   Exception(ExceptionVector/4, m68k_getpc());
1.1.1.2   root      241: 
1.1       root      242:   return;
                    243: 
                    244: #if 0
1.1.1.3 ! root      245:   /* Was the CPU stopped, ie by a STOP instruction? */
1.1       root      246:   if (CPUStopped) {
1.1.1.3 ! root      247:     PC += 4;             /* Skip after the STOP instruction as CPU is now to resume! */
        !           248:     CPUStopped = FALSE;  /* All is go,go,go! */
1.1       root      249:   }
1.1.1.3 ! root      250: 
1.1       root      251:   /* Find exception vector, keep 32-bit address as top byte is used by TOS */
                    252:   /* exception vectors as an ID! */
                    253:   Vector = STMemory_ReadLong(ExceptionVector);
                    254: 
                    255:   /* Check for intercept - The game 'Operation Wolf' re-directs traps, */
                    256:   /* so double check is a TOS trap and not software! (ie Vector is >0xE00000) */
                    257:   if ((Vector&0xffffff)>=0xE00000) {
                    258:     if (ExceptionVector==EXCEPTION_TRAP13)
                    259:       bRet = Bios();
                    260:     else if (ExceptionVector==EXCEPTION_TRAP14)
                    261:       bRet = XBios();
                    262:     else if (ExceptionVector==EXCEPTION_TRAP1)
                    263:       bRet = GemDOS();
                    264:     else if (ExceptionVector==EXCEPTION_TRAP2) {
                    265:       bRet = VDI();
                    266:       if (!bRet) {
1.1.1.3 ! root      267:         /* Set 'PC' as address of 'VDI_OPCODE' illegal instruction */
        !           268:         /* This will call VDI_OpCode after completion of Trap call! */
        !           269:         /* Use to modify return structure from VDI */
1.1       root      270:         if (bUseVDIRes) {
                    271:           VDI_OldPC = PC;
                    272:           PC = CART_VDI_OPCODE_ADDR;
                    273:         }
                    274:       }
                    275:     }
                    276: 
1.1.1.3 ! root      277:   /* Do handly bit of debugging to trap bus/address errors, before goes to TOS handler */
1.1       root      278: #ifdef TRAP_BUSERROR_HISTORY
                    279:     if (ExceptionVector==EXCEPTION_BUSERROR) {
                    280:       MessageBox(NULL,"TRAP BUS ERROR",PROG_NAME,MB_OK | MB_ICONSTOP);
                    281:       Debug_File("TRAP BUS ERROR\n");
                    282:       M68000_OutputHistory();
                    283:       exit(0);
                    284:     }
                    285: #endif
                    286: #ifdef TRAP_ADDRESSERROR_HISTORY
                    287:     if (ExceptionVector==EXCEPTION_ADDRERROR) {
                    288:       MessageBox(NULL,"TRAP ADDRESS ERROR",PROG_NAME,MB_OK | MB_ICONSTOP);
                    289:       Debug_File("TRAP ADDRESS ERROR\n");
                    290:       M68000_OutputHistory();
                    291:       exit(0);
                    292:     }
                    293: #endif
                    294: #ifdef TRAP_ILLEGALINSTRUCTIONERROR_HISTORY
                    295:     if (ExceptionVector==EXCEPTION_ILLEGALINS) {
                    296:       MessageBox(NULL,"TRAP ILLEGAL INSTRUCTION ERROR",PROG_NAME,MB_OK | MB_ICONSTOP);
                    297:       Debug_File("TRAP ILLEGAL INSTRUCTION ERROR\n");
                    298:       M68000_OutputHistory();
                    299:       exit(0);
                    300:     }
                    301: #endif
                    302:   }
                    303: 
1.1.1.3 ! root      304:   /* Did we re-direct call? No, so let's call it! */
1.1       root      305:   if (!bRet) {
1.1.1.3 ! root      306:     /* Save PC and SR to supervisor stack */
1.1       root      307: /*
                    308:     __asm {
                    309:       push  ebp
                    310: 
                    311:       mov    edx,[Reg_SuperSP]
                    312: 
                    313:       sub    DWORD PTR [edx],SIZE_LONG
                    314:       mov    ebp,[edx]        // Stack pointer
                    315:       and    ebp,0xffffff        // as 24-bit address in PC memory(note _C)
                    316:       mov    ecx,[PC]        // Save PC
                    317:       SWAP_ENDIAN_LONG_ECX
                    318:       mov    DWORD PTR STRam[ebp],ecx
                    319: 
                    320:       sub    DWORD PTR [edx],SIZE_WORD
                    321:       mov    ebp,[edx]        // Stack pointer
                    322:       and    ebp,0xffffff        // as 24-bit address in PC memory(note _C)
                    323:       mov    cx,WORD PTR [SR]
                    324:       and    ecx,SR_MASK        // Remove condition codes
                    325:       mov    eax,[EmuCCode]
                    326:       shr    eax,4          // Emulation codes in correct bits
                    327:       and    eax,SR_CCODE_MASK
                    328:       or    eax,ecx          // Or in current condition codes
                    329:       SWAP_ENDIAN_WORD_AX
                    330:       mov    WORD PTR STRam[ebp],ax
                    331: 
                    332:       pop    ebp
                    333:     }
                    334: */
1.1.1.3 ! root      335:     /* Exception frame, total 14 bytes (6 already put on stack, ie PC and SR) */
        !           336:     /*       15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00                  */
        !           337:     /* SSP->|                                |RW|IN|Func.cod|  Higher address */
        !           338:     /*      |High word access address                       |                 */
        !           339:     /*      |Low word access address                        |                 */
        !           340:     /*      |Instruction register                           |                 */
        !           341:     /*      |Status register                                |                 */
        !           342:     /*      |High word program counter                      |                 */
        !           343:     /*      |Low word program counter                       |  Lower address  */
        !           344:     /* RW: Write=0, Read=1      */
        !           345:     /* IN: Instruction=0, Not=1 */
1.1       root      346:     if ( (ExceptionVector==EXCEPTION_BUSERROR) || (ExceptionVector==EXCEPTION_ADDRERROR) ) {
                    347: /*
                    348:       __asm {
                    349:         push  ebp
                    350: 
                    351:         mov    ebp,[InsPC]      // Get PC of instruction last ran
                    352:         mov    cx,WORD PTR [ebp]    // 'Opcode' in 68000 endian
                    353:         mov    edx,[Reg_SuperSP]
                    354:         sub    DWORD PTR [edx],SIZE_WORD
                    355:         mov    ebp,[edx]      // Stack pointer
                    356:         and    ebp,0xffffff      // as 24-bit address in PC memory(note _C)
                    357:         mov    WORD PTR STRam[ebp],cx    // Store 'Instruction Register'
                    358: 
                    359:         sub    DWORD PTR [edx],SIZE_LONG
                    360:         mov    ebp,[edx]      // Stack pointer
                    361:         and    ebp,0xffffff      // as 24-bit address in PC memory(note _C)
                    362:         mov    ecx,[BusAddressLocation]  // Address which caused fault
                    363:         SWAP_ENDIAN_LONG_ECX
                    364:         mov    DWORD PTR STRam[ebp],ecx
                    365: 
                    366:         sub    DWORD PTR [edx],SIZE_WORD
                    367:         mov    ebp,[edx]      // Stack pointer
                    368:         and    ebp,0xffffff      // as 24-bit address in PC memory(note _C)
                    369:         xor    ecx,ecx
                    370:         mov    WORD PTR STRam[ebp],cx    // '0' for now
                    371: 
                    372:         pop    ebp
                    373:       }
                    374: */
                    375:     }
                    376: 
                    377:     SR_Before = SR;
1.1.1.3 ! root      378:     SR &= SR_CLEAR_TRACEMODE;           /* Clear trace mode (bit 15) */
        !           379:     SR |= SR_SUPERMODE;                 /* Set super mode (bit 13) */
        !           380:     M68000_CheckUserSuperToggle();      /* Check if swapped mode */
1.1       root      381: 
1.1.1.3 ! root      382:     /* Do call to vector */
1.1       root      383: //    char szString[256];
                    384: //    sprintf(szString,"0x%X (0x%X)",Vector,ExceptionVector);
                    385: //    debug << szString << endl;
                    386:     PC = Vector;
1.1.1.3 ! root      387:     /* Set Status Register so interrupt can ONLY be stopped by another interrupt of higher priority! */
1.1       root      388:     if (ExceptionVector==EXCEPTION_VBLANK)
1.1.1.3 ! root      389:       SR = (SR&SR_CLEAR_IPL)|0x0400;        /* VBL, level 4 */
1.1       root      390:     else if (ExceptionVector==EXCEPTION_HBLANK)
1.1.1.3 ! root      391:       SR = (SR&SR_CLEAR_IPL)|0x0200;        /* HBL, level 2 */
1.1       root      392:     else {
                    393:       MFPBaseVector = (unsigned int)(MFP_VR&0xf0)<<2;
                    394:       if ( (ExceptionVector>=MFPBaseVector) && (ExceptionVector<=(MFPBaseVector+0x34)) )
1.1.1.3 ! root      395:         SR = (SR&SR_CLEAR_IPL)|0x0600;      /* MFP, level 6 */
1.1       root      396:     }
                    397:   }
                    398: #endif
                    399: }
                    400: 
1.1.1.3 ! root      401: 
        !           402: /*-----------------------------------------------------------------------*/
1.1       root      403: /*
                    404:   Handle Line-A OpCode exception(Top 4-bit in opcode are 0xA)
                    405: */
                    406: /*
1.1.1.3 ! root      407: void M68000_Line_A_OpCode(void)
1.1       root      408: {
                    409:   PC -= SIZE_WORD;    // PC needs to be at address of Line-A instruction
                    410:   ExceptionVector = EXCEPTION_LINE_A;
                    411:   M68000_Exception();
                    412: }
                    413: */
                    414: 
1.1.1.3 ! root      415: 
        !           416: /*-----------------------------------------------------------------------*/
1.1       root      417: /*
                    418:   During init do 0xA000, followed by 0xA0FF - we use this to get pointer to Line-A structure details(to fix for extended VDI res)
                    419: */
                    420: void M68000_Line_A_Trap(void)
                    421: {
                    422: /* FIXME */
                    423: /*
                    424: 
                    425:   PUSH_ALL
                    426:   __asm {
                    427:     mov    edx,DWORD PTR Regs[REG_D0*4]
                    428:     mov    [LineABase],edx
                    429:     mov    edx,DWORD PTR Regs[REG_A1*4]
                    430:     mov    [FontBase],edx
                    431:     call  VDI_LineA                // Modify Line-A structure
                    432:   }
                    433:   POP_ALL
                    434:   RET
                    435: */
                    436: }
                    437: 
1.1.1.3 ! root      438: 
        !           439: /*-----------------------------------------------------------------------*/
1.1       root      440: /*
                    441:   Handle Line-F OpCode exception(Top 4-bit in opcode are 0xF)
                    442: */
                    443: /*
1.1.1.3 ! root      444: void M68000_Line_F_OpCode(void)
1.1       root      445: {
                    446:   PC -= SIZE_WORD;    // PC needs to be at address of Line-F instruction
                    447:   ExceptionVector = EXCEPTION_LINE_F;
                    448:   M68000_Exception();
                    449: }
                    450: */
                    451: 
                    452: 
1.1.1.3 ! root      453: /*-----------------------------------------------------------------------*/
1.1       root      454: /*
                    455:   Output CPU instruction history(last 'x' instructions) for debugging
                    456: */
                    457: void M68000_OutputHistory(void)
                    458: {
                    459: #ifndef FINAL_VERSION
                    460:   unsigned long StartPC;
                    461:   int i;
                    462: 
                    463:   /* First, Return back into a Window */
                    464:   Screen_ReturnFromFullScreen();
                    465:   View_ToggleWindowsMouse(MOUSE_WINDOWS);
                    466: 
                    467:   Debug_File("HISTORY\n");
                    468: 
                    469:   for(i=0; i<(INSTRUCTION_HISTORY_SIZE-1); i++) {
                    470:     StartPC = DisPC = InstructionHistory[(InstructionHistoryIndex+i+1)&INSTRUCTION_HISTORY_MASK];
1.1.1.3 ! root      471:     Disass_DiassembleLine();            /* Disassemble instruction */
1.1       root      472: 
                    473:     Debug_File("%8.8X\t%s\n",StartPC,szOpString);
                    474:   }
                    475: #endif
                    476: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.