|
|
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
1.1.1.5 ! root 11: count into the global 'PendingInterrupt' variable. This is then
1.1 root 12: decremented by the execution loop - rather than decrement each and every
13: entry (as the others cannot occur before this one).
1.1.1.5 ! root 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.
1.1 root 18: */
19:
1.1.1.5 ! root 20: const char CycInt_fileid[] = "Previous cycInt.c : " __DATE__ " " __TIME__;
1.1 root 21:
22: #include <stdint.h>
23: #include <assert.h>
24: #include "main.h"
25: #include "cycInt.h"
26: #include "m68000.h"
1.1.1.2 root 27: #include "screen.h"
1.1 root 28: #include "video.h"
1.1.1.3 root 29: #include "sysReg.h"
1.1.1.4 root 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"
1.1.1.5 ! root 38: #include "configuration.h"
! 39: #include "main.h"
! 40: #include "nd_sdl.h"
1.1 root 41:
42: void (*PendingInterruptFunction)(void);
1.1.1.5 ! root 43: Sint64 PendingInterruptCounter;
! 44: int usCheckCycles;
! 45:
! 46: Sint64 nCyclesOver;
! 47: Sint64 nCyclesMainCounter; /* Main cycles counter, counts emulated CPU cycles sind reset */
1.1 root 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,
1.1.1.2 root 55: Video_InterruptHandler_VBL,
1.1.1.4 root 56: Hardclock_InterruptHandler,
57: Mouse_Handler,
58: ESP_InterruptHandler,
59: ESP_IO_Handler,
1.1.1.5 ! root 60: M2MDMA_IO_Handler,
1.1.1.4 root 61: MO_InterruptHandler,
62: MO_IO_Handler,
63: ECC_IO_Handler,
64: ENET_IO_Handler,
65: FLP_IO_Handler,
1.1.1.5 ! root 66: SND_Out_Handler,
! 67: SND_In_Handler,
! 68: Printer_IO_Handler,
! 69: Main_EventHandlerInterrupt,
! 70: nd_vbl_handler,
! 71: nd_video_vbl_handler,
1.1 root 72: };
73:
74: static INTERRUPTHANDLER InterruptHandlers[MAX_INTERRUPTS];
1.1.1.5 ! root 75: INTERRUPTHANDLER PendingInterrupt;
! 76: static int ActiveInterrupt=0;
1.1 root 77:
78: static void CycInt_SetNewInterrupt(void);
79:
1.1.1.5 ! root 80: extern Uint8 NEXTRom[0x20000];
! 81:
1.1 root 82: /*-----------------------------------------------------------------------*/
83: /**
84: * Reset interrupts, handlers
85: */
1.1.1.5 ! root 86: void CycInt_Reset(void) {
1.1 root 87: int i;
88:
89: /* Reset counts */
1.1.1.5 ! root 90: PendingInterrupt.time = 0;
! 91: ActiveInterrupt = 0;
! 92: nCyclesOver = 0;
! 93: nCyclesMainCounter = 0;
! 94: usCheckCycles = 0;
! 95:
1.1 root 96: /* Reset interrupt table */
1.1.1.5 ! root 97: for (i=0; i<MAX_INTERRUPTS; i++) {
! 98: InterruptHandlers[i].type = CYC_INT_NONE;
! 99: InterruptHandlers[i].time = INT64_MAX;
1.1 root 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.
1.1.1.5 ! root 108: * (SC) Microseconf interrupts are skipped here and handled in the decode loop.
1.1 root 109: */
1.1.1.5 ! root 110: static void CycInt_SetNewInterrupt(void) {
! 111: Sint64 LowestCycleCount = INT64_MAX;
! 112: interrupt_id LowestInterrupt = INTERRUPT_NULL;
! 113:
1.1 root 114: /* Find next interrupt to go off */
1.1.1.5 ! root 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: }
1.1 root 121: }
122:
123: /* Set new counts, active interrupt */
1.1.1.5 ! root 124: PendingInterrupt = InterruptHandlers[LowestInterrupt];
! 125: ActiveInterrupt = LowestInterrupt;
1.1 root 126: }
127:
128: /*-----------------------------------------------------------------------*/
129: /**
130: * Adjust all interrupt timings, MUST call CycInt_SetNewInterrupt after this.
131: */
1.1.1.5 ! root 132: static void CycInt_UpdateInterrupt(void) {
1.1 root 133: int i;
134:
1.1.1.5 ! root 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;
1.1 root 141: }
142:
1.1.1.5 ! root 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: }
1.1 root 161:
162: /*-----------------------------------------------------------------------*/
163: /**
164: * Adjust all interrupt timings as 'ActiveInterrupt' has occured, and
165: * remove from active list.
166: */
1.1.1.5 ! root 167: void CycInt_AcknowledgeInterrupt(void) {
1.1 root 168: /* Update list cycle counts */
169: CycInt_UpdateInterrupt();
170:
171: /* Disable interrupt entry which has just occured */
1.1.1.5 ! root 172: InterruptHandlers[ActiveInterrupt].type = CYC_INT_NONE;
1.1 root 173:
174: /* Set new */
175: CycInt_SetNewInterrupt();
176: }
177:
178: /*-----------------------------------------------------------------------*/
179: /**
1.1.1.5 ! root 180: * Add interrupt to occur from now.
1.1 root 181: */
1.1.1.5 ! root 182: void CycInt_AddRelativeInterruptCycles(Sint64 CycleTime, interrupt_id Handler) {
1.1 root 183: assert(CycleTime >= 0);
184:
1.1.1.2 root 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 )
1.1 root 188: CycInt_UpdateInterrupt();
189:
1.1.1.5 ! root 190: InterruptHandlers[Handler].type = CYC_INT_CPU;
! 191: InterruptHandlers[Handler].time = CycleTime;
1.1 root 192:
1.1.1.2 root 193: /* Set new active int and compute a new value for PendingInterruptCount*/
1.1 root 194: CycInt_SetNewInterrupt();
195: }
196:
197: /*-----------------------------------------------------------------------*/
198: /**
1.1.1.5 ! root 199: * Add interrupt to occur us microsencods from now
! 200: * Use usreal if we are in realtime mode
1.1 root 201: */
1.1.1.5 ! root 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: }
1.1 root 220: }
221:
222: /*-----------------------------------------------------------------------*/
223: /**
1.1.1.5 ! root 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: }
1.1 root 232:
1.1.1.5 ! root 233: CycInt_AddRelativeInterruptCycles(us * ConfigureParams.System.nCpuFreq, Handler);
1.1 root 234: }
235:
236: /*-----------------------------------------------------------------------*/
237: /**
238: * Remove a pending interrupt from our table
239: */
1.1.1.5 ! root 240: void CycInt_RemovePendingInterrupt(interrupt_id Handler) {
1.1 root 241: /* Update list cycle counts, including the handler we want to remove */
1.1.1.5 ! root 242: /* to be able to resume it later */
1.1 root 243: CycInt_UpdateInterrupt();
244:
1.1.1.5 ! root 245: /* Stop interrupt after CycInt_UpdateInterrupt */
! 246: InterruptHandlers[Handler].type = CYC_INT_NONE;
1.1 root 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: {
1.1.1.5 ! root 259: return InterruptHandlers[Handler].type != CYC_INT_NONE;
1.1 root 260: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.