|
|
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.