|
|
1.1 ! root 1: /* ! 2: Hatari - cycInt.c ! 3: ! 4: This file is distributed under the GNU Public License, version 2 or at ! 5: your option any later version. Read the file gpl.txt for details. ! 6: ! 7: This code handles our table with callbacks for cycle accurate program ! 8: interruption. We add any pending callback handler into a table so that we do ! 9: not need to test for every possible interrupt event. We then scan ! 10: the list if used entries in the table and copy the one with the least cycle ! 11: count into the global 'PendingInterrupt' variable. This is then ! 12: decremented by the execution loop - rather than decrement each and every ! 13: entry (as the others cannot occur before this one). ! 14: We support three time units: CPU cycles, ticks, and microseconds. ! 15: Ticks are bound to CPU cycles and run at TICK_RATE MHz. Microseconds are either ! 16: bound to the host CPU's performance counter in real-time mode or to the emulated ! 17: CPU cycles if non-realtime mode. ! 18: */ ! 19: ! 20: const char CycInt_fileid[] = "Previous cycInt.c : " __DATE__ " " __TIME__; ! 21: ! 22: #include <stdint.h> ! 23: #include <assert.h> ! 24: #include "main.h" ! 25: #include "cycInt.h" ! 26: #include "m68000.h" ! 27: #include "screen.h" ! 28: #include "video.h" ! 29: #include "sysReg.h" ! 30: #include "esp.h" ! 31: #include "mo.h" ! 32: #include "ethernet.h" ! 33: #include "dma.h" ! 34: #include "floppy.h" ! 35: #include "snd.h" ! 36: #include "printer.h" ! 37: #include "kms.h" ! 38: #include "configuration.h" ! 39: #include "main.h" ! 40: #include "nd_sdl.hpp" ! 41: ! 42: void (*PendingInterruptFunction)(void); ! 43: Sint64 PendingInterruptCounter; ! 44: int usCheckCycles; ! 45: ! 46: Sint64 nCyclesOver; ! 47: Sint64 nCyclesMainCounter; /* Main cycles counter, counts emulated CPU cycles sind reset */ ! 48: ! 49: ! 50: /* List of possible interrupt handlers to be store in 'PendingInterruptTable', ! 51: * used for 'MemorySnapShot' */ ! 52: static void (* const pIntHandlerFunctions[MAX_INTERRUPTS])(void) = ! 53: { ! 54: NULL, ! 55: Video_InterruptHandler_VBL, ! 56: Hardclock_InterruptHandler, ! 57: Mouse_Handler, ! 58: ESP_InterruptHandler, ! 59: ESP_IO_Handler, ! 60: M2MDMA_IO_Handler, ! 61: MO_InterruptHandler, ! 62: MO_IO_Handler, ! 63: ECC_IO_Handler, ! 64: ENET_IO_Handler, ! 65: FLP_IO_Handler, ! 66: SND_Out_Handler, ! 67: SND_In_Handler, ! 68: Printer_IO_Handler, ! 69: Main_EventHandlerInterrupt, ! 70: nd_vbl_handler, ! 71: nd_video_vbl_handler, ! 72: }; ! 73: ! 74: static INTERRUPTHANDLER InterruptHandlers[MAX_INTERRUPTS]; ! 75: INTERRUPTHANDLER PendingInterrupt; ! 76: static int ActiveInterrupt=0; ! 77: ! 78: static void CycInt_SetNewInterrupt(void); ! 79: ! 80: extern Uint8 NEXTRom[0x20000]; ! 81: ! 82: /*-----------------------------------------------------------------------*/ ! 83: /** ! 84: * Reset interrupts, handlers ! 85: */ ! 86: void CycInt_Reset(void) { ! 87: int i; ! 88: ! 89: /* Reset counts */ ! 90: PendingInterrupt.time = 0; ! 91: ActiveInterrupt = 0; ! 92: nCyclesOver = 0; ! 93: nCyclesMainCounter = 0; ! 94: usCheckCycles = 0; ! 95: ! 96: /* Reset interrupt table */ ! 97: for (i=0; i<MAX_INTERRUPTS; i++) { ! 98: InterruptHandlers[i].type = CYC_INT_NONE; ! 99: InterruptHandlers[i].time = INT64_MAX; ! 100: InterruptHandlers[i].pFunction = pIntHandlerFunctions[i]; ! 101: } ! 102: } ! 103: ! 104: /*-----------------------------------------------------------------------*/ ! 105: /** ! 106: * Find next interrupt to occur, and store to global variables for decrement ! 107: * in instruction decode loop. ! 108: * (SC) Microseconf interrupts are skipped here and handled in the decode loop. ! 109: */ ! 110: static void CycInt_SetNewInterrupt(void) { ! 111: Sint64 LowestCycleCount = INT64_MAX; ! 112: interrupt_id LowestInterrupt = INTERRUPT_NULL; ! 113: ! 114: /* Find next interrupt to go off */ ! 115: for(int i = INTERRUPT_NULL+1; i < MAX_INTERRUPTS; i++) { ! 116: /* Is interrupt pending? */ ! 117: if(InterruptHandlers[i].type == CYC_INT_CPU && InterruptHandlers[i].time < LowestCycleCount) { ! 118: LowestCycleCount = InterruptHandlers[i].time; ! 119: LowestInterrupt = i; ! 120: } ! 121: } ! 122: ! 123: /* Set new counts, active interrupt */ ! 124: PendingInterrupt = InterruptHandlers[LowestInterrupt]; ! 125: ActiveInterrupt = LowestInterrupt; ! 126: } ! 127: ! 128: /*-----------------------------------------------------------------------*/ ! 129: /** ! 130: * Adjust all interrupt timings, MUST call CycInt_SetNewInterrupt after this. ! 131: */ ! 132: static void CycInt_UpdateInterrupt(void) { ! 133: int i; ! 134: ! 135: /* Adjust table by subtracting cycles that have passed since last update */ ! 136: for (i = 0; i < MAX_INTERRUPTS; i++) { ! 137: if (InterruptHandlers[i].type == CYC_INT_CPU) ! 138: InterruptHandlers[i].time -= nCyclesOver; ! 139: } ! 140: nCyclesOver = 0; ! 141: } ! 142: ! 143: /*-----------------------------------------------------------------------*/ ! 144: /** ! 145: * Check all microsecond interrupt timings ! 146: */ ! 147: bool CycInt_SetNewInterruptUs(void) { ! 148: Sint64 now = host_time_us(); ! 149: if (ConfigureParams.System.bRealtime) { ! 150: for(int i = 0; i < MAX_INTERRUPTS; i++) { ! 151: if (InterruptHandlers[i].type == CYC_INT_US && now > InterruptHandlers[i].time) { ! 152: PendingInterrupt = InterruptHandlers[i]; ! 153: PendingInterrupt.time = -1; ! 154: ActiveInterrupt = i; ! 155: return true; ! 156: } ! 157: } ! 158: } ! 159: return false; ! 160: } ! 161: ! 162: /*-----------------------------------------------------------------------*/ ! 163: /** ! 164: * Adjust all interrupt timings as 'ActiveInterrupt' has occured, and ! 165: * remove from active list. ! 166: */ ! 167: void CycInt_AcknowledgeInterrupt(void) { ! 168: /* Update list cycle counts */ ! 169: CycInt_UpdateInterrupt(); ! 170: ! 171: /* Disable interrupt entry which has just occured */ ! 172: InterruptHandlers[ActiveInterrupt].type = CYC_INT_NONE; ! 173: ! 174: /* Set new */ ! 175: CycInt_SetNewInterrupt(); ! 176: } ! 177: ! 178: /*-----------------------------------------------------------------------*/ ! 179: /** ! 180: * Add interrupt to occur from now. ! 181: */ ! 182: void CycInt_AddRelativeInterruptCycles(Sint64 CycleTime, interrupt_id Handler) { ! 183: assert(CycleTime >= 0); ! 184: ! 185: /* Update list cycle counts with current PendingInterruptCount before adding a new int, */ ! 186: /* because CycInt_SetNewInterrupt can change the active int / PendingInterruptCount */ ! 187: if ( ActiveInterrupt > 0 ) ! 188: CycInt_UpdateInterrupt(); ! 189: ! 190: InterruptHandlers[Handler].type = CYC_INT_CPU; ! 191: InterruptHandlers[Handler].time = CycleTime; ! 192: ! 193: /* Set new active int and compute a new value for PendingInterruptCount*/ ! 194: CycInt_SetNewInterrupt(); ! 195: } ! 196: ! 197: /*-----------------------------------------------------------------------*/ ! 198: /** ! 199: * Add interrupt to occur us microsencods from now ! 200: * Use usreal if we are in realtime mode ! 201: */ ! 202: void CycInt_AddRelativeInterruptUs(Sint64 us, Sint64 usreal, interrupt_id Handler) { ! 203: assert(us >= 0); ! 204: ! 205: if(ConfigureParams.System.bRealtime) { ! 206: /* Update list cycle counts with current PendingInterruptCount before adding a new int, */ ! 207: /* because CycInt_SetNewInterrupt can change the active int / PendingInterruptCount */ ! 208: if ( ActiveInterrupt > 0 ) CycInt_UpdateInterrupt(); ! 209: ! 210: if ( usreal > 0 ) us = usreal; ! 211: ! 212: InterruptHandlers[Handler].type = CYC_INT_US; ! 213: InterruptHandlers[Handler].time = host_time_us() + us; ! 214: ! 215: /* Set new active int and compute a new value for PendingInterruptCount*/ ! 216: CycInt_SetNewInterrupt(); ! 217: } else { ! 218: CycInt_AddRelativeInterruptCycles(us * ConfigureParams.System.nCpuFreq, Handler); ! 219: } ! 220: } ! 221: ! 222: /*-----------------------------------------------------------------------*/ ! 223: /** ! 224: * Add interrupt to occur microseconds from now. Convert to cycles. ! 225: * Use UsTimeFast if we are in realtime mode. ! 226: */ ! 227: void CycInt_AddRelativeInterruptUsCycles(Sint64 us, Sint64 usreal, interrupt_id Handler) { ! 228: ! 229: if (ConfigureParams.System.bRealtime && usreal > 0) { ! 230: us = usreal; ! 231: } ! 232: ! 233: CycInt_AddRelativeInterruptCycles(us * ConfigureParams.System.nCpuFreq, Handler); ! 234: } ! 235: ! 236: /*-----------------------------------------------------------------------*/ ! 237: /** ! 238: * Remove a pending interrupt from our table ! 239: */ ! 240: void CycInt_RemovePendingInterrupt(interrupt_id Handler) { ! 241: /* Update list cycle counts, including the handler we want to remove */ ! 242: /* to be able to resume it later */ ! 243: CycInt_UpdateInterrupt(); ! 244: ! 245: /* Stop interrupt after CycInt_UpdateInterrupt */ ! 246: InterruptHandlers[Handler].type = CYC_INT_NONE; ! 247: ! 248: /* Set new */ ! 249: CycInt_SetNewInterrupt(); ! 250: } ! 251: ! 252: ! 253: /*-----------------------------------------------------------------------*/ ! 254: /** ! 255: * Return true if interrupt is active in list ! 256: */ ! 257: bool CycInt_InterruptActive(interrupt_id Handler) ! 258: { ! 259: return InterruptHandlers[Handler].type != CYC_INT_NONE; ! 260: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.