|
|
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"
1.1.1.6 ! root 40: #include "nd_sdl.hpp"
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.6 ! root 108: * (SC) Microsecond 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.