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