|
|
1.1 root 1: /*
1.1.1.3 root 2: Hatari - int.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.
1.1 root 6:
7: This code handles our interrupt table. So we do not need to test for every possible
8: interrupt we add any pending interrupts into a table. We then scan the list if used
9: entries in the table and copy the one with the least cycle count into the global
10: 'PendingInterruptCount' variable. This is then decremented by the execution loop -
11: rather than decrement each and every entry (as the others cannot occur before this one)
12: We have two methods of adding interrupts; Absolute and Relative. Absolute will set values
13: from the time of the previous interrupt(eg, add HBL every 512 cycles), and Relative
14: will add from the current cycle time.
15: Note that interrupt may occur 'late'. Ie, if an interrupt is due in 4 cycles time but
16: the current instruction takes 20 cycles we will be 16 cycles late - this is handled in
17: the adjust functions.
18: */
1.1.1.6 ! root 19: char Int_rcsid[] = "Hatari $Id: int.c,v 1.9 2005/08/06 12:32:09 thothy Exp $";
1.1 root 20:
21: #include "main.h"
1.1.1.6 ! root 22: #include "dmaSnd.h"
1.1 root 23: #include "ikbd.h"
24: #include "int.h"
25: #include "m68000.h"
26: #include "memorySnapShot.h"
27: #include "mfp.h"
28: #include "sound.h"
29: #include "video.h"
30:
1.1.1.3 root 31:
1.1 root 32: /* List of possible interrupt handlers to be store in 'PendingInterruptTable', used for 'MemorySnapShot' */
1.1.1.3 root 33: void *pIntHandlerFunctions[] =
34: {
1.1 root 35: NULL,
36: Video_InterruptHandler_VBL,
37: Video_InterruptHandler_HBL,
38: Video_InterruptHandler_EndLine,
39: MFP_InterruptHandler_TimerA,
40: MFP_InterruptHandler_TimerB,
41: MFP_InterruptHandler_TimerC,
42: MFP_InterruptHandler_TimerD,
43: IKBD_InterruptHandler_ResetTimer,
44: IKBD_InterruptHandler_ACIA,
1.1.1.6 ! root 45: DmaSnd_InterruptHandler,
1.1 root 46: NULL
47: };
48:
49: INTERRUPTHANDLER InterruptHandlers[MAX_INTERRUPTS];
50: int nCyclesOver=0;
51: int nFrameCyclesOver=0;
52: int ActiveInterrupt=0;
53:
1.1.1.2 root 54:
55: /*-----------------------------------------------------------------------*/
1.1 root 56: /*
57: Reset interrupts, handlers
58: */
59: void Int_Reset(void)
60: {
61: int i;
62:
1.1.1.2 root 63: /* Reset counts */
1.1 root 64: PendingInterruptCount = 0;
65: nCyclesOver = 0;
66:
1.1.1.2 root 67: /* Reset interrupt table */
1.1 root 68: for(i=0; i<MAX_INTERRUPTS; i++) {
69: InterruptHandlers[i].bUsed = FALSE;
70: InterruptHandlers[i].pFunction = pIntHandlerFunctions[i];
71: }
72: }
73:
1.1.1.2 root 74:
75: /*-----------------------------------------------------------------------*/
1.1 root 76: /*
77: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
78: */
79: void Int_MemorySnapShot_Capture(BOOL bSave)
80: {
81: int i,ID;
82:
1.1.1.2 root 83: /* Save/Restore details */
1.1 root 84: for(i=0; i<MAX_INTERRUPTS; i++) {
85: MemorySnapShot_Store(&InterruptHandlers[i].bUsed,sizeof(InterruptHandlers[i].bUsed));
86: MemorySnapShot_Store(&InterruptHandlers[i].Cycles,sizeof(InterruptHandlers[i].Cycles));
87: if (bSave) {
1.1.1.2 root 88: /* Convert function to ID */
1.1 root 89: ID = Int_HandlerFunctionToID(InterruptHandlers[i].pFunction);
90: MemorySnapShot_Store(&ID,sizeof(int));
91: }
92: else {
1.1.1.2 root 93: /* Convert ID to function */
1.1 root 94: MemorySnapShot_Store(&ID,sizeof(int));
95: InterruptHandlers[i].pFunction = Int_IDToHandlerFunction(ID);
96: }
97: }
98: MemorySnapShot_Store(&nCyclesOver,sizeof(nCyclesOver));
99: MemorySnapShot_Store(&nFrameCyclesOver,sizeof(nFrameCyclesOver));
100: }
101:
1.1.1.2 root 102:
103: /*-----------------------------------------------------------------------*/
1.1 root 104: /*
105: Convert interrupt handler function pointer to ID, used for saving
106: */
107: int Int_HandlerFunctionToID(void *pHandlerFunction)
108: {
109: int i;
110:
1.1.1.2 root 111: /* Is NULL, return ID 0 */
1.1 root 112: if (pHandlerFunction==NULL)
113: return(0);
114:
1.1.1.2 root 115: /* Scan for function match */
1.1 root 116: for(i=1; i<MAX_INTERRUPTS; i++) {
117: if (pIntHandlerFunctions[i]==pHandlerFunction)
118: return(i);
119: }
120:
1.1.1.2 root 121: /* Didn't find one! Oops */
1.1 root 122: return(0);
123: }
124:
1.1.1.2 root 125:
126: /*-----------------------------------------------------------------------*/
1.1 root 127: /*
128: Convert ID back into interrupt handler function, used for restoring
129: */
130: void *Int_IDToHandlerFunction(int ID)
131: {
1.1.1.2 root 132: /* Get function pointer */
1.1 root 133: return( pIntHandlerFunctions[ID] );
134: }
135:
1.1.1.2 root 136:
137: /*-----------------------------------------------------------------------*/
1.1 root 138: /*
139: Return number of clock cycles into retrace
140: */
141: int Int_FindFrameCycles(void)
142: {
143: return( nFrameCyclesOver + (InterruptHandlers[ActiveInterrupt].Cycles-PendingInterruptCount) );
144: }
145:
1.1.1.2 root 146:
147: /*-----------------------------------------------------------------------*/
1.1 root 148: /*
149: Find next interrupt to occur, and store to global variables for decrement in instruction decode loop
150: */
151: void Int_SetNewInterrupt(void)
152: {
153: int LowestCycleCount=999999,LowestInterrupt=0;
154: int i;
155:
1.1.1.2 root 156: /* Find next interrupt to go off */
1.1 root 157: for(i=0; i<MAX_INTERRUPTS; i++) {
1.1.1.2 root 158: /* Is interrupt pending? */
1.1 root 159: if (InterruptHandlers[i].bUsed) {
160: if (InterruptHandlers[i].Cycles<LowestCycleCount) {
161: LowestCycleCount = InterruptHandlers[i].Cycles;
162: LowestInterrupt = i;
163: }
164: }
165: }
1.1.1.2 root 166:
167: /* Set new counts, active interrupt */
1.1 root 168: PendingInterruptCount = (short int)InterruptHandlers[LowestInterrupt].Cycles;
169: PendingInterruptFunction = InterruptHandlers[LowestInterrupt].pFunction;
170: ActiveInterrupt = LowestInterrupt;
171:
172: }
173:
1.1.1.2 root 174:
175: /*-----------------------------------------------------------------------*/
1.1 root 176: /*
177: Adjust all interrupt timings, MUST call Int_SetNewInterrupt after this
178: */
1.1.1.3 root 179: static void Int_UpdateInterrupt(void)
1.1 root 180: {
181: int CycleSubtract;
182: int i;
183:
1.1.1.2 root 184: /* Find out how many cycles we went over (<=0) */
1.1 root 185: nCyclesOver = PendingInterruptCount;
1.1.1.2 root 186: /* Calculate how many cycles have passed, included time we went over */
1.1 root 187: CycleSubtract = InterruptHandlers[ActiveInterrupt].Cycles-nCyclesOver;
188:
1.1.1.2 root 189: /* Adjust table */
1.1 root 190: for(i=0; i<MAX_INTERRUPTS; i++) {
191: if (InterruptHandlers[i].bUsed)
192: InterruptHandlers[i].Cycles -= CycleSubtract;
193: }
194: nFrameCyclesOver += CycleSubtract;
195: }
196:
1.1.1.2 root 197:
198: /*-----------------------------------------------------------------------*/
1.1 root 199: /*
200: Adjust all interrupt timings as 'ActiveInterrupt' has occured, and remove from active list
201: */
202: void Int_AcknowledgeInterrupt(void)
203: {
1.1.1.2 root 204: /* Update list cycle counts */
1.1 root 205: Int_UpdateInterrupt();
206:
1.1.1.2 root 207: /* Disable interrupt entry which has just occured */
1.1 root 208: InterruptHandlers[ActiveInterrupt].bUsed = FALSE;
209:
1.1.1.2 root 210: /* Set new */
1.1 root 211: Int_SetNewInterrupt();
212: }
213:
1.1.1.2 root 214:
215: /*-----------------------------------------------------------------------*/
1.1 root 216: /*
217: Add interrupt from time last one occurred
218: */
219: void Int_AddAbsoluteInterrupt(int CycleTime, int Handler)
220: {
221: InterruptHandlers[Handler].bUsed = TRUE;
222: InterruptHandlers[Handler].Cycles = CycleTime + nCyclesOver;
223:
1.1.1.2 root 224: /* Set new */
1.1 root 225: Int_SetNewInterrupt();
226: }
227:
1.1.1.2 root 228:
229: /*-----------------------------------------------------------------------*/
1.1 root 230: /*
231: Add interrupt to occur from now
232: */
233: void Int_AddRelativeInterrupt(int CycleTime, int Handler)
234: {
235: InterruptHandlers[Handler].bUsed = TRUE;
236: InterruptHandlers[Handler].Cycles = CycleTime;
237:
1.1.1.2 root 238: /* Set new */
1.1 root 239: Int_SetNewInterrupt();
240: }
241:
1.1.1.2 root 242:
243: /*-----------------------------------------------------------------------*/
1.1 root 244: /*
245: Remove a pending interrupt from our table
246: */
247: void Int_RemovePendingInterrupt(int Handler)
248: {
1.1.1.2 root 249: /* Stop interrupt */
1.1 root 250: InterruptHandlers[Handler].bUsed = FALSE;
251:
1.1.1.2 root 252: /* Update list cycle counts */
1.1 root 253: Int_UpdateInterrupt();
1.1.1.2 root 254: /* Set new */
1.1 root 255: Int_SetNewInterrupt();
256: }
257:
1.1.1.2 root 258:
259: /*-----------------------------------------------------------------------*/
1.1 root 260: /*
261: Return TRUE if interrupt is active in list
262: */
263: BOOL Int_InterruptActive(int Handler)
264: {
1.1.1.2 root 265: /* Is timer active? */
1.1 root 266: if (InterruptHandlers[Handler].bUsed)
267: return(TRUE);
268:
269: return(FALSE);
270: }
271:
1.1.1.2 root 272:
273: /*-----------------------------------------------------------------------*/
1.1 root 274: /*
275: Return cycles passed for an interrupt handler
276: */
277: int Int_FindCyclesPassed(int Handler)
278: {
279: int CyclesPassed, CyclesFromLastInterrupt;
280:
281: CyclesFromLastInterrupt = (int)InterruptHandlers[ActiveInterrupt].Cycles-PendingInterruptCount;
282: CyclesPassed = ((int)InterruptHandlers[Handler].Cycles-CyclesFromLastInterrupt);
283:
284: return(CyclesPassed);
285: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.