|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - mfp.c
1.1 root 3:
1.1.1.5 root 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: MFP - Multi Functional Peripheral. In emulation terms it's the 'chip from
8: hell' - most differences between a real machine and an emulator are down to
9: this chip. It seems very simple at first but the implementation is very
10: difficult.
11: The following code is the very accurate for an ST emulator as it is able to
12: perform Spectrum 512 raster effects as well as simulate the quirks found in
13: the chip. The easiest way to 'see' the MFP chip is to look at the diagram.
14: It shows the main details of the chip's behaviour with regard to interrupts
15: and pending/service bits.
1.1 root 16: */
1.1.1.11 root 17:
18: /* 2007/04/18 [NP] - Better values for MFPTimerToCPUCycleTable. */
19: /* - Don't restart the timers in MFP_EnableA_WriteByte and */
20: /* MFP_EnableB_WriteByte, this gives wrong results. */
21: /* 2007/05/05 [NP] - When a timer is looping (counter reaches 0), we must use */
22: /* PendingCyclesOver to restart it with Int_AddRelativeInterrupt. */
23: /* PendingCyclesOver is the value of PendingInterruptCount when */
24: /* the timer expired. */
25: /* - MFP_ReadTimer_AB/CD was wrong (returned the elapsed counter */
1.1.1.12 root 26: /* changes since start, instead of the remaining counter value). */
1.1.1.11 root 27: /* (ULM DSOTS Demos and Overscan Demos). */
28: /* 2007/09/25 [NP] Replace printf by calls to HATARI_TRACE. */
29: /* 2007/10/21 [NP] Use 'Int_AddRelativeInterruptWithOffset' when an MFP timer is */
30: /* looping. Gives better accuracy when using '4' as a divisor. */
31: /* (fix ULM DSOTS Demos and Overscan Demos). */
32: /* 2007/10/24 [NP] Handle the possibility to resume a timer after stopping it. */
33: /* After writing 0 to ctrl, writing a >0 in ctrl should continue */
34: /* the timer with the value that was stored in data reg when timer */
35: /* was stopped. The value is saved in MFP_Tx_MAINCOUNTER whenever */
36: /* 0 is written in ctrl reg (Froggies Over The Fence by STCNX). */
37: /* 2007/10/28 [NP] Function 'Int_ResumeStoppedInterrupt' to better handle the */
38: /* possibility to resume a timer that was stopped with ctrl=0 */
39: /* (ST CNX screen in Punish Your Machine). */
40: /* 2007/12/27 [NP] When adding a new MFP interrupt (ctrl != 0 ), we must take */
41: /* into account the number of cycles of the current instruction, as*/
42: /* well as the accumulated wait state cycles, else the int counter */
43: /* will be started between 8 - 20 cycles earlier, which can break */
44: /* some too strict code : the int counter must start after the */
45: /* current instruction is processed, not before. The write is */
46: /* considered effective 4 cycles before the end of the current */
47: /* instruction. */
48: /* (fix ULM Dark Side Of The Spoon and Decade Demo's Wow Scroll 2).*/
49: /* 2008/02/06 [NP] Handle "fast" timers as those started by the TOS for the RS232 */
50: /* baud rate generator. In that case, the timers could be too fast */
51: /* to be handled by the CPU, which means PendingCyclesOver can be */
52: /* >= INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE ) */
53: /* and this will give wrong results when the timer restarts if */
54: /* we call Int_AddRelativeInterruptWithOffset. We use a modulo to */
55: /* limit PendingCyclesOver to not more than the number of cycles */
56: /* of one int (which means we "skip" the ints that could not be */
57: /* processed). */
58: /* 2008/03/08 [NP] Add traces when writing to vector register fffa17. */
59: /* Use M68000_INT_MFP when calling M68000_Exception(). */
1.1.1.12 root 60: /* 2008/04/17 [NP] Handle the case where Timer B is in event count mode and the */
61: /* content of $fffa21 is updated by the end of line signal while a */
62: /* read instruction at addr $fffa21 occurs at the same time (before*/
63: /* calling MFP_TimerB_EventCount_Interrupt). */
64: /* In that case, we need to return MFP_TB_MAINCOUNTER - 1. */
65: /* (fix B.I.G. Demo Screen 1). */
66: /* FIXME : this should be handled by Cycles_GetCounterOnReadAccess */
67: /* but it's not correctly implemented at the moment. */
68: /* 2008/04/20 [NP] In the TRACE call in 'MFP_Exception', replace 'get_long' by */
69: /* 'STMemory_ReadLong' because 'get_long' produced a bus error */
70: /* if we were not already in supervisor mode when the mfp exception*/
71: /* occured. This could cause bus error when restoring snapshot */
72: /* of a gemdos program for example if trace mode was activated. */
73: /* 2008/07/12 [NP] When stopping an active timer just when the internal data */
74: /* counter is going from 1 to 0, the internal data counter will be */
75: /* set to 0 (=256) instead of being reloaded with the original */
76: /* data value. In case no new value is written to the data reg, */
77: /* this means a write > 0 to the control reg will restart the timer*/
78: /* with a counter of 256 ! (fix timer saving routine used by */
79: /* ST Cnx in the Punish Your Machine and the Froggies Over The */
80: /* Fence (although this routine is in fact buggy)). */
81: /* 2008/09/13 [NP] Add some traces when stopping a timer and changing data reg. */
82: /* Don't apply timer D patch if timer D ctrl reg is 0. */
83: /* 2008/10/04 [NP] In MFP_TimerBData_ReadByte, test for overlap only when nHBL */
84: /* is between nStartHBL and nEndHBL (fix Wolfenstein 3D intro). */
85: /* In event count mode for timer A and B, set data reg to 255 when */
86: /* data reg was 0 (which in fact means 256). */
87: /* 2008/10/16 [NP] No need to set data reg to 255 when decrementing a data reg that*/
88: /* was 0, this is already what is implicitly done, because data */
89: /* reg for timer A/B is Uint8 (revert 2008/10/04 changes). */
1.1.1.13! root 90: /* 2008/12/11 [NP] In MFP_CheckPendingInterrupts(), returns TRUE or FALSE instead */
! 91: /* of void, depending on whether at least one MFP interrupt was */
! 92: /* allowed or not. */
1.1.1.11 root 93:
1.1.1.12 root 94:
1.1.1.13! root 95: const char MFP_fileid[] = "Hatari mfp.c : " __DATE__ " " __TIME__;
1.1 root 96:
97: #include "main.h"
1.1.1.8 root 98: #include "configuration.h"
1.1.1.9 root 99: #include "dmaSnd.h"
1.1 root 100: #include "fdc.h"
101: #include "ikbd.h"
102: #include "int.h"
1.1.1.8 root 103: #include "ioMem.h"
1.1.1.9 root 104: #include "joy.h"
1.1 root 105: #include "m68000.h"
106: #include "memorySnapShot.h"
107: #include "mfp.h"
108: #include "psg.h"
1.1.1.8 root 109: #include "rs232.h"
1.1 root 110: #include "sound.h"
1.1.1.12 root 111: #include "stMemory.h"
1.1.1.8 root 112: #include "tos.h"
1.1.1.13! root 113: #include "vdi.h"
1.1 root 114: #include "video.h"
1.1.1.3 root 115:
1.1 root 116:
117: /*
118: MFP interrupt channel circuit:-
119:
120: EdgeRegister EnableRegister MaskRegister SBit
121: | | | |
122: | | | | ------------------------
123: | | ------------------------ ---\ |---\ | |
124: | o--\ | | AND---o----------------AND---| S InterruptInService |
125: ---\ | AND---| S InterruptPending O |-------/ | |---/ | |
126: XOR----------)--/ | R | | | ------------------------
127: Input -----/ | ------------------------ | |
128: | | InterruptRequest |
129: NOT OR |
130: | | | |
131: -------------------- --------------------------------------o--- PassVector
132: */
133:
1.1.1.7 root 134:
135: /*-----------------------------------------------------------------------*/
1.1 root 136:
1.1.1.2 root 137: /* MFP Registers */
1.1.1.9 root 138: Uint8 MFP_GPIP; /* General Purpose Pins */
1.1.1.11 root 139: Uint8 MFP_VR; /* Vector Register 0xfffa17 */
1.1.1.9 root 140: Uint8 MFP_IERA,MFP_IERB; /* Interrupt Enable Registers A,B 0xfffa07,0xfffa09 */
141: Uint8 MFP_IPRA,MFP_IPRB; /* Interrupt Pending Registers A,B 0xfffa0b,0xfffa0d */
1.1.1.11 root 142: Uint8 MFP_TACR,MFP_TBCR; /* Timer A,B Control Registers */
1.1.1.10 root 143:
1.1.1.11 root 144: static Uint8 MFP_TCDCR; /* C+D Control Registers */
1.1.1.10 root 145: static Uint8 MFP_AER,MFP_DDR; /* Active Edge Register, Data Direction Register */
146: static Uint8 MFP_ISRA,MFP_ISRB; /* Interrupt In-Service Registers A,B 0xfffa0f,0xfffa11 */
147: static Uint8 MFP_IMRA,MFP_IMRB; /* Interrupt Mask Registers A,B 0xfffa13,0xfffa15 */
148: static Uint8 MFP_TADR,MFP_TBDR; /* Timer A,B Data Registers */
149: static Uint8 MFP_TCDR,MFP_TDDR; /* Timer C,D Data Registers */
150: static Uint8 MFP_TA_MAINCOUNTER; /* Timer A Main Counter (internal to MFP) */
151: static Uint8 MFP_TB_MAINCOUNTER; /* Timer B Main Counter */
152: static Uint8 MFP_TC_MAINCOUNTER; /* Timer C Main Counter (these are temp's, set when read as) */
153: static Uint8 MFP_TD_MAINCOUNTER; /* Timer D Main Counter (as done via interrupts) */
1.1 root 154:
155: /* CPU clock cycle counts for each timer */
1.1.1.7 root 156: static int TimerAClockCycles=0;
157: static int TimerBClockCycles=0;
158: static int TimerCClockCycles=0;
159: static int TimerDClockCycles=0;
160:
1.1.1.11 root 161: /* If a timer is stopped then restarted later without writing to the data register, */
162: /* we must resume the timer from where we left in the interrupts table, instead of */
163: /* computing a new number of clock cycles to restart the interrupt. */
1.1.1.12 root 164: static bool TimerACanResume = FALSE;
165: static bool TimerBCanResume = FALSE;
166: static bool TimerCCanResume = FALSE;
167: static bool TimerDCanResume = FALSE;
1.1.1.11 root 168:
1.1.1.12 root 169: bool bAppliedTimerDPatch; /* TRUE if the Timer-D patch has been applied */
1.1.1.9 root 170: static int nTimerDFakeValue; /* Faked Timer-D data register for the Timer-D patch */
1.1.1.8 root 171:
1.1.1.11 root 172: static int PendingCyclesOver = 0; /* >= 0 value, used to "loop" a timer when data counter reaches 0 */
1.1 root 173:
1.1.1.11 root 174: static const Uint16 MFPDiv[] =
175: {
176: 0,
177: 4,
178: 10,
179: 16,
180: 50,
181: 64,
182: 100,
183: 200
1.1 root 184: };
185:
1.1.1.11 root 186: /* Convert data/ctrl register to a number of mfp cycles */
187: #define MFP_REG_TO_CYCLES(data,ctrl) ( data * MFPDiv[ ctrl&0x7 ] )
188: /* Determine the data register corresponding to a number of mfp cycles/ctrl register */
189: /* (we round to the closest higher integer) */
190: #define MFP_CYCLE_TO_REG(cyc,ctrl) ( ( cyc + MFPDiv[ ctrl&0x7 ] - 1 ) / MFPDiv[ ctrl&0x7 ] )
191: //#define MFP_CYCLE_TO_REG(cyc,ctrl) ( cyc / MFPDiv[ ctrl&0x7 ] )
192:
1.1 root 193:
1.1.1.2 root 194: /*-----------------------------------------------------------------------*/
1.1.1.11 root 195: /**
196: * Reset all MFP variables and start interrupts on their way!
197: */
1.1 root 198: void MFP_Reset(void)
199: {
1.1.1.11 root 200: /* Reset MFP internal variables */
1.1.1.7 root 201:
1.1.1.11 root 202: bAppliedTimerDPatch = FALSE;
1.1.1.7 root 203:
1.1.1.11 root 204: MFP_GPIP = 0xff;
205: MFP_AER = MFP_DDR = 0;
206: MFP_IERA = MFP_IERB = 0;
207: MFP_IPRA = MFP_IPRB = 0;
208: MFP_ISRA = MFP_ISRB = 0;
209: MFP_IMRA = MFP_IMRB = 0;
210: MFP_VR = 0;
211: MFP_TACR = MFP_TBCR = MFP_TCDCR = 0;
212: MFP_TADR = MFP_TBDR = 0;
213: MFP_TCDR = MFP_TDDR = 0;
214: MFP_TA_MAINCOUNTER = MFP_TB_MAINCOUNTER = 0;
215: MFP_TC_MAINCOUNTER = MFP_TD_MAINCOUNTER = 0;
1.1 root 216:
1.1.1.11 root 217: /* Clear counters */
218: TimerAClockCycles = TimerBClockCycles = 0;
219: TimerCClockCycles = TimerDClockCycles = 0;
1.1 root 220: }
221:
1.1.1.2 root 222:
223: /*-----------------------------------------------------------------------*/
1.1.1.11 root 224: /**
225: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
226: */
1.1.1.12 root 227: void MFP_MemorySnapShot_Capture(bool bSave)
1.1 root 228: {
1.1.1.11 root 229: /* Save/Restore details */
230: MemorySnapShot_Store(&MFP_GPIP, sizeof(MFP_GPIP));
231: MemorySnapShot_Store(&MFP_AER, sizeof(MFP_AER));
232: MemorySnapShot_Store(&MFP_DDR, sizeof(MFP_DDR));
233: MemorySnapShot_Store(&MFP_IERA, sizeof(MFP_IERA));
234: MemorySnapShot_Store(&MFP_IERB, sizeof(MFP_IERB));
235: MemorySnapShot_Store(&MFP_IPRA, sizeof(MFP_IPRA));
236: MemorySnapShot_Store(&MFP_IPRB, sizeof(MFP_IPRB));
237: MemorySnapShot_Store(&MFP_ISRA, sizeof(MFP_ISRA));
238: MemorySnapShot_Store(&MFP_ISRB, sizeof(MFP_ISRB));
239: MemorySnapShot_Store(&MFP_IMRA, sizeof(MFP_IMRA));
240: MemorySnapShot_Store(&MFP_IMRB, sizeof(MFP_IMRB));
241: MemorySnapShot_Store(&MFP_VR, sizeof(MFP_VR));
242: MemorySnapShot_Store(&MFP_TACR, sizeof(MFP_TACR));
243: MemorySnapShot_Store(&MFP_TBCR, sizeof(MFP_TBCR));
244: MemorySnapShot_Store(&MFP_TCDCR, sizeof(MFP_TCDCR));
245: MemorySnapShot_Store(&MFP_TADR, sizeof(MFP_TADR));
246: MemorySnapShot_Store(&MFP_TBDR, sizeof(MFP_TBDR));
247: MemorySnapShot_Store(&MFP_TCDR, sizeof(MFP_TCDR));
248: MemorySnapShot_Store(&MFP_TDDR, sizeof(MFP_TDDR));
249: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER, sizeof(MFP_TA_MAINCOUNTER));
250: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER, sizeof(MFP_TB_MAINCOUNTER));
251: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER, sizeof(MFP_TC_MAINCOUNTER));
252: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER, sizeof(MFP_TD_MAINCOUNTER));
253: MemorySnapShot_Store(&TimerAClockCycles, sizeof(TimerAClockCycles));
254: MemorySnapShot_Store(&TimerBClockCycles, sizeof(TimerBClockCycles));
255: MemorySnapShot_Store(&TimerCClockCycles, sizeof(TimerCClockCycles));
256: MemorySnapShot_Store(&TimerDClockCycles, sizeof(TimerDClockCycles));
257: MemorySnapShot_Store(&TimerACanResume, sizeof(TimerACanResume));
258: MemorySnapShot_Store(&TimerBCanResume, sizeof(TimerBCanResume));
259: MemorySnapShot_Store(&TimerCCanResume, sizeof(TimerCCanResume));
260: MemorySnapShot_Store(&TimerDCanResume, sizeof(TimerDCanResume));
1.1 root 261: }
262:
1.1.1.2 root 263:
264: /*-----------------------------------------------------------------------*/
1.1.1.11 root 265: /**
266: * Call MFP interrupt - NOTE when the MFP is in Auto interrupt (AEI), the MFP
267: * puts the interrupt number on the data bus and then the 68000 reads it, multiplies
268: * it by 4 and adds in a base(usually 0x100) to give the vector. Some programs
269: * change this offset, eg RoboCod. This offset is stored in the top 4 bits of register
270: * 0xfffa17(0x40 is the default=0x100)
271: * Many thanks to Steve Bak for that one!
272: */
1.1.1.7 root 273: static void MFP_Exception(int Interrupt)
1.1 root 274: {
1.1.1.11 root 275: unsigned int Vec;
1.1 root 276:
1.1.1.11 root 277: Vec = (unsigned int)(MFP_VR&0xf0)<<2;
278: Vec += Interrupt<<2;
279:
280: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_EXCEPTION ) )
281: {
1.1.1.12 root 282: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.11 root 283: int nLineCycles = nFrameCycles % nCyclesPerLine;
284: HATARI_TRACE_PRINT ( "mfp excep int=%d vec=0x%x new_pc=0x%x video_cyc=%d %d@%d\n" ,
1.1.1.12 root 285: Interrupt, Vec, STMemory_ReadLong ( Vec ), nFrameCycles, nLineCycles, nHBL );
1.1.1.11 root 286: }
287:
1.1.1.12 root 288: M68000_Exception ( Vec , M68000_EXCEPTION_SRC_INT_MFP );
1.1 root 289: }
290:
1.1.1.2 root 291:
292: /*-----------------------------------------------------------------------*/
1.1.1.11 root 293: /**
294: * This is called whenever the MFP_IPRA or MFP_IPRB registers are modified.
295: * We set the special flag SPCFLAG_MFP accordingly (to say if an MFP interrupt
296: * is to be checked) so we only have one compare during the decode
297: * instruction loop.
298: */
1.1.1.10 root 299: static void MFP_UpdateFlags(void)
300: {
1.1.1.11 root 301: if (MFP_IPRA|MFP_IPRB)
302: {
303: M68000_SetSpecial(SPCFLAG_MFP);
304: }
305: else
306: {
307: M68000_UnsetSpecial(SPCFLAG_MFP);
308: }
1.1.1.10 root 309: }
310:
311:
312: /*-----------------------------------------------------------------------*/
1.1.1.11 root 313: /**
314: * Test interrupt request to see if can cause exception,return TRUE if pass vector
315: */
1.1.1.12 root 316: static bool MFP_InterruptRequest(int nMfpException, Uint8 Bit, Uint8 *pPendingReg, Uint8 MaskRegister,
1.1.1.9 root 317: Uint8 PriorityMaskLow, Uint8 PriorityMaskHigh, Uint8 *pInServiceReg)
1.1 root 318: {
1.1.1.11 root 319: /* Are any higher priority interupts in service? */
320: if (((MFP_ISRA&PriorityMaskLow) == 0) && ((MFP_ISRB&PriorityMaskHigh) == 0))
321: {
322: /* Is masked? */
323: if (MaskRegister&Bit)
324: {
325: /* CPU allows interrupt of an MFP level? */
326: if (6 > FIND_IPL)
327: {
328: *pPendingReg &= ~Bit; /* Clear pending bit */
329: MFP_UpdateFlags();
330:
331: /* Are we in 'auto' interrupt or 'manual'? */
332: if (MFP_VR&0x08) /* Software End-of-Interrupt (SEI) */
333: *pInServiceReg |= Bit; /* Set interrupt in service register */
334: else
335: *pInServiceReg &= ~Bit; /* Clear interrupt in service register */
336:
337: /* Call interrupt, adds in base (default 0x100) */
338: MFP_Exception(nMfpException);
339: return TRUE;
340: }
341: }
342: }
1.1 root 343:
1.1.1.11 root 344: return FALSE;
1.1 root 345: }
346:
1.1.1.2 root 347:
348: /*-----------------------------------------------------------------------*/
1.1.1.11 root 349: /**
350: * Check 'pending' registers to see if any MFP interrupts need servicing.
351: * Request interrupt if necessary.
1.1.1.13! root 352: * Return TRUE if at least one MFP interrupt was allowed, else return FALSE.
1.1.1.11 root 353: */
1.1.1.13! root 354: bool MFP_CheckPendingInterrupts(void)
1.1 root 355: {
1.1.1.13! root 356: int InterruptPossible;
! 357:
! 358:
1.1.1.12 root 359: if ((MFP_IPRA & 0xb5) == 0 && (MFP_IPRB & 0xfb) == 0)
1.1.1.11 root 360: {
361: /* Should never get here, but if do just clear flag (see 'MFP_UpdateFlags') */
362: M68000_UnsetSpecial(SPCFLAG_MFP);
1.1.1.13! root 363: return FALSE;
1.1.1.11 root 364: }
1.1 root 365:
1.1.1.12 root 366:
1.1.1.13! root 367: InterruptPossible = FALSE;
! 368:
1.1.1.11 root 369: if (MFP_IPRA & MFP_TIMER_GPIP7_BIT) /* Check MFP GPIP7 interrupt (bit 7) */
1.1.1.13! root 370: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_GPIP7, MFP_TIMER_GPIP7_BIT, &MFP_IPRA, MFP_IMRA, 0x80, 0x00, &MFP_ISRA);
1.1.1.9 root 371:
1.1.1.11 root 372: if (MFP_IPRA & MFP_TIMER_A_BIT) /* Check Timer A (bit 5) */
1.1.1.13! root 373: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_TIMERA, MFP_TIMER_A_BIT, &MFP_IPRA, MFP_IMRA, 0xe0, 0x00, &MFP_ISRA);
1.1.1.2 root 374:
1.1.1.11 root 375: if (MFP_IPRA & MFP_RCVBUFFULL_BIT) /* Check Receive buffer full (bit 4) */
1.1.1.13! root 376: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_RECBUFFULL, MFP_RCVBUFFULL_BIT, &MFP_IPRA, MFP_IMRA, 0xf0, 0x00, &MFP_ISRA);
1.1.1.7 root 377:
1.1.1.11 root 378: if (MFP_IPRA & MFP_TRNBUFEMPTY_BIT) /* Check transmit buffer empty (bit 2) */
1.1.1.13! root 379: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_TRANSBUFFEMPTY, MFP_TRNBUFEMPTY_BIT, &MFP_IPRA, MFP_IMRA, 0xfc, 0x00, &MFP_ISRA);
1.1.1.7 root 380:
1.1.1.11 root 381: if (MFP_IPRA & MFP_TIMER_B_BIT) /* Check Timer B (bit 0) */
1.1.1.13! root 382: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_TIMERB, MFP_TIMER_B_BIT, &MFP_IPRA, MFP_IMRA, 0xff, 0x00, &MFP_ISRA);
1.1.1.7 root 383:
1.1.1.12 root 384:
1.1.1.11 root 385: if (MFP_IPRB & MFP_FDCHDC_BIT) /* Check FDC (bit 7) */
1.1.1.13! root 386: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_GPIP5, MFP_FDCHDC_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0x80, &MFP_ISRB);
1.1.1.7 root 387:
1.1.1.11 root 388: if (MFP_IPRB & MFP_ACIA_BIT) /* Check ACIA (Keyboard or MIDI) (bit 6) */
1.1.1.13! root 389: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_ACIA, MFP_ACIA_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xc0, &MFP_ISRB);
1.1 root 390:
1.1.1.11 root 391: if (MFP_IPRB & MFP_TIMER_C_BIT) /* Check Timer C (bit 5) */
1.1.1.13! root 392: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_TIMERC, MFP_TIMER_C_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xe0, &MFP_ISRB);
1.1 root 393:
1.1.1.11 root 394: if (MFP_IPRB & MFP_TIMER_D_BIT) /* Check Timer D (bit 4) */
1.1.1.13! root 395: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_TIMERD, MFP_TIMER_D_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xf0, &MFP_ISRB);
1.1.1.12 root 396:
397: if (MFP_IPRB & MFP_GPU_DONE_BIT) /* Check GPU done (bit 3) */
1.1.1.13! root 398: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_GPIP3, MFP_GPU_DONE_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xf8, &MFP_ISRB);
1.1.1.12 root 399:
400: if (MFP_IPRB & MFP_GPIP_1_BIT) /* Check (Falcon) Centronics ACK / (ST) RS232 DCD (bit 1) */
1.1.1.13! root 401: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_GPIP1, MFP_GPIP_1_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xfe, &MFP_ISRB);
1.1.1.12 root 402:
403: if (MFP_IPRB & MFP_GPIP_0_BIT) /* Check Centronics BUSY (bit 0) */
1.1.1.13! root 404: InterruptPossible |= MFP_InterruptRequest(MFP_EXCEPT_GPIP0, MFP_GPIP_0_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xff, &MFP_ISRB);
1.1.1.12 root 405:
1.1.1.13! root 406: return InterruptPossible;
1.1 root 407: }
408:
1.1.1.2 root 409:
410: /*-----------------------------------------------------------------------*/
1.1.1.11 root 411: /**
412: * Interrupt Channel is active, set pending bit so can be serviced
413: */
1.1.1.9 root 414: void MFP_InputOnChannel(Uint8 Bit, Uint8 EnableBit, Uint8 *pPendingReg)
1.1 root 415: {
1.1.1.11 root 416: /* Input has occurred on MFP channel, set interrupt pending to request interrupt when able */
417: if (EnableBit&Bit)
418: *pPendingReg |= Bit; /* Set bit */
419: else
420: *pPendingReg &= ~Bit; /* Clear bit */
421: MFP_UpdateFlags();
1.1 root 422: }
423:
1.1.1.2 root 424:
425: /*-----------------------------------------------------------------------*/
1.1.1.11 root 426: /**
427: * Generate Timer A Interrupt when in Event Count mode
428: */
1.1 root 429: void MFP_TimerA_EventCount_Interrupt(void)
430: {
1.1.1.12 root 431: if (MFP_TA_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */
1.1.1.11 root 432: {
1.1.1.12 root 433: MFP_TA_MAINCOUNTER = MFP_TADR; /* Reload timer from data register */
1.1 root 434:
1.1.1.11 root 435: /* Acknowledge in MFP circuit, pass bit,enable,pending */
436: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
437: }
438: else
1.1.1.12 root 439: {
440: MFP_TA_MAINCOUNTER--; /* Decrement timer main counter */
441: /* As MFP_TA_MAINCOUNTER is Uint8, when we decrement MFP_TA_MAINCOUNTER=0 */
442: /* we go to MFP_TA_MAINCOUNTER=255, which is the wanted behaviour because */
443: /* data reg = 0 means 256 in fact. So, the next 2 lines are redundant. */
444: /* if ( MFP_TA_MAINCOUNTER < 0 )
445: MFP_TA_MAINCOUNTER = 255;
446: */
447: }
1.1 root 448: }
449:
1.1.1.2 root 450:
451: /*-----------------------------------------------------------------------*/
1.1.1.11 root 452: /**
453: * Generate Timer B Interrupt when in Event Count mode
454: */
1.1 root 455: void MFP_TimerB_EventCount_Interrupt(void)
456: {
1.1.1.12 root 457: if (MFP_TB_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */
1.1.1.11 root 458: {
1.1.1.12 root 459: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Reload timer from data register */
1.1 root 460:
1.1.1.11 root 461: /* Acknowledge in MFP circuit, pass bit,enable,pending */
462: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
463: }
464: else
1.1.1.12 root 465: {
466: MFP_TB_MAINCOUNTER--; /* Decrement timer main counter */
467: /* As MFP_TB_MAINCOUNTER is Uint8, when we decrement MFP_TB_MAINCOUNTER=0 */
468: /* we go to MFP_TB_MAINCOUNTER=255, which is the wanted behaviour because */
469: /* data reg = 0 means 256 in fact. So, the next 2 lines are redundant. */
470: /* if ( MFP_TB_MAINCOUNTER < 0 )
471: MFP_TB_MAINCOUNTER = 255;
472: */
473: }
1.1 root 474: }
475:
1.1.1.2 root 476:
477: /*-----------------------------------------------------------------------*/
1.1.1.11 root 478: /**
479: * Start Timer A or B - EventCount mode is done in HBL handler to time correctly
480: */
481: static int MFP_StartTimer_AB(Uint8 TimerControl, Uint16 TimerData, int Handler,
1.1.1.12 root 482: bool bFirstTimer, bool *pTimerCanResume)
1.1 root 483: {
1.1.1.11 root 484: int TimerClockCycles = 0;
485:
486: /* Is timer in delay mode (ctrl = 0-7) ? */
487: /* If we are in event-count mode (ctrl = 8) ignore this (done on HBL) */
488: if (TimerControl <= 7)
489: {
490: /* Find number of CPU cycles for when timer is due (include preset
491: * and counter). As timer occurs very often we multiply by counter
492: * to speed up emulator */
493: if (TimerData == 0) /* Data=0 is actually Data=256 */
494: TimerData = 256;
495: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl );
496:
497: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
498: {
499: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
500: int nLineCycles = nFrameCycles % nCyclesPerLine;
501: HATARI_TRACE_PRINT ( "mfp start AB handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
502: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
503: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
504: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
505: }
506:
507: /* And add to our internal interrupt list, if timer cycles is zero
508: * then timer is stopped */
509: Int_RemovePendingInterrupt(Handler);
510: if (TimerClockCycles)
511: {
512: if ( ( *pTimerCanResume == TRUE ) && ( bFirstTimer == TRUE ) ) /* we can't resume if the timer is auto restarting after an interrupt */
513: {
514: Int_ResumeStoppedInterrupt ( Handler );
515: }
516: else
517: {
518: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE );
519:
520: /* Start timer from now? If not continue timer using PendingCycleOver */
521: if (bFirstTimer)
1.1.1.12 root 522: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles);
1.1.1.11 root 523: else
524: {
525: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE );
526:
527: /* In case we miss more than one int, we must correct the delay for the next one */
528: if ( PendingCyclesOver > TimerClockCyclesInternal )
529: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal;
530:
531: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver);
532: }
1.1 root 533:
1.1.1.11 root 534: *pTimerCanResume = TRUE; /* timer was set, resume is possible if stop/start it later */
535: }
536: }
1.1.1.12 root 537:
538: else /* Ctrl was 0 -> timer is stopped */
539: {
540: /* do nothing, only print some traces */
541: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
542: {
543: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
544: int nLineCycles = nFrameCycles % nCyclesPerLine;
545: HATARI_TRACE_PRINT ( "mfp stop AB handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
546: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
547: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
548: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
549: }
550: }
1.1.1.11 root 551: }
1.1.1.12 root 552:
553: else /* timer control > 7 */
1.1.1.11 root 554: {
555: /* Make sure no outstanding interrupts in list if channel is disabled */
556: Int_RemovePendingInterrupt(Handler);
557: }
1.1 root 558:
1.1.1.12 root 559: if (TimerControl == 8 ) /* event count mode */
560: {
561: /* do nothing, only print some traces */
562:
563: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
564: {
565: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
566: int nLineCycles = nFrameCycles % nCyclesPerLine;
567: HATARI_TRACE_PRINT ( "mfp start AB handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
568: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
569: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
570: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
571: }
572:
573:
574: }
575:
1.1.1.11 root 576: return TimerClockCycles;
1.1 root 577: }
578:
1.1.1.2 root 579:
580: /*-----------------------------------------------------------------------*/
1.1.1.11 root 581: /**
582: * Start Timer C or D
583: */
584: static int MFP_StartTimer_CD(Uint8 TimerControl, Uint16 TimerData, int Handler,
1.1.1.12 root 585: bool bFirstTimer, bool *pTimerCanResume)
1.1 root 586: {
1.1.1.11 root 587: int TimerClockCycles = 0;
1.1 root 588:
1.1.1.11 root 589: /* Is timer in delay mode ? */
590: if ((TimerControl&0x7) != 0)
591: {
592: /* Find number of cycles for when timer is due (include preset and
593: * counter). As timer occurs very often we multiply by counter to
594: * speed up emulator */
595: if (TimerData == 0) /* Data=0 is actually Data=256 */
596: TimerData = 256;
597: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl );
598:
599: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
600: {
601: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
602: int nLineCycles = nFrameCycles % nCyclesPerLine;
603: HATARI_TRACE_PRINT ( "mfp start CD handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
604: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
605: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
606: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
607: }
608:
609: /* And add to our internal interrupt list, if timer cycles is zero
610: * then timer is stopped */
611: Int_RemovePendingInterrupt(Handler);
612: if (TimerClockCycles)
613: {
614: if ( ( *pTimerCanResume == TRUE ) && ( bFirstTimer == TRUE ) ) /* we can't resume if the timer is auto restarting after an interrupt */
615: {
616: Int_ResumeStoppedInterrupt ( Handler );
617: }
618: else
619: {
620: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE );
621:
622: /* Start timer from now? If not continue timer using PendingCycleOver */
623: if (bFirstTimer)
1.1.1.12 root 624: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles);
1.1.1.11 root 625: else
626: {
627: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE );
628:
629: /* In case we miss more than one int, we must correct the delay for the next one */
630: if ( PendingCyclesOver > TimerClockCyclesInternal )
631: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal;
632:
633: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver);
634: }
635:
636: *pTimerCanResume = TRUE; /* timer was set, resume is possible if stop/start it later */
637: }
638: }
639: }
1.1.1.12 root 640:
641: else /* timer control is 0 */
1.1.1.11 root 642: {
1.1.1.12 root 643: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
644: {
645: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
646: int nLineCycles = nFrameCycles % nCyclesPerLine;
647: HATARI_TRACE_PRINT ( "mfp stop CD handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
648: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
649: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
650: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
651: }
652:
1.1.1.11 root 653: /* Make sure no outstanding interrupts in list if channel is disabled */
654: Int_RemovePendingInterrupt(Handler);
655: }
1.1 root 656:
1.1.1.11 root 657: return TimerClockCycles;
1.1 root 658: }
659:
1.1.1.2 root 660:
661: /*-----------------------------------------------------------------------*/
1.1.1.11 root 662: /**
663: * Read Timer A or B - If in EventCount MainCounter already has correct value
664: */
1.1.1.12 root 665: static Uint8 MFP_ReadTimer_AB(Uint8 TimerControl, Uint8 MainCounter, int TimerCycles, int Handler, bool TimerIsStopping)
1.1 root 666: {
1.1.1.12 root 667: // int TimerCyclesPassed;
1.1 root 668:
1.1.1.11 root 669: /* Find TimerAB count, if no interrupt or not in delay mode assume
670: * in Event Count mode so already up-to-date as kept by HBL */
671: if (Int_InterruptActive(Handler) && (TimerControl > 0) && (TimerControl <= 7))
672: {
673: /* Find cycles passed since last interrupt */
1.1.1.12 root 674: //TimerCyclesPassed = TimerCycles - Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE );
1.1.1.11 root 675: MainCounter = MFP_CYCLE_TO_REG ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl );
676: //fprintf ( stderr , "mfp read AB passed %d count %d\n" , TimerCyclesPassed, MainCounter );
677: }
678:
1.1.1.12 root 679: /* If the timer is stopped when the internal mfp data reg is already < 1 */
680: /* then the data reg will be 0 (=256) next time the timer will be restarted */
681: /* if no write is made to the data reg before */
682: if ( TimerIsStopping )
683: {
684: if ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ) < MFP_REG_TO_CYCLES ( 1 , TimerControl ) )
685: {
686: MainCounter = 0; /* internal mfp counter becomes 0 (=256) */
687: HATARI_TRACE ( HATARI_TRACE_MFP_READ , "mfp read AB handler=%d stopping timer while data reg between 1 and 0 : forcing data to 256\n" ,
688: Handler );
689: }
690: }
691:
1.1.1.11 root 692: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_READ ) )
693: {
694: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
695: int nLineCycles = nFrameCycles % nCyclesPerLine;
696: HATARI_TRACE_PRINT ( "mfp read AB handler=%d data=%d ctrl=%d timer_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" ,
697: Handler, MainCounter, TimerControl, TimerCycles,
698: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
699: }
1.1.1.6 root 700:
1.1.1.11 root 701: return MainCounter;
1.1 root 702: }
703:
1.1.1.2 root 704:
705: /*-----------------------------------------------------------------------*/
1.1.1.11 root 706: /**
707: * Read Timer C or D
708: */
1.1.1.12 root 709: static Uint8 MFP_ReadTimerCD(Uint8 TimerControl, Uint8 TimerData, Uint8 MainCounter, int TimerCycles, int Handler, bool TimerIsStopping)
1.1 root 710: {
1.1.1.12 root 711: // int TimerCyclesPassed;
1.1 root 712:
1.1.1.11 root 713: /* Find TimerCD count. If timer is off, MainCounter already contains
714: * the latest value */
715: if (Int_InterruptActive(Handler))
716: {
717: /* Find cycles passed since last interrupt */
1.1.1.12 root 718: //TimerCyclesPassed = TimerCycles - Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE );
1.1.1.11 root 719: MainCounter = MFP_CYCLE_TO_REG ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl);
720: //fprintf ( stderr , "mfp read CD passed %d count %d\n" , TimerCyclesPassed, MainCounter );
721: }
722:
1.1.1.12 root 723: /* If the timer is stopped when the internal mfp data reg is already < 1 */
724: /* then the data reg will be 0 (=256) next time the timer will be restarted */
725: /* if no write is made to the data reg before */
726: if ( TimerIsStopping )
727: {
728: if ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ) < MFP_REG_TO_CYCLES ( 1 , TimerControl ) )
729: {
730: MainCounter = 0; /* internal mfp counter becomes 0 (=256) */
731: HATARI_TRACE ( HATARI_TRACE_MFP_READ , "mfp read CD handler=%d stopping timer while data reg between 1 and 0 : forcing data to 256\n" ,
732: Handler );
733: }
734: }
735:
1.1.1.11 root 736: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_READ ) )
737: {
738: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
739: int nLineCycles = nFrameCycles % nCyclesPerLine;
740: HATARI_TRACE_PRINT ( "mfp read CD handler=%d data=%d ctrl=%d timer_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" ,
741: Handler, MainCounter, TimerControl, TimerCycles,
742: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
743: }
1.1 root 744:
1.1.1.11 root 745: return MainCounter;
1.1 root 746: }
747:
1.1.1.2 root 748:
749: /*-----------------------------------------------------------------------*/
1.1.1.11 root 750: /**
751: * Start Timer A
752: */
1.1.1.10 root 753: static void MFP_StartTimerA(void)
1.1 root 754: {
1.1.1.11 root 755: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER,
756: INTERRUPT_MFP_TIMERA, TRUE, &TimerACanResume);
1.1 root 757: }
758:
759:
1.1.1.2 root 760: /*-----------------------------------------------------------------------*/
1.1.1.11 root 761: /**
762: * Read Timer A
763: */
1.1.1.12 root 764: static void MFP_ReadTimerA(bool TimerIsStopping)
1.1 root 765: {
1.1.1.11 root 766: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER,
1.1.1.12 root 767: TimerAClockCycles, INTERRUPT_MFP_TIMERA, TimerIsStopping);
1.1 root 768: }
769:
770:
1.1.1.2 root 771: /*-----------------------------------------------------------------------*/
1.1.1.11 root 772: /**
773: * Start Timer B
774: * (This does not start the EventCount mode time as this is taken care
775: * of by the HBL)
776: */
1.1.1.10 root 777: static void MFP_StartTimerB(void)
1.1 root 778: {
1.1.1.11 root 779: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER,
780: INTERRUPT_MFP_TIMERB, TRUE, &TimerBCanResume);
1.1 root 781: }
782:
783:
1.1.1.2 root 784: /*-----------------------------------------------------------------------*/
1.1.1.11 root 785: /**
786: * Read Timer B
787: */
1.1.1.12 root 788: static void MFP_ReadTimerB(bool TimerIsStopping)
1.1 root 789: {
1.1.1.11 root 790: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER,
1.1.1.12 root 791: TimerBClockCycles, INTERRUPT_MFP_TIMERB, TimerIsStopping);
1.1 root 792: }
793:
794:
1.1.1.2 root 795: /*-----------------------------------------------------------------------*/
1.1.1.11 root 796: /**
797: * Start Timer C
798: */
1.1.1.10 root 799: static void MFP_StartTimerC(void)
1.1 root 800: {
1.1.1.11 root 801: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TC_MAINCOUNTER,
802: INTERRUPT_MFP_TIMERC , TRUE, &TimerCCanResume);
1.1 root 803: }
804:
805:
1.1.1.2 root 806: /*-----------------------------------------------------------------------*/
1.1.1.11 root 807: /**
808: * Read Timer C
809: */
1.1.1.12 root 810: static void MFP_ReadTimerC(bool TimerIsStopping)
1.1 root 811: {
1.1.1.11 root 812: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD((MFP_TCDCR>>4)&7, MFP_TCDR, MFP_TC_MAINCOUNTER,
1.1.1.12 root 813: TimerCClockCycles, INTERRUPT_MFP_TIMERC, TimerIsStopping);
1.1 root 814: }
815:
816:
1.1.1.2 root 817: /*-----------------------------------------------------------------------*/
1.1.1.11 root 818: /**
819: * Start Timer D
820: */
1.1.1.10 root 821: static void MFP_StartTimerD(void)
1.1 root 822: {
1.1.1.11 root 823: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TD_MAINCOUNTER,
824: INTERRUPT_MFP_TIMERD, TRUE, &TimerDCanResume);
1.1 root 825: }
826:
827:
1.1.1.2 root 828: /*-----------------------------------------------------------------------*/
1.1.1.11 root 829: /**
830: * Read Timer D
831: */
1.1.1.12 root 832: static void MFP_ReadTimerD(bool TimerIsStopping)
1.1 root 833: {
1.1.1.11 root 834: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR&7, MFP_TDDR, MFP_TD_MAINCOUNTER,
1.1.1.12 root 835: TimerDClockCycles, INTERRUPT_MFP_TIMERD, TimerIsStopping);
1.1 root 836: }
837:
838:
1.1.1.2 root 839: /*-----------------------------------------------------------------------*/
1.1.1.11 root 840: /**
841: * Handle Timer A Interrupt
842: */
1.1 root 843: void MFP_InterruptHandler_TimerA(void)
844: {
1.1.1.11 root 845: /* Number of internal cycles we went over for this timer ( <= 0 ),
846: * used when timer expires and needs to be restarted */
847: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
848:
849: /* Remove this interrupt from list and re-order */
850: Int_AcknowledgeInterrupt();
1.1 root 851:
1.1.1.11 root 852: /* Acknowledge in MFP circuit, pass bit,enable,pending */
853: if ((MFP_TACR&0xf) != 0) /* Is timer OK? */
854: MFP_InputOnChannel(MFP_TIMER_A_BIT, MFP_IERA, &MFP_IPRA);
1.1 root 855:
1.1.1.11 root 856: /* Start next interrupt, if need one - from current cycle count */
857: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TADR, INTERRUPT_MFP_TIMERA, FALSE, &TimerACanResume);
1.1 root 858: }
859:
860:
1.1.1.2 root 861: /*-----------------------------------------------------------------------*/
1.1.1.11 root 862: /**
863: * Handle Timer B Interrupt
864: */
1.1 root 865: void MFP_InterruptHandler_TimerB(void)
866: {
1.1.1.11 root 867: /* Number of internal cycles we went over for this timer ( <= 0 ),
868: * used when timer expires and needs to be restarted */
869: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
870:
871: /* Remove this interrupt from list and re-order */
872: Int_AcknowledgeInterrupt();
1.1 root 873:
1.1.1.11 root 874: /* Acknowledge in MFP circuit, pass bit, enable, pending */
875: if ((MFP_TBCR&0xf) != 0) /* Is timer OK? */
876: MFP_InputOnChannel(MFP_TIMER_B_BIT, MFP_IERA, &MFP_IPRA);
1.1 root 877:
1.1.1.11 root 878: /* Start next interrupt, if need one - from current cycle count */
879: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TBDR, INTERRUPT_MFP_TIMERB, FALSE, &TimerBCanResume);
1.1 root 880: }
881:
882:
1.1.1.2 root 883: /*-----------------------------------------------------------------------*/
1.1.1.11 root 884: /**
885: * Handle Timer C Interrupt
886: */
1.1 root 887: void MFP_InterruptHandler_TimerC(void)
888: {
1.1.1.11 root 889: /* Number of internal cycles we went over for this timer ( <= 0 ),
890: * used when timer expires and needs to be restarted */
891: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
1.1 root 892:
1.1.1.11 root 893: /* Remove this interrupt from list and re-order */
894: Int_AcknowledgeInterrupt();
1.1 root 895:
1.1.1.11 root 896: /* Acknowledge in MFP circuit, pass bit, enable, pending */
897: if ((MFP_TCDCR&0x70) != 0) /* Is timer OK? */
898: MFP_InputOnChannel(MFP_TIMER_C_BIT, MFP_IERB, &MFP_IPRB);
899:
900: /* Start next interrupt, if need one - from current cycle count */
901: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TCDR, INTERRUPT_MFP_TIMERC, FALSE, &TimerCCanResume);
1.1 root 902: }
903:
904:
1.1.1.2 root 905: /*-----------------------------------------------------------------------*/
1.1.1.11 root 906: /**
907: * Handle Timer D Interrupt
908: */
1.1 root 909: void MFP_InterruptHandler_TimerD(void)
910: {
1.1.1.11 root 911: /* Number of internal cycles we went over for this timer ( <= 0 ),
912: * used when timer expires and needs to be restarted */
913: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
914:
915: /* Remove this interrupt from list and re-order */
916: Int_AcknowledgeInterrupt();
917:
918: /* Acknowledge in MFP circuit, pass bit, enable, pending */
919: if ((MFP_TCDCR&0x07) != 0) /* Is timer OK? */
920: MFP_InputOnChannel(MFP_TIMER_D_BIT, MFP_IERB, &MFP_IPRB);
921:
922: /* Start next interrupt, if need one - from current cycle count */
923: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TDDR, INTERRUPT_MFP_TIMERD, FALSE, &TimerDCanResume);
1.1 root 924: }
925:
1.1.1.8 root 926:
927:
928: /*-----------------------------------------------------------------------*/
1.1.1.11 root 929: /**
930: * Handle read from GPIP pins register (0xfffa01).
931: *
932: * - Bit 0 is the BUSY signal of the printer port, it is SET if no printer
933: * is connected or on BUSY. Therefor we should assume it to be 0 in Hatari
934: * when a printer is emulated.
935: * - Bit 1 is used for RS232: DCD
936: * - Bit 2 is used for RS232: CTS
937: * - Bit 3 is used by the blitter for signalling when its done.
938: * - Bit 4 is used by the ACIAs.
939: * - Bit 5 is used by the floppy controller / ACSI DMA
940: * - Bit 6 is used for RS232: RI
941: * - Bit 7 is monochrome monitor detection signal. On STE it is also XORed with
942: * the DMA sound play bit.
943: */
1.1.1.8 root 944: void MFP_GPIP_ReadByte(void)
945: {
1.1.1.10 root 946: M68000_WaitState(4);
947:
1.1.1.8 root 948: if (!bUseHighRes)
1.1.1.11 root 949: MFP_GPIP |= 0x80; /* Color monitor -> set top bit */
1.1.1.9 root 950: else
951: MFP_GPIP &= ~0x80;
952: if (nDmaSoundControl & DMASNDCTRL_PLAY)
1.1.1.11 root 953: MFP_GPIP ^= 0x80; /* Top bit is XORed with DMA sound control play bit */
1.1.1.9 root 954:
955: if (ConfigureParams.Printer.bEnablePrinting)
956: {
957: /* Signal that printer is not busy */
958: MFP_GPIP &= ~1;
959: }
960: else
961: {
962: MFP_GPIP |= 1;
963:
964: /* Printer BUSY bit is also used by parallel port joystick adapters as fire button */
965: if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT1].nJoystickMode != JOYSTICK_DISABLED)
966: {
967: /* Fire pressed? */
968: if (Joy_GetStickData(JOYID_PARPORT1) & 0x80)
969: MFP_GPIP &= ~1;
970: }
971: }
1.1.1.8 root 972:
1.1.1.10 root 973: FDC_GpipRead();
974:
1.1.1.9 root 975: IoMem[0xfffa01] = MFP_GPIP;
1.1.1.13! root 976:
! 977: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_READ ) )
! 978: {
! 979: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
! 980: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 981: HATARI_TRACE_PRINT ( "mfp read gpip fa01=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
! 982: MFP_GPIP, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
! 983: }
1.1.1.8 root 984: }
985:
986: /*-----------------------------------------------------------------------*/
1.1.1.11 root 987: /**
988: * Handle read from active edge register (0xfffa03).
989: */
1.1.1.8 root 990: void MFP_ActiveEdge_ReadByte(void)
991: {
1.1.1.10 root 992: M68000_WaitState(4);
993:
1.1.1.8 root 994: IoMem[0xfffa03] = MFP_AER;
995: }
996:
997: /*-----------------------------------------------------------------------*/
1.1.1.11 root 998: /**
999: * Handle read from data direction register (0xfffa05).
1000: */
1.1.1.8 root 1001: void MFP_DataDirection_ReadByte(void)
1002: {
1.1.1.10 root 1003: M68000_WaitState(4);
1004:
1.1.1.8 root 1005: IoMem[0xfffa05] = MFP_DDR;
1006: }
1007:
1008: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1009: /**
1010: * Handle read from interupt enable register A (0xfffa07).
1011: */
1.1.1.8 root 1012: void MFP_EnableA_ReadByte(void)
1013: {
1.1.1.10 root 1014: M68000_WaitState(4);
1015:
1.1.1.8 root 1016: IoMem[0xfffa07] = MFP_IERA;
1017: }
1018:
1019: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1020: /**
1021: * Handle read from interupt enable register B (0xfffa09).
1022: */
1.1.1.8 root 1023: void MFP_EnableB_ReadByte(void)
1024: {
1.1.1.10 root 1025: M68000_WaitState(4);
1026:
1.1.1.8 root 1027: IoMem[0xfffa09] = MFP_IERB;
1028: }
1029:
1030: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1031: /**
1032: * Handle read from interupt pending register A (0xfffa0b).
1033: */
1.1.1.8 root 1034: void MFP_PendingA_ReadByte(void)
1035: {
1.1.1.10 root 1036: M68000_WaitState(4);
1037:
1.1.1.8 root 1038: IoMem[0xfffa0b] = MFP_IPRA;
1039: }
1040:
1041: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1042: /**
1043: * Handle read from interupt pending register A (0xfffa0d).
1044: */
1.1.1.8 root 1045: void MFP_PendingB_ReadByte(void)
1046: {
1.1.1.10 root 1047: M68000_WaitState(4);
1048:
1.1.1.8 root 1049: IoMem[0xfffa0d] = MFP_IPRB;
1050: }
1051:
1052: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1053: /**
1054: * Handle read from interupt in service register A (0xfffa0f).
1055: */
1.1.1.8 root 1056: void MFP_InServiceA_ReadByte(void)
1057: {
1.1.1.10 root 1058: M68000_WaitState(4);
1059:
1.1.1.8 root 1060: IoMem[0xfffa0f] = MFP_ISRA;
1061: }
1062:
1063: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1064: /**
1065: * Handle read from interupt in service register B (0xfffa11).
1066: */
1.1.1.8 root 1067: void MFP_InServiceB_ReadByte(void)
1068: {
1.1.1.10 root 1069: M68000_WaitState(4);
1070:
1.1.1.8 root 1071: IoMem[0xfffa11] = MFP_ISRB;
1072: }
1073:
1074: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1075: /**
1076: * Handle read from interupt mask register A (0xfffa13).
1077: */
1.1.1.8 root 1078: void MFP_MaskA_ReadByte(void)
1079: {
1.1.1.10 root 1080: M68000_WaitState(4);
1081:
1.1.1.8 root 1082: IoMem[0xfffa13] = MFP_IMRA;
1083: }
1084:
1085: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1086: /**
1087: * Handle read from interupt mask register B (0xfffa15).
1088: */
1.1.1.8 root 1089: void MFP_MaskB_ReadByte(void)
1090: {
1.1.1.10 root 1091: M68000_WaitState(4);
1092:
1.1.1.8 root 1093: IoMem[0xfffa15] = MFP_IMRB;
1094: }
1095:
1096: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1097: /**
1098: * Handle read from MFP vector register (0xfffa17).
1099: */
1.1.1.8 root 1100: void MFP_VectorReg_ReadByte(void)
1101: {
1.1.1.10 root 1102: M68000_WaitState(4);
1103:
1.1.1.8 root 1104: IoMem[0xfffa17] = MFP_VR;
1105: }
1106:
1107: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1108: /**
1109: * Handle read from timer A control register (0xfffa19).
1110: */
1.1.1.8 root 1111: void MFP_TimerACtrl_ReadByte(void)
1112: {
1.1.1.10 root 1113: M68000_WaitState(4);
1114:
1.1.1.8 root 1115: IoMem[0xfffa19] = MFP_TACR;
1116: }
1117:
1118: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1119: /**
1120: * Handle read from timer B control register (0xfffa1b).
1121: */
1.1.1.8 root 1122: void MFP_TimerBCtrl_ReadByte(void)
1123: {
1.1.1.10 root 1124: M68000_WaitState(4);
1125:
1.1.1.8 root 1126: IoMem[0xfffa1b] = MFP_TBCR;
1127: }
1128:
1129: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1130: /**
1131: * Handle read from timer C/D control register (0xfffa1d).
1132: */
1.1.1.8 root 1133: void MFP_TimerCDCtrl_ReadByte(void)
1134: {
1.1.1.10 root 1135: M68000_WaitState(4);
1136:
1.1.1.8 root 1137: IoMem[0xfffa1d] = MFP_TCDCR;
1138: }
1139:
1140: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1141: /**
1142: * Handle read from timer A data register (0xfffa1f).
1143: */
1.1.1.8 root 1144: void MFP_TimerAData_ReadByte(void)
1145: {
1.1.1.10 root 1146: M68000_WaitState(4);
1147:
1.1.1.12 root 1148: if (MFP_TACR != 8) /* Is event count? Need to re-calculate counter */
1149: MFP_ReadTimerA(FALSE); /* Stores result in 'MFP_TA_MAINCOUNTER' */
1.1.1.8 root 1150:
1151: IoMem[0xfffa1f] = MFP_TA_MAINCOUNTER;
1152: }
1153:
1154: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1155: /**
1156: * Handle read from timer B data register (0xfffa21).
1157: */
1.1.1.8 root 1158: void MFP_TimerBData_ReadByte(void)
1159: {
1.1.1.12 root 1160: Uint8 TB_count;
1161:
1.1.1.10 root 1162: M68000_WaitState(4);
1163:
1.1.1.13! root 1164: /* Is it event count mode or not? */
! 1165: if (MFP_TBCR != 8)
! 1166: {
! 1167: /* Not event count mode, so handle as normal timer
! 1168: * and store result in 'MFP_TB_MAINCOUNTER' */
! 1169: MFP_ReadTimerB(FALSE);
! 1170: }
! 1171: else if (bUseVDIRes)
! 1172: {
! 1173: /* HBLs are disabled in VDI mode, but TOS expects to read a 1. */
! 1174: MFP_TB_MAINCOUNTER = 1;
! 1175: }
1.1.1.12 root 1176: /* Special case when reading $fffa21, we need to test if the current read instruction */
1177: /* overlaps the horizontal video position where $fffa21 is changed */
1178: else
1179: {
1180: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1181: int pos_start , pos_read;
1182:
1183: /* Cycle position of the start of the current instruction */
1184: pos_start = nFrameCycles % nCyclesPerLine;
1185: /* Cycle position of the read for the current instruction (approximatively, we consider */
1186: /* the read happens after 4 cycles (due to MFP wait states in that case)) */
1187: /* This is quite a hack, but hard to do without proper 68000 read cycle emulation */
1188: if ( CurrentInstrCycles <= 8 ) /* move.b (a0),d0 / cmp.b (a0),d0 ... */
1189: pos_read = pos_start + 4; /* wait state */
1190: else /* cmp.b $fa21.w,d0 (BIG Demo) ... */
1191: pos_read = pos_start + 8; /* more time needed to compute the effective address */
1192:
1193: TB_count = MFP_TB_MAINCOUNTER; /* default value */
1194:
1195: /* If Timer B's change happens before the read cycle of the current instruction, we must return */
1196: /* the current value - 1 (because MFP_TimerB_EventCount_Interrupt was not called yet) */
1197: if ( (nHBL >= nStartHBL ) && ( nHBL < nEndHBL ) /* ensure display is ON and timer B can happen */
1198: && ( LineTimerBCycle > pos_start ) && ( LineTimerBCycle < pos_read ) )
1199: {
1200: HATARI_TRACE ( HATARI_TRACE_MFP_READ , "mfp read TB overlaps pos_start=%d TB_pos=%d pos_read=%d nHBL=%d \n",
1201: pos_start, LineTimerBCycle, pos_read , nHBL );
1202:
1203: TB_count--;
1204: if ( TB_count == 0 ) /* going from 1 to 0 : timer restart, reload data reg */
1205: TB_count = MFP_TBDR;
1206: /* Going from 0 to -1 : data reg is in fact going from 256 to 255. As TB_count is Uint8, */
1207: /* this is already what we get when we decrement TB_count=0. So, the next 2 lines are redundant. */
1208: /* else if ( TB_count < 0 )
1209: TB_count = 255;
1210: */
1211: }
1212:
1213: HATARI_TRACE ( HATARI_TRACE_MFP_READ , "mfp read TB data=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" ,
1214: TB_count, nFrameCycles, pos_start, nHBL, M68000_GetPC(), CurrentInstrCycles );
1215: IoMem[0xfffa21] = TB_count;
1216: return;
1217: }
1.1.1.8 root 1218:
1219: IoMem[0xfffa21] = MFP_TB_MAINCOUNTER;
1220: }
1221:
1222: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1223: /**
1224: * Handle read from timer C data register (0xfffa23).
1225: */
1.1.1.8 root 1226: void MFP_TimerCData_ReadByte(void)
1227: {
1.1.1.10 root 1228: M68000_WaitState(4);
1229:
1.1.1.12 root 1230: MFP_ReadTimerC(FALSE); /* Stores result in 'MFP_TC_MAINCOUNTER' */
1.1.1.8 root 1231:
1232: IoMem[0xfffa23] = MFP_TC_MAINCOUNTER;
1233: }
1234:
1235: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1236: /**
1237: * Handle read from timer D data register (0xfffa25).
1238: */
1.1.1.8 root 1239: void MFP_TimerDData_ReadByte(void)
1240: {
1.1.1.11 root 1241: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1242:
1.1.1.10 root 1243: M68000_WaitState(4);
1244:
1.1.1.8 root 1245: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
1246: {
1247: /* Trick the tos to believe it was changed: */
1248: IoMem[0xfffa25] = nTimerDFakeValue;
1249: }
1250: else
1251: {
1.1.1.12 root 1252: MFP_ReadTimerD(FALSE); /* Stores result in 'MFP_TD_MAINCOUNTER' */
1.1.1.8 root 1253: IoMem[0xfffa25] = MFP_TD_MAINCOUNTER;
1254: }
1255: }
1256:
1257:
1258: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1259: /**
1260: * Handle write to GPIP register (0xfffa01).
1261: */
1.1.1.8 root 1262: void MFP_GPIP_WriteByte(void)
1263: {
1.1.1.10 root 1264: M68000_WaitState(4);
1265:
1.1.1.8 root 1266: /* Nothing... */
1267: /*fprintf(stderr, "Write to GPIP: %x\n", (int)IoMem[0xfffa01]);*/
1268: /*MFP_GPIP = IoMem[0xfffa01];*/ /* TODO: What are the GPIP pins good for? */
1269: }
1270:
1271: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1272: /**
1273: * Handle write to AER (0xfffa03).
1274: */
1.1.1.8 root 1275: void MFP_ActiveEdge_WriteByte(void)
1276: {
1.1.1.10 root 1277: M68000_WaitState(4);
1278:
1.1.1.8 root 1279: MFP_AER = IoMem[0xfffa03];
1280: }
1281:
1282: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1283: /**
1284: * Handle write to data direction register (0xfffa05).
1285: */
1.1.1.8 root 1286: void MFP_DataDirection_WriteByte(void)
1287: {
1.1.1.10 root 1288: M68000_WaitState(4);
1289:
1.1.1.8 root 1290: MFP_DDR = IoMem[0xfffa05];
1291: }
1292:
1293: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1294: /**
1295: * Handle write to interrupt enable register A (0xfffa07).
1296: */
1.1.1.8 root 1297: void MFP_EnableA_WriteByte(void)
1298: {
1.1.1.10 root 1299: M68000_WaitState(4);
1300:
1.1.1.8 root 1301: MFP_IERA = IoMem[0xfffa07];
1302: MFP_IPRA &= MFP_IERA;
1303: MFP_UpdateFlags();
1304: /* We may have enabled Timer A or B, check */
1.1.1.11 root 1305: /* [NP] No check, restarting the timer is wrong */
1306: // MFP_StartTimerA();
1307: // MFP_StartTimerB();
1.1.1.8 root 1308: }
1309:
1310: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1311: /**
1312: * Handle write to interrupt enable register B (0xfffa09).
1313: */
1.1.1.8 root 1314: void MFP_EnableB_WriteByte(void)
1315: {
1.1.1.10 root 1316: M68000_WaitState(4);
1317:
1.1.1.8 root 1318: MFP_IERB = IoMem[0xfffa09];
1319: MFP_IPRB &= MFP_IERB;
1320: MFP_UpdateFlags();
1321: /* We may have enabled Timer C or D, check */
1.1.1.11 root 1322: /* [NP] No check, restarting the timer is wrong */
1323: // MFP_StartTimerC();
1324: // MFP_StartTimerD();
1.1.1.8 root 1325: }
1326:
1327: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1328: /**
1329: * Handle write to interrupt pending register A (0xfffa0b).
1330: */
1.1.1.8 root 1331: void MFP_PendingA_WriteByte(void)
1332: {
1.1.1.10 root 1333: M68000_WaitState(4);
1334:
1.1.1.8 root 1335: MFP_IPRA &= IoMem[0xfffa0b]; /* Cannot set pending bits - only clear via software */
1336: MFP_UpdateFlags(); /* Check if any interrupts pending */
1337: }
1338:
1339: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1340: /**
1341: * Handle write to interrupt pending register B (0xfffa0d).
1342: */
1.1.1.8 root 1343: void MFP_PendingB_WriteByte(void)
1344: {
1.1.1.10 root 1345: M68000_WaitState(4);
1346:
1.1.1.8 root 1347: MFP_IPRB &= IoMem[0xfffa0d];
1348: MFP_UpdateFlags(); /* Check if any interrupts pending */
1349: }
1350:
1351: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1352: /**
1353: * Handle write to interrupt in service register A (0xfffa0f).
1354: */
1.1.1.8 root 1355: void MFP_InServiceA_WriteByte(void)
1356: {
1.1.1.10 root 1357: M68000_WaitState(4);
1358:
1.1.1.8 root 1359: MFP_ISRA &= IoMem[0xfffa0f]; /* Cannot set in-service bits - only clear via software */
1360: }
1361:
1362: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1363: /**
1364: * Handle write to interrupt in service register B (0xfffa11).
1365: */
1.1.1.8 root 1366: void MFP_InServiceB_WriteByte(void)
1367: {
1.1.1.10 root 1368: M68000_WaitState(4);
1369:
1.1.1.8 root 1370: MFP_ISRB &= IoMem[0xfffa11]; /* Cannot set in-service bits - only clear via software */
1371: }
1372:
1373: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1374: /**
1375: * Handle write to interrupt mask register A (0xfffa13).
1376: */
1.1.1.8 root 1377: void MFP_MaskA_WriteByte(void)
1378: {
1.1.1.10 root 1379: M68000_WaitState(4);
1380:
1.1.1.8 root 1381: MFP_IMRA = IoMem[0xfffa13];
1382: }
1383:
1384: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1385: /**
1386: * Handle write to interrupt mask register B (0xfffa15).
1387: */
1.1.1.8 root 1388: void MFP_MaskB_WriteByte(void)
1389: {
1.1.1.10 root 1390: M68000_WaitState(4);
1391:
1.1.1.8 root 1392: MFP_IMRB = IoMem[0xfffa15];
1393: }
1394:
1395: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1396: /**
1397: * Handle write to MFP vector register (0xfffa17).
1398: */
1.1.1.8 root 1399: void MFP_VectorReg_WriteByte(void)
1400: {
1401: Uint8 old_vr;
1.1.1.10 root 1402:
1403: M68000_WaitState(4);
1404:
1.1.1.8 root 1405: old_vr = MFP_VR; /* Copy for checking if set mode */
1406: MFP_VR = IoMem[0xfffa17];
1.1.1.10 root 1407:
1.1.1.8 root 1408: if ((MFP_VR^old_vr) & 0x08) /* Test change in end-of-interrupt mode */
1409: {
1.1.1.10 root 1410: /* Mode did change but was it to automatic mode? (ie bit is a zero) */
1411: if (!(MFP_VR & 0x08))
1412: {
1413: /* We are now in automatic mode, so clear all in-service bits! */
1.1.1.8 root 1414: MFP_ISRA = 0;
1415: MFP_ISRB = 0;
1416: }
1417: }
1.1.1.11 root 1418:
1419: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
1420: {
1.1.1.12 root 1421: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1.1.1.11 root 1422: int nLineCycles = nFrameCycles % nCyclesPerLine;
1.1.1.12 root 1423: HATARI_TRACE_PRINT ( "mfp write vector reg fa17=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1.1.1.11 root 1424: MFP_VR, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
1425: }
1426:
1.1.1.8 root 1427: }
1428:
1429: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1430: /**
1431: * Handle write to timer A control register (0xfffa19).
1432: */
1.1.1.8 root 1433: void MFP_TimerACtrl_WriteByte(void)
1434: {
1.1.1.11 root 1435: Uint8 new_tacr;
1.1.1.10 root 1436:
1437: M68000_WaitState(4);
1438:
1.1.1.11 root 1439: new_tacr = IoMem[0xfffa19] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */
1.1.1.10 root 1440:
1.1.1.11 root 1441: if ( MFP_TACR != new_tacr ) /* Timer control changed */
1442: {
1443: /* If we stop a timer which was in delay mode, we need to store
1444: * the current value of the counter to be able to read it or to
1445: * continue from where we left if the timer is restarted later
1446: * without writing to the data register. */
1447: if ((new_tacr == 0) && (MFP_TACR >=1) && (MFP_TACR <= 7))
1.1.1.12 root 1448: MFP_ReadTimerA(TRUE); /* Store result in 'MFP_TA_MAINCOUNTER' */
1.1.1.11 root 1449:
1450: MFP_TACR = new_tacr; /* set to new value before calling MFP_StartTimer */
1451: MFP_StartTimerA(); /* start/stop timer depending on control reg */
1452: }
1.1.1.8 root 1453: }
1454:
1455: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1456: /**
1457: * Handle write to timer B control register (0xfffa1b).
1458: */
1.1.1.8 root 1459: void MFP_TimerBCtrl_WriteByte(void)
1460: {
1.1.1.11 root 1461: Uint8 new_tbcr;
1.1.1.10 root 1462:
1463: M68000_WaitState(4);
1464:
1.1.1.11 root 1465: new_tbcr = IoMem[0xfffa1b] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */
1466:
1467: if (MFP_TBCR != new_tbcr) /* Timer control changed */
1468: {
1469: /* If we stop a timer which was in delay mode, we need to store
1470: * the current value of the counter to be able to read it or to
1471: * continue from where we left if the timer is restarted later
1472: * without writing to the data register. */
1473: if ((new_tbcr == 0) && (MFP_TBCR >= 1) && (MFP_TBCR <= 7))
1.1.1.12 root 1474: MFP_ReadTimerB(TRUE); /* Store result in 'MFP_TB_MAINCOUNTER' */
1.1.1.10 root 1475:
1.1.1.11 root 1476: MFP_TBCR = new_tbcr; /* set to new value before calling MFP_StartTimer */
1477: MFP_StartTimerB(); /* start/stop timer depending on control reg */
1478: }
1.1.1.8 root 1479: }
1480:
1481: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1482: /**
1483: * Handle write to timer C/D control register (0xfffa1d).
1484: */
1.1.1.8 root 1485: void MFP_TimerCDCtrl_WriteByte(void)
1486: {
1.1.1.11 root 1487: Uint8 new_tcdcr;
1.1.1.8 root 1488: Uint8 old_tcdcr;
1489:
1.1.1.10 root 1490: M68000_WaitState(4);
1491:
1.1.1.11 root 1492: new_tcdcr = IoMem[0xfffa1d];
1493: old_tcdcr = MFP_TCDCR;
1.1.1.12 root 1494: //fprintf ( stderr , "write fa1d new %x old %x\n" , IoMem[0xfffa1d] , MFP_TCDCR );
1.1.1.8 root 1495:
1.1.1.12 root 1496: if ((old_tcdcr & 0x70) != (new_tcdcr & 0x70)) /* Timer C control changed */
1.1.1.11 root 1497: {
1498: /* If we stop a timer which was in delay mode, we need to store
1499: * the current value of the counter to be able to read it or to
1500: * continue from where we left if the timer is restarted later
1501: * without writing to the data register. */
1502: if ((new_tcdcr & 0x70) == 0)
1.1.1.12 root 1503: MFP_ReadTimerC(TRUE); /* Store result in 'MFP_TC_MAINCOUNTER' */
1.1.1.11 root 1504:
1.1.1.12 root 1505: MFP_TCDCR = ( new_tcdcr & 0x70 ) | ( old_tcdcr & 0x07 ); /* we set TCCR and keep old TDDR in case we need to read it below */
1.1.1.11 root 1506: MFP_StartTimerC(); /* start/stop timer depending on control reg */
1507: }
1.1.1.8 root 1508:
1.1.1.12 root 1509: if ((old_tcdcr & 0x07) != (new_tcdcr & 0x07)) /* Timer D control changed */
1.1.1.8 root 1510: {
1.1.1.11 root 1511: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1512:
1513: /* Need to change baud rate of RS232 emulation? */
1514: if (ConfigureParams.RS232.bEnableRS232)
1515: {
1516: RS232_SetBaudRateFromTimerD();
1517: }
1518:
1519: if (ConfigureParams.System.bPatchTimerD && !bAppliedTimerDPatch
1.1.1.11 root 1520: && pc >= TosAddress && pc <= TosAddress + TosSize)
1.1.1.8 root 1521: {
1.1.1.11 root 1522: /* Slow down Timer-D if set from TOS for the first time to gain
1523: * more desktop performance.
1524: * Obviously, we need to emulate all timers correctly but TOS sets
1525: * up Timer-D at a very high rate (every couple of instructions).
1526: * The interrupt isn't enabled but the emulator still needs to
1527: * process the interrupt table and this HALVES our frame rate!!!
1.1.1.8 root 1528: * Some games actually reference this timer but don't set it up
1.1.1.11 root 1529: * (eg Paradroid, Speedball I) so we simply intercept the Timer-D
1530: * setup code in TOS and fix the numbers with more 'laid-back'
1531: * values. This still keeps 100% compatibility */
1.1.1.12 root 1532: if ( new_tcdcr & 0x07 ) /* apply patch only if timer D is being started */
1533: {
1534: new_tcdcr = IoMem[0xfffa1d] = (IoMem[0xfffa1d] & 0xf0) | 7;
1535: bAppliedTimerDPatch = TRUE;
1536: }
1.1.1.8 root 1537: }
1.1.1.11 root 1538:
1539: /* If we stop a timer which was in delay mode, we need to store the current value */
1540: /* of the counter to be able to read it or to continue from where we left if the timer is */
1541: /* restarted later without writing to the data register. */
1542: if ((new_tcdcr & 0x07) == 0)
1.1.1.12 root 1543: MFP_ReadTimerD(TRUE); /* Stores result in 'MFP_TD_MAINCOUNTER' */
1.1.1.11 root 1544:
1545: MFP_TCDCR = new_tcdcr; /* set to new value before calling MFP_StartTimer */
1.1.1.12 root 1546: MFP_StartTimerD(); /* start/stop timer depending on control reg */
1.1.1.8 root 1547: }
1548: }
1549:
1550: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1551: /**
1552: * Handle write to timer A data register (0xfffa1f).
1553: */
1.1.1.8 root 1554: void MFP_TimerAData_WriteByte(void)
1555: {
1.1.1.10 root 1556: M68000_WaitState(4);
1557:
1.1.1.8 root 1558: MFP_TADR = IoMem[0xfffa1f]; /* Store into data register */
1.1.1.10 root 1559:
1.1.1.8 root 1560: if (MFP_TACR == 0) /* Now check if timer is running - if so do not set */
1561: {
1562: MFP_TA_MAINCOUNTER = MFP_TADR; /* Timer is off, store to main counter */
1.1.1.11 root 1563: TimerACanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1564: }
1.1.1.12 root 1565:
1566: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
1567: {
1568: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1569: int nLineCycles = nFrameCycles % nCyclesPerLine;
1570: HATARI_TRACE_PRINT ( "mfp write data reg A fa1f=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1571: MFP_TADR, MFP_TA_MAINCOUNTER, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
1572: }
1.1.1.8 root 1573: }
1574:
1575: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1576: /**
1577: * Handle write to timer B data register (0xfffa21).
1578: */
1.1.1.8 root 1579: void MFP_TimerBData_WriteByte(void)
1580: {
1.1.1.10 root 1581: M68000_WaitState(4);
1582:
1.1.1.8 root 1583: MFP_TBDR = IoMem[0xfffa21]; /* Store into data register */
1.1.1.10 root 1584:
1.1.1.8 root 1585: if (MFP_TBCR == 0) /* Now check if timer is running - if so do not set */
1586: {
1587: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Timer is off, store to main counter */
1.1.1.11 root 1588: TimerBCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1589: }
1.1.1.12 root 1590:
1591: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
1592: {
1593: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1594: int nLineCycles = nFrameCycles % nCyclesPerLine;
1595: HATARI_TRACE_PRINT ( "mfp write data reg B fa21=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1596: MFP_TBDR, MFP_TB_MAINCOUNTER, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
1597: }
1.1.1.8 root 1598: }
1599:
1600: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1601: /**
1602: * Handle write to timer C data register (0xfffa23).
1603: */
1.1.1.8 root 1604: void MFP_TimerCData_WriteByte(void)
1605: {
1.1.1.10 root 1606: M68000_WaitState(4);
1607:
1.1.1.8 root 1608: MFP_TCDR = IoMem[0xfffa23]; /* Store into data register */
1.1.1.10 root 1609:
1.1.1.8 root 1610: if ((MFP_TCDCR&0x70) == 0) /* Now check if timer is running - if so do not set */
1611: {
1.1.1.11 root 1612: MFP_TC_MAINCOUNTER = MFP_TCDR; /* Timer is off, store to main counter */
1613: TimerCCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1614: }
1.1.1.12 root 1615:
1616: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
1617: {
1618: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1619: int nLineCycles = nFrameCycles % nCyclesPerLine;
1620: HATARI_TRACE_PRINT ( "mfp write data reg C fa23=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1621: MFP_TCDR, MFP_TC_MAINCOUNTER, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
1622: }
1.1.1.8 root 1623: }
1624:
1625: /*-----------------------------------------------------------------------*/
1.1.1.11 root 1626: /**
1627: * Handle write to timer D data register (0xfffa25).
1628: */
1.1.1.8 root 1629: void MFP_TimerDData_WriteByte(void)
1630: {
1.1.1.11 root 1631: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1632:
1.1.1.10 root 1633: M68000_WaitState(4);
1634:
1.1.1.8 root 1635: /* Need to change baud rate of RS232 emulation? */
1636: if (ConfigureParams.RS232.bEnableRS232 && (IoMem[0xfffa1d] & 0x07))
1637: {
1638: RS232_SetBaudRateFromTimerD();
1639: }
1640:
1641: /* Patch Timer-D for better performance? */
1642: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
1643: {
1644: nTimerDFakeValue = IoMem[0xfffa25];
1645: IoMem[0xfffa25] = 0x64; /* Slow down the useless Timer-D setup from the bios */
1646: }
1647:
1648: MFP_TDDR = IoMem[0xfffa25]; /* Store into data register */
1649: if ((MFP_TCDCR&0x07) == 0) /* Now check if timer is running - if so do not set */
1650: {
1.1.1.11 root 1651: MFP_TD_MAINCOUNTER = MFP_TDDR; /* Timer is off, store to main counter */
1652: TimerDCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1653: }
1.1.1.12 root 1654:
1655: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
1656: {
1657: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
1658: int nLineCycles = nFrameCycles % nCyclesPerLine;
1659: HATARI_TRACE_PRINT ( "mfp write data reg D fa25=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
1660: MFP_TDDR, MFP_TD_MAINCOUNTER, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
1661: }
1.1.1.8 root 1662: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.