|
|
1.1 ! root 1: /* ! 2: Hatari - acia.c ! 3: ! 4: Copyright (C) 2012 by Nicolas Pomarède ! 5: ! 6: This file is distributed under the GNU Public License, version 2 or at ! 7: your option any later version. Read the file gpl.txt for details. ! 8: ! 9: MC6850 ACIA emulation. ! 10: */ ! 11: ! 12: const char ACIA_fileid[] = "Hatari acia.c : " __DATE__ " " __TIME__; ! 13: ! 14: ! 15: /* 2012/09/28 [NP] Start of the full rewrite of the MC6850 ACIA emulation, using the official */ ! 16: /* datasheets for maximum accuracy, as well as bit level serial transfers (start, */ ! 17: /* stop and parity bits). */ ! 18: /* 2012/12/21 [NP] Add accurate cycles delays when accessing an ACIA register, taking E Clock */ ! 19: /* into account. */ ! 20: /* 2013/04/24 [NP] Remove INTERRUPT_ACIA_MFP used to add a 4 cycle delay when IRQ is set, as this */ ! 21: /* delay is now correctly handled directly in the MFP since 2013/03/01. */ ! 22: ! 23: ! 24: ! 25: ! 26: /* ! 27: 6850 ACIA (Asynchronous Communications Inferface Apdater) ! 28: ! 29: References : ! 30: - MC6850 datasheet by Motorola (DS9493R4, 1985) ! 31: - A6850 datasheet by Altera (A-DS-A6850-01, 1996) (nearly identical component) ! 32: ! 33: Others references : ! 34: - MAME's 6850acia.c for RTS, CTS and DCD behaviour ! 35: ! 36: ! 37: Pins : ! 38: Vss ! 39: RX DATA Receive Data ! 40: RX CLK Receive Clock ! 41: TX CLK Transmitter Clock ! 42: RTS Request To Send ! 43: TX DATA Transmitter Data ! 44: IRQ Interrupt Request ! 45: CS 0,1,2 Chip Select ! 46: RS Register Select ! 47: Vcc Voltage ! 48: R/W Read/Write ! 49: E Enable ! 50: D0-D7 Data ! 51: DCD Data Carrier Detect ! 52: CTS Clear To Send ! 53: ! 54: Registers : ! 55: 0xfffc00 Keyboard ACIA Control (write)/Status(read) ! 56: 0xfffc02 Keyboard ACIA Data ! 57: 0xfffc04 MIDI ACIA Control (write)/Status(read) ! 58: 0xfffc06 MIDI ACIA Data ! 59: ! 60: Control Register (0xfffc00 write) : ! 61: Bits 0,1 - These bits determine by which factor the transmitter and receiver ! 62: clock will be divided. These bits also are joined with a master reset ! 63: function. The 6850 has no separate reset line, so it must be ! 64: accomplished though software. ! 65: 0 0 RXCLK/TXCLK without division ! 66: 0 1 RXCLK/TXCLK by 16 (MIDI) ! 67: 1 0 RXCLK/TXCLK by 64 (Keyboard) ! 68: 1 1 Master RESET ! 69: Bits 2,3,4 - These so-called Word Select bits tell whether 7 or 8 data-bits are ! 70: involved; whether 1 or 2 stop-bits are transferred; and the type of parity ! 71: Bits 5,6 - These Transmitter Control bits set the RTS output pin, and allow or prevent ! 72: an interrupt through the ACIA when the send register is emptied. Also, BREAK signals ! 73: can be sent over the serial output by this line. A BREAK signal is nothing more than ! 74: a long seqence of null bits ! 75: 0 0 RTS low, transmitter IRQ disabled ! 76: 0 1 RTS low, transmitter IRQ enabled ! 77: 1 0 RTS high, transmitter IRQ disabled ! 78: 1 1 RTS low, transmitter IRQ disabled, BREAK sent ! 79: Bit 7 - The Receiver Interrupt Enable bit determines whether the receiver interrupt ! 80: will be on. An interrupt can be caused by the DCD line chaning from low to high, or ! 81: by the receiver data buffer filling. Besides that, an interrupt can occur from an ! 82: OVERRUN (a received character isn't properly read from the processor). ! 83: 0 Interrupt disabled ! 84: 1 Interrupt enabled ! 85: ! 86: Status Register (0xfffc00 read) : ! 87: Bit 0 - When this bit is high, the RX data register is full. The byte must be read ! 88: before a new character is received (otherwise an OVERRUN happens) ! 89: Bit 1 - This bit reflects the status of the TX data buffer. An empty register ! 90: set the bit. ! 91: Bit 2 - A low-high change in pin DCD sets bit 2. If the receiver interrupt is allowable, the IRQ ! 92: is cancelled. The bit is cleared when the status register and the receiver register are ! 93: read. This also cancels the IRQ. Bit 2 register remains highis the signal on the DCD pin ! 94: is still high; Bit 2 register low if DCD becomes low. ! 95: Bit 3 - This line shows the status of CTS. This signal cannot be altered by a mater reset, ! 96: or by ACIA programming. ! 97: Bit 4 - Shows 'Frame Errors'. Frame errors are when no stop-bit is recognized in receiver ! 98: switching. It can be set with every new character. ! 99: Bit 5 - This bit display the previously mentioned OVERRUN condition. Bit 5 is reset when the ! 100: RX buffer is read. ! 101: Bit 6 - This bit recognizes whether the parity of a received character is correct. The bit is ! 102: set on an error. ! 103: Bit 7 - This signals the state of the IRQ pins; this bit make it possible to switch several ! 104: IRQ lines on one interrupt input. In cases where an interrupt is program-generated, bit 7 ! 105: can tell which IC cut off the interrupt. ! 106: ! 107: ST ACIA : ! 108: CTS,DCD and RTS are not connected ! 109: The keyboard ACIA addresses are 0xfffc000 and 0xfffc02. ! 110: The MIDI ACIA addresses are 0xfffc004 and 0xfffc06. ! 111: Default keyboard parameters are : 8-bit word, 1 stopbit, no parity, 7812.5 baud; 500KHz/64 (keyboard clock div) ! 112: Default MIDI parameters are as above but : 31250 baud; 500KHz/16 (MIDI clock div) ! 113: ! 114: ! 115: CPU cycles in the ST : ! 116: When accessing an ACIA register, an additional delay will be added to the usual number of ! 117: cycles for this CPU instruction. This delay is made of 2 parts (for a 68000 at 8 MHz) : ! 118: - a fixed delay of 6 cycles. ! 119: - a variable delay of 0 to 8 cycles to synchronise with the E Clock. ! 120: ! 121: Examples for some common instructions measured on a real 520 STF ! 122: (with a0=$fffffc00 and 'n' the delay for E Clock) : ! 123: move.b (a0),d2 : 14 cycles = 8 + 6 + n ! 124: move.w (a0),d2 : 14 cycles = 8 + 6 + n ! 125: move.l (a0),d2 : 24 cycles = 12 + 6 + 6 + n ! 126: movep.w (a0),d2 : 28 cycles = 16 + 6 + 6 + n ! 127: movep.l (a0),d2 : 48 cycles = 24 + 6 + 6 + 6 + 6 + n ! 128: (on ST, those values might be rounded to the next multiple of 4 cycles) ! 129: ! 130: When the ACIA's IRQ signal goes low, the resulting bit in the MFP is visible to the CPU only 4 cycles later. ! 131: From the hardware point of view, the ACIA's irq signal is immediately propagated to the MFP, ! 132: but the MFP will then add a 4 cycle delay before generating a 68000 interrupt. ! 133: ! 134: */ ! 135: ! 136: /*-----------------------------------------------------------------------*/ ! 137: ! 138: ! 139: #include "main.h" ! 140: #include "log.h" ! 141: #include "memorySnapShot.h" ! 142: #include "configuration.h" ! 143: #include "acia.h" ! 144: #include "m68000.h" ! 145: #include "cycInt.h" ! 146: #include "ioMem.h" ! 147: #include "clocks_timings.h" ! 148: #include "mfp.h" ! 149: #include "screen.h" ! 150: #include "video.h" ! 151: ! 152: ! 153: #define ACIA_SR_BIT_RDRF 0x01 /* Receive Data Register Full */ ! 154: #define ACIA_SR_BIT_TDRE 0x02 /* Transmit Data Register Empty */ ! 155: #define ACIA_SR_BIT_DCD 0x04 /* Data Carrier Detect */ ! 156: #define ACIA_SR_BIT_CTS 0x08 /* Clear To Send */ ! 157: #define ACIA_SR_BIT_FE 0x10 /* Framing Error */ ! 158: #define ACIA_SR_BIT_OVRN 0x20 /* Receiver Overrun */ ! 159: #define ACIA_SR_BIT_PE 0x40 /* Parity Error */ ! 160: #define ACIA_SR_BIT_IRQ 0x80 /* IRQ */ ! 161: ! 162: #define ACIA_CR_COUNTER_DIVIDE( CR ) ( CR & 0x03 ) /* CR1 + CR0 : 0x03 causes a master reset */ ! 163: #define ACIA_CR_WORD_SELECT( CR ) ( ( CR >> 2 ) & 0x07 ) /* CR4 + CR3 + CR2 : size, parity, stop bits */ ! 164: #define ACIA_CR_TRANSMITTER_CONTROL( CR ) ( ( CR >> 5 ) & 0x03 ) /* CR6 + CR5 : RTS + IRQ on send */ ! 165: #define ACIA_CR_RECEIVE_INTERRUPT_ENABLE( CR ) ( ( CR >> 7 ) & 0x01 ) /* CR7 : Reveive interrupt enable */ ! 166: ! 167: ! 168: ! 169: int ACIA_Counter_Divide[ 3 ] = { 1 , 16 , 64 }; /* Used to divide txclock/rxclock to get the correct baud rate */ ! 170: ! 171: ! 172: /* Data size, parity and stop bits used for the transfer depending on CR_WORD_SELECT */ ! 173: enum ! 174: { ! 175: ACIA_PARITY_NONE , ! 176: ACIA_PARITY_EVEN , ! 177: ACIA_PARITY_ODD ! 178: }; ! 179: ! 180: ! 181: static struct { ! 182: int DataBits; /* 7 or 8 */ ! 183: int Parity; /* EVEN or ODD or NONE */ ! 184: int StopBits; /* 1 or 2 */ ! 185: } ACIA_Serial_Params [ 8 ] = { ! 186: { 7 , ACIA_PARITY_EVEN , 2 }, ! 187: { 7 , ACIA_PARITY_ODD , 2 }, ! 188: { 7 , ACIA_PARITY_EVEN , 1 }, ! 189: { 7 , ACIA_PARITY_ODD , 1 }, ! 190: { 8 , ACIA_PARITY_NONE , 2 }, ! 191: { 8 , ACIA_PARITY_NONE , 1 }, ! 192: { 8 , ACIA_PARITY_EVEN , 1 }, ! 193: { 8 , ACIA_PARITY_ODD , 1 } ! 194: }; ! 195: ! 196: ! 197: ! 198: /* Possible states when handling TX/RX interrupts */ ! 199: enum ! 200: { ! 201: ACIA_STATE_IDLE = 0, ! 202: ACIA_STATE_DATA_BIT, ! 203: ACIA_STATE_PARITY_BIT, ! 204: ACIA_STATE_STOP_BIT ! 205: }; ! 206: ! 207: ! 208: ACIA_STRUCT ACIA_Array[ ACIA_MAX_NB ]; ! 209: ACIA_STRUCT *pACIA_IKBD; ! 210: ACIA_STRUCT *pACIA_MIDI; ! 211: ! 212: ! 213: ! 214: ! 215: /*--------------------------------------------------------------*/ ! 216: /* Local functions prototypes */ ! 217: /*--------------------------------------------------------------*/ ! 218: ! 219: static void ACIA_Init_Pointers ( ACIA_STRUCT *pAllACIA ); ! 220: ! 221: static void ACIA_Set_Line_IRQ_MFP ( int bit ); ! 222: static Uint8 ACIA_Get_Line_CTS_Dummy ( void ); ! 223: static Uint8 ACIA_Get_Line_DCD_Dummy ( void ); ! 224: static void ACIA_Set_Line_RTS_Dummy ( int bit ); ! 225: ! 226: static void ACIA_Set_Timers_IKBD ( void *pACIA ); ! 227: static void ACIA_Start_InterruptHandler_IKBD ( ACIA_STRUCT *pACIA , int InternalCycleOffset ); ! 228: ! 229: static Uint8 ACIA_MasterReset ( ACIA_STRUCT *pACIA , Uint8 CR ); ! 230: ! 231: static void ACIA_UpdateIRQ ( ACIA_STRUCT *pACIA ); ! 232: ! 233: static Uint8 ACIA_Read_SR ( ACIA_STRUCT *pACIA ); ! 234: static void ACIA_Write_CR ( ACIA_STRUCT *pACIA , Uint8 CR ); ! 235: static Uint8 ACIA_Read_RDR ( ACIA_STRUCT *pACIA ); ! 236: static void ACIA_Write_TDR ( ACIA_STRUCT *pACIA , Uint8 TDR ); ! 237: ! 238: static void ACIA_Prepare_TX ( ACIA_STRUCT *pACIA ); ! 239: static void ACIA_Prepare_RX ( ACIA_STRUCT *pACIA ); ! 240: static void ACIA_Clock_TX ( ACIA_STRUCT *pACIA ); ! 241: static void ACIA_Clock_RX ( ACIA_STRUCT *pACIA ); ! 242: ! 243: ! 244: ! 245: ! 246: ! 247: /*-----------------------------------------------------------------------*/ ! 248: /** ! 249: * Init the 2 ACIAs in an Atari ST. ! 250: * Both ACIAs have a 500 MHZ TX/RX clock. ! 251: * This is called only once, when the emulator starts. ! 252: * NOTE : when testing EmuTos on real hardware, it seems the tx/rx is working ! 253: * after a cold reset (ST switched on), even if Clock_Divider was not initialized yet. ! 254: * The default behaviour is not described in the ACIA's ref doc, but bits ! 255: * seem to be transmitted (maybe with errors ?). So we default ! 256: * to 9600 bauds to avoid a lock if a program uses tx/rx after a reset. ! 257: */ ! 258: void ACIA_Init ( ACIA_STRUCT *pAllACIA , Uint32 TX_Clock , Uint32 RX_Clock ) ! 259: { ! 260: int i; ! 261: ! 262: ! 263: LOG_TRACE ( TRACE_ACIA, "acia init tx_clock=%d rx_clock=%d\n" , TX_Clock , RX_Clock ); ! 264: ! 265: for ( i=0 ; i<ACIA_MAX_NB ; i++ ) ! 266: { ! 267: memset ( (void *)&(pAllACIA[ i ]) , 0 , sizeof ( ACIA_STRUCT) ); ! 268: ! 269: pAllACIA[ i ].TX_Clock = TX_Clock; ! 270: pAllACIA[ i ].RX_Clock = RX_Clock; ! 271: pAllACIA[ i ].Clock_Divider = 0; /* Divider not initialized yet */ ! 272: pAllACIA[ i ].FirstMasterReset = 1; ! 273: } ! 274: ! 275: /* Set the default common callback functions + other pointers */ ! 276: ACIA_Init_Pointers ( pAllACIA ); ! 277: } ! 278: ! 279: ! 280: ! 281: /*-----------------------------------------------------------------------*/ ! 282: /** ! 283: * Init some functions/memory pointers for each ACIA. ! 284: * This is called at Init and when restoring a memory snapshot. ! 285: */ ! 286: static void ACIA_Init_Pointers ( ACIA_STRUCT *pAllACIA ) ! 287: { ! 288: int i; ! 289: ! 290: ! 291: for ( i=0 ; i<ACIA_MAX_NB ; i++ ) ! 292: { ! 293: /* Set the default common callback functions */ ! 294: pAllACIA[ i ].Set_Line_IRQ = ACIA_Set_Line_IRQ_MFP; ! 295: pAllACIA[ i ].Get_Line_CTS = ACIA_Get_Line_CTS_Dummy; ! 296: pAllACIA[ i ].Get_Line_DCD = ACIA_Get_Line_DCD_Dummy; ! 297: pAllACIA[ i ].Set_Line_RTS = ACIA_Set_Line_RTS_Dummy; ! 298: } ! 299: ! 300: strcpy ( pAllACIA[ 0 ].ACIA_Name , "ikbd" ); ! 301: strcpy ( pAllACIA[ 1 ].ACIA_Name , "midi" ); ! 302: ! 303: pACIA_IKBD = &(pAllACIA[ 0 ]); ! 304: pACIA_MIDI = &(pAllACIA[ 1 ]); ! 305: ! 306: pACIA_IKBD->Set_Timers = ACIA_Set_Timers_IKBD; ! 307: // pACIA_MIDI->Set_Timers = ACIA_Set_Timers_MIDI; /* Not used for now */ ! 308: } ! 309: ! 310: ! 311: ! 312: ! 313: /*-----------------------------------------------------------------------*/ ! 314: /** ! 315: * There's no real hardware reset on the ACIA, but as the Reset_ST() ! 316: * functions turns off all internal interrupts, we must restart the ACIA's ! 317: * interrupt after a reset. ! 318: */ ! 319: void ACIA_Reset ( ACIA_STRUCT *pAllACIA ) ! 320: { ! 321: int i; ! 322: ! 323: ! 324: LOG_TRACE ( TRACE_ACIA, "acia reset\n" ); ! 325: ! 326: for ( i=0 ; i<ACIA_MAX_NB ; i++ ) ! 327: { ! 328: if ( pAllACIA[ i ].Clock_Divider > 0 ) /* Divider already initialized */ ! 329: pAllACIA[ i ].Set_Timers ( &(pAllACIA[ i ]) ); /* Restart the timer */ ! 330: } ! 331: } ! 332: ! 333: ! 334: ! 335: /*-----------------------------------------------------------------------*/ ! 336: /** ! 337: * Save/Restore snapshot of local variables ('MemorySnapShot_Store' handles type) ! 338: */ ! 339: void ACIA_MemorySnapShot_Capture ( bool bSave ) ! 340: { ! 341: MemorySnapShot_Store(&ACIA_Array, sizeof(ACIA_Array)); ! 342: ! 343: if ( !bSave ) /* If restoring */ ! 344: ACIA_Init_Pointers ( ACIA_Array ); /* Restore pointers */ ! 345: } ! 346: ! 347: ! 348: ! 349: ! 350: /*-----------------------------------------------------------------------*/ ! 351: /** ! 352: * Set or reset the ACIA's IRQ signal. ! 353: * IRQ signal is inverted (0/low sets irq, 1/high resets irq) ! 354: * In the ST, the 2 ACIA's IRQ pins are connected to the same MFP pin, ! 355: * so they share the same IRQ bit in the MFP. ! 356: */ ! 357: static void ACIA_Set_Line_IRQ_MFP ( int bit ) ! 358: { ! 359: LOG_TRACE ( TRACE_ACIA, "acia set irq line val=%d VBL=%d HBL=%d\n" , bit , nVBLs , nHBL ); ! 360: ! 361: if ( bit == 0 ) ! 362: { ! 363: /* There's a small delay on a real ST between the point in time ! 364: * the irq bit is set and the MFP interrupt is triggered - for example ! 365: * the "V8 music system" demo depends on this behaviour. ! 366: * This 4 cycle delay is handled in mfp.c */ ! 367: ! 368: MFP_GPIP &= ~0x10; /* set IRQ signal for GPIP P4 */ ! 369: MFP_InputOnChannel ( MFP_INT_ACIA , 0 ); ! 370: } ! 371: else ! 372: { ! 373: /* GPIP I4 - General Purpose Pin Keyboard/MIDI interrupt */ ! 374: MFP_GPIP |= 0x10; /* IRQ bit was reset */ ! 375: } ! 376: } ! 377: ! 378: ! 379: ! 380: ! 381: /*-----------------------------------------------------------------------*/ ! 382: /** ! 383: * Read the Clear To Send (CTS) pin ! 384: * When CTS is high, TDRE should always be set to 0 ! 385: * Note : this is not connected on an ST, so we always return 0. ! 386: */ ! 387: static Uint8 ACIA_Get_Line_CTS_Dummy ( void ) ! 388: { ! 389: Uint8 bit; ! 390: ! 391: bit = 0; ! 392: LOG_TRACE ( TRACE_ACIA, "acia get cts=%d VBL=%d HBL=%d\n" , bit , nVBLs , nHBL ); ! 393: return bit; ! 394: } ! 395: ! 396: /*-----------------------------------------------------------------------*/ ! 397: /** ! 398: * Read the Data Carrier Detect (DCD) pin ! 399: * Note : this is not connected on an ST, so we always return 0. ! 400: */ ! 401: static Uint8 ACIA_Get_Line_DCD_Dummy ( void ) ! 402: { ! 403: Uint8 bit; ! 404: ! 405: bit = 0; ! 406: LOG_TRACE ( TRACE_ACIA, "acia get dcd=%d VBL=%d HBL=%d\n" , bit , nVBLs , nHBL ); ! 407: return bit; ! 408: } ! 409: ! 410: /*-----------------------------------------------------------------------*/ ! 411: /** ! 412: * Set the Request To Send (RTS) pin. ! 413: * Note : this is not connected on an ST, so we ignore it. ! 414: */ ! 415: static void ACIA_Set_Line_RTS_Dummy ( int bit ) ! 416: { ! 417: LOG_TRACE ( TRACE_ACIA, "acia set rts val=%d VBL=%d HBL=%d\n" , bit , nVBLs , nHBL ); ! 418: } ! 419: ! 420: ! 421: ! 422: ! 423: /*-----------------------------------------------------------------------*/ ! 424: /** ! 425: * Set the required timers to handle RX / TX, depending on the CR_DIVIDE ! 426: * value. ! 427: * When CR is changed with a new CR_DIVIDE value, we restart the timers. ! 428: */ ! 429: static void ACIA_Set_Timers_IKBD ( void *pACIA ) ! 430: { ! 431: ACIA_Start_InterruptHandler_IKBD ( (ACIA_STRUCT *)pACIA , 0 ); ! 432: } ! 433: ! 434: ! 435: ! 436: ! 437: /*-----------------------------------------------------------------------*/ ! 438: /** ! 439: * Set a timer to handle the RX / TX bits at the expected baud rate. ! 440: * NOTE : on ST, TX_Clock and RX_Clock are the same, so the timer's freq will be ! 441: * TX_Clock / Divider and we only need one timer interrupt to handle both RX and TX. ! 442: * This freq should be converted to CPU_CYCLE : 1 ACIA cycle = 16 CPU cycles ! 443: * (with cpu running at 8 MHz) ! 444: * InternalCycleOffset allows to compensate for a != 0 value in PendingInterruptCount ! 445: * to keep a constant baud rate. ! 446: * TODO : we use a fixed 8 MHz clock and nCpuFreqShift to convert cycles for our ! 447: * internal timers in cycInt.c. This should be replaced some days by using ! 448: * MachineClocks.CPU_Freq and not using nCpuFreqShift anymore. ! 449: */ ! 450: static void ACIA_Start_InterruptHandler_IKBD ( ACIA_STRUCT *pACIA , int InternalCycleOffset ) ! 451: { ! 452: int Cycles; ! 453: ! 454: ! 455: // Cycles = MachineClocks.CPU_Freq / pACIA->TX_Clock; /* Convert ACIA cycles in CPU cycles */ ! 456: Cycles = 8021247 / pACIA->TX_Clock; /* Convert ACIA cycles in CPU cycles, for a 8 MHz STF reference */ ! 457: Cycles *= pACIA->Clock_Divider; ! 458: Cycles <<= nCpuFreqShift; /* Compensate for x2 or x4 cpu speed */ ! 459: ! 460: LOG_TRACE ( TRACE_ACIA, "acia %s start timer divider=%d cpu_cycles=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , ! 461: pACIA->Clock_Divider , Cycles , nVBLs , nHBL ); ! 462: ! 463: CycInt_AddRelativeInterruptWithOffset ( Cycles, INT_CPU_CYCLE, INTERRUPT_ACIA_IKBD , InternalCycleOffset ); ! 464: } ! 465: ! 466: ! 467: ! 468: ! 469: /*-----------------------------------------------------------------------*/ ! 470: /** ! 471: * Interrupt called each time a new bit must be sent / received with the IKBD. ! 472: * This interrupt will be called at freq ( 500 MHz / ACIA_CR_COUNTER_DIVIDE ) ! 473: * On ST, RX_Clock = TX_Clock = 500 MHz. ! 474: * We continuously restart the interrupt, taking into account PendingCyclesOver. ! 475: */ ! 476: void ACIA_InterruptHandler_IKBD ( void ) ! 477: { ! 478: int PendingCyclesOver; ! 479: ! 480: ! 481: /* Number of internal cycles we went over for this timer ( <= 0 ) */ ! 482: /* Used to restart the next timer and keep a constant baud rate */ ! 483: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */ ! 484: ! 485: LOG_TRACE ( TRACE_ACIA, "acia ikbd interrupt handler pending_cyc=%d VBL=%d HBL=%d\n" , PendingCyclesOver , nVBLs , nHBL ); ! 486: ! 487: /* Remove this interrupt from list and re-order */ ! 488: CycInt_AcknowledgeInterrupt(); ! 489: ! 490: ACIA_Clock_TX ( pACIA_IKBD ); ! 491: ACIA_Clock_RX ( pACIA_IKBD ); ! 492: ! 493: ACIA_Start_InterruptHandler_IKBD ( pACIA_IKBD , -PendingCyclesOver ); /* Compensate for a != 0 value of PendingCyclesOver */ ! 494: } ! 495: ! 496: ! 497: ! 498: ! 499: /*-----------------------------------------------------------------------*/ ! 500: /** ! 501: * Interrupt called each time a new bit must be sent / received with the MIDI. ! 502: * This interrupt will be called at freq ( 500 MHz / ACIA_CR_COUNTER_DIVIDE ) ! 503: * On ST, RX_Clock = TX_Clock = 500 MHz. ! 504: */ ! 505: void ACIA_InterruptHandler_MIDI ( void ) ! 506: { ! 507: ACIA_Clock_TX ( pACIA_MIDI ); ! 508: ACIA_Clock_RX ( pACIA_MIDI ); ! 509: } ! 510: ! 511: ! 512: ! 513: ! 514: /*-----------------------------------------------------------------------*/ ! 515: /** ! 516: * - For each access to an ACIA register, a 6 cycles delay is added to the ! 517: * normal 68000 timing for the current CPU instruction. If the instruction ! 518: * accesses several registers at once, the delays are cumulated. ! 519: * - An additional delay will also be added to ensure the 68000 clock and ! 520: * the E clock are synchronised ; this delay can add between 0 and 8 cycles ! 521: * to reach the next multiple of 10 cycles. This delay is added only once ! 522: * per CPU instruction. ! 523: * These delays are measured for an 8 MHz 68000 CPU. ! 524: */ ! 525: void ACIA_AddWaitCycles ( void ) ! 526: { ! 527: int cycles; ! 528: ! 529: /* Add a default of 6 cycles for each access */ ! 530: cycles = 6; ! 531: ! 532: /* Wait for E clock only if this is the first ACIA access for this instruction */ ! 533: /* (NOTE : in UAE, movep behaves like several bytes access with different IoAccessBaseAddress, */ ! 534: /* so only the first movep's access should wait for E Clock) */ ! 535: if ( ( ( MovepByteNbr == 0 ) && ( IoAccessBaseAddress == IoAccessCurrentAddress ) ) ! 536: || ( MovepByteNbr == 1 ) ) /* First access of a movep */ ! 537: cycles += M68000_WaitEClock (); ! 538: ! 539: M68000_WaitState ( cycles ); ! 540: } ! 541: ! 542: ! 543: ! 544: /*-----------------------------------------------------------------------*/ ! 545: /** ! 546: * Return SR for the IKBD's ACIA (0xfffc00) ! 547: */ ! 548: void ACIA_IKBD_Read_SR ( void ) ! 549: { ! 550: ACIA_AddWaitCycles (); /* Additional cycles when accessing the ACIA */ ! 551: ! 552: IoMem[0xfffc00] = ACIA_Read_SR ( pACIA_IKBD ); ! 553: ! 554: if (LOG_TRACE_LEVEL(TRACE_ACIA)) ! 555: { ! 556: int FrameCycles, HblCounterVideo, LineCycles; ! 557: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 558: LOG_TRACE_PRINT("acia %s read fffc00 sr=0x%02x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", pACIA_IKBD->ACIA_Name , ! 559: IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); ! 560: } ! 561: } ! 562: ! 563: ! 564: ! 565: ! 566: /*-----------------------------------------------------------------------*/ ! 567: /** ! 568: * Return RDR for the IKBD's ACIA (0xfffc02) : receive a byte from the IKBD ! 569: */ ! 570: void ACIA_IKBD_Read_RDR ( void ) ! 571: { ! 572: ACIA_AddWaitCycles (); /* Additional cycles when accessing the ACIA */ ! 573: ! 574: IoMem[0xfffc02] = ACIA_Read_RDR ( pACIA_IKBD ); ! 575: ! 576: if (LOG_TRACE_LEVEL(TRACE_IKBD_ACIA)) ! 577: { ! 578: int FrameCycles, HblCounterVideo, LineCycles; ! 579: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 580: LOG_TRACE_PRINT("acia %s read fffc02 rdr=0x%02x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", pACIA_IKBD->ACIA_Name , ! 581: IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); ! 582: } ! 583: } ! 584: ! 585: ! 586: ! 587: ! 588: /*-----------------------------------------------------------------------*/ ! 589: /** ! 590: * Write to CR in the IKBD's ACIA (0xfffc00) ! 591: */ ! 592: void ACIA_IKBD_Write_CR ( void ) ! 593: { ! 594: int FrameCycles, HblCounterVideo, LineCycles; ! 595: ! 596: ACIA_AddWaitCycles (); /* Additional cycles when accessing the ACIA */ ! 597: ! 598: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 599: LOG_TRACE(TRACE_IKBD_ACIA, "acia %s write fffc00 cr=0x%02x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", pACIA_IKBD->ACIA_Name , ! 600: IoMem[0xfffc00], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); ! 601: ! 602: ACIA_Write_CR ( pACIA_IKBD , IoMem[0xfffc00] ); ! 603: } ! 604: ! 605: ! 606: ! 607: ! 608: /*-----------------------------------------------------------------------*/ ! 609: /** ! 610: * Write to TDR in the IKBD's ACIA (0xfffc02) : send a byte to the IKBD ! 611: */ ! 612: void ACIA_IKBD_Write_TDR ( void ) ! 613: { ! 614: int FrameCycles, HblCounterVideo, LineCycles; ! 615: ! 616: ACIA_AddWaitCycles (); /* Additional cycles when accessing the ACIA */ ! 617: ! 618: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 619: LOG_TRACE(TRACE_IKBD_ACIA, "acia %s write fffc02 tdr=0x%02x video_cyc=%d %d@%d pc=%x instr_cycle %d\n", pACIA_IKBD->ACIA_Name , ! 620: IoMem[0xfffc02], FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); ! 621: ! 622: ACIA_Write_TDR ( pACIA_IKBD , IoMem[0xfffc02] ); ! 623: } ! 624: ! 625: ! 626: ! 627: ! 628: /*----------------------------------------------------------------------*/ ! 629: /* The part below is the real core of the 6850's emulation. */ ! 630: /* */ ! 631: /* This core is not correlated to any specific machine. All the specific*/ ! 632: /* code between the 6850 and the rest of Hatari is called through some */ ! 633: /* callback functions (see above). */ ! 634: /*----------------------------------------------------------------------*/ ! 635: ! 636: ! 637: ! 638: /*-----------------------------------------------------------------------*/ ! 639: /** ! 640: * Reset an ACIA. ! 641: * There's no RESET pin on the MC6850, so the only way to reset the ACIA ! 642: * is to set bit 0 an 1 to 0x03 in the CR to force a master reset. ! 643: * This will clear SR (except CTS and DCD) and halt/initialize both the ! 644: * receiver and transmitter. ! 645: * This also returns the new state of the RTS bit, that must be updated ! 646: * in ACIA_Write_CR. ! 647: */ ! 648: static Uint8 ACIA_MasterReset ( ACIA_STRUCT *pACIA , Uint8 CR ) ! 649: { ! 650: Uint8 dcd_bit; ! 651: Uint8 cts_bit; ! 652: Uint8 rts_bit; ! 653: ! 654: ! 655: LOG_TRACE ( TRACE_ACIA, "acia %s master reset VBL=%d HBL=%d\n" , pACIA->ACIA_Name , nVBLs , nHBL ); ! 656: ! 657: dcd_bit = pACIA->Get_Line_DCD (); ! 658: cts_bit = pACIA->Get_Line_CTS (); ! 659: ! 660: pACIA->SR = ACIA_SR_BIT_TDRE | ( dcd_bit << 2 ) | ( cts_bit << 3 ); ! 661: ! 662: pACIA->TX_State = ACIA_STATE_IDLE; ! 663: pACIA->TSR = 0; ! 664: pACIA->TX_Size = 0; ! 665: pACIA->TX_SendBrk = 0; ! 666: ! 667: pACIA->RX_State = ACIA_STATE_IDLE; ! 668: pACIA->RSR = 0; ! 669: pACIA->RX_Size = 0; ! 670: pACIA->RX_Overrun = 0; ! 671: ! 672: /* On Master Reset, IRQ line is high */ ! 673: /* If it's the 1st reset, RTS should be high, else RTS depends on CR bit 5 and 6 */ ! 674: pACIA->Set_Line_IRQ ( 1 ); /* IRQ line goes high */ ! 675: if ( pACIA->FirstMasterReset == 1 ) ! 676: { ! 677: pACIA->FirstMasterReset = 0; ! 678: rts_bit = 1; /* RTS line goes high */ ! 679: } ! 680: else ! 681: rts_bit = ( ACIA_CR_TRANSMITTER_CONTROL ( CR ) == 0x02 ) ? 1 : 0; ! 682: ! 683: return rts_bit; ! 684: } ! 685: ! 686: ! 687: ! 688: ! 689: /*-----------------------------------------------------------------------*/ ! 690: /** ! 691: * Check if the IRQ must be changed in SR. ! 692: * When there's a change, we must change the IRQ line too. ! 693: */ ! 694: static void ACIA_UpdateIRQ ( ACIA_STRUCT *pACIA ) ! 695: { ! 696: Uint8 irq_bit_new; ! 697: ! 698: irq_bit_new = 0; ! 699: ! 700: if ( ACIA_CR_RECEIVE_INTERRUPT_ENABLE ( pACIA->CR ) /* Check for RX causes of interrupt */ ! 701: && ( ( pACIA->SR & ( ACIA_SR_BIT_RDRF | ACIA_SR_BIT_DCD ) ) ! 702: || ( pACIA->RX_Overrun ) ) ) ! 703: irq_bit_new = ACIA_SR_BIT_IRQ; ! 704: ! 705: if ( pACIA->TX_EnableInt /* Check for TX causes of interrupt */ ! 706: && ( pACIA->SR & ACIA_SR_BIT_TDRE ) ! 707: && ( ( pACIA->SR & ACIA_SR_BIT_CTS ) == 0 ) ) ! 708: irq_bit_new = ACIA_SR_BIT_IRQ; ! 709: ! 710: /* Update SR and IRQ line if a change happened */ ! 711: if ( ( pACIA->SR & ACIA_SR_BIT_IRQ ) != irq_bit_new ) ! 712: { ! 713: LOG_TRACE ( TRACE_ACIA, "acia %s update irq irq_new=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , irq_bit_new?1:0 , nVBLs , nHBL ); ! 714: ! 715: if ( irq_bit_new ) ! 716: { ! 717: pACIA->SR |= ACIA_SR_BIT_IRQ; /* Set IRQ bit */ ! 718: pACIA->Set_Line_IRQ ( 0 ); /* IRQ line goes low */ ! 719: } ! 720: else ! 721: { ! 722: pACIA->SR &= ~ACIA_SR_BIT_IRQ; /* Clear IRQ bit */ ! 723: pACIA->Set_Line_IRQ ( 1 ); /* IRQ line goes high */ ! 724: } ! 725: } ! 726: } ! 727: ! 728: ! 729: ! 730: /*-----------------------------------------------------------------------*/ ! 731: /** ! 732: * Read SR. ! 733: * Also update CTS ; when CTS is high, TDRE should always be masked to 0. ! 734: */ ! 735: static Uint8 ACIA_Read_SR ( ACIA_STRUCT *pACIA ) ! 736: { ! 737: Uint8 SR; ! 738: ! 739: ! 740: if ( pACIA->Get_Line_CTS() == 1 ) ! 741: pACIA->SR |= ACIA_SR_BIT_CTS; ! 742: else ! 743: pACIA->SR &= ~ACIA_SR_BIT_CTS; ! 744: ! 745: SR = pACIA->SR; ! 746: pACIA->SR_Read = 1; /* Used in ACIA_Read_RDR to clear Overrun and DCD IRQ */ ! 747: ! 748: if ( SR & ACIA_SR_BIT_CTS ) ! 749: SR &= ~ACIA_SR_BIT_TDRE; /* Inhibit TDRE when CTS is set */ ! 750: ! 751: LOG_TRACE ( TRACE_ACIA, "acia %s read sr data=0x%02x VBL=%d HBL=%d\n" , pACIA->ACIA_Name , SR , nVBLs , nHBL ); ! 752: ! 753: return SR; ! 754: } ! 755: ! 756: ! 757: ! 758: ! 759: /*-----------------------------------------------------------------------*/ ! 760: /** ! 761: * Write to CR. ! 762: */ ! 763: static void ACIA_Write_CR ( ACIA_STRUCT *pACIA , Uint8 CR ) ! 764: { ! 765: int Divide; ! 766: int Force_rts_bit; ! 767: Uint8 rts_bit=0; ! 768: ! 769: LOG_TRACE ( TRACE_ACIA, "acia %s write cr data=0x%02x VBL=%d HBL=%d\n" , pACIA->ACIA_Name , CR , nVBLs , nHBL ); ! 770: ! 771: /* Bit 0 and 1 : Counter Divide */ ! 772: Divide = ACIA_CR_COUNTER_DIVIDE ( CR ); ! 773: if ( Divide == 0x03 ) ! 774: { ! 775: Force_rts_bit = ACIA_MasterReset ( pACIA , CR ); /* Special behaviour for RTS after a master reset */ ! 776: } ! 777: else ! 778: { ! 779: if ( ACIA_CR_COUNTER_DIVIDE ( CR ) != ACIA_CR_COUNTER_DIVIDE ( pACIA->CR ) ) ! 780: { ! 781: pACIA->Clock_Divider = ACIA_Counter_Divide[ Divide ]; ! 782: pACIA->Set_Timers ( pACIA ); /* Set a timer at the baud rate computed from Clock_Divider */ ! 783: } ! 784: Force_rts_bit = -1; /* Don't force RTS bit, use bit 5/6 in CR */ ! 785: } ! 786: ! 787: /* Bits 2, 3 and 4 : word select */ ! 788: /* Don't do anything here, see ACIA_Prepare_TX and ACIA_Prepare_RX */ ! 789: ! 790: /* Bits 5 and 6 : transmitter control */ ! 791: pACIA->TX_EnableInt = 0; ! 792: pACIA->TX_SendBrk = 0; ! 793: switch ( ACIA_CR_TRANSMITTER_CONTROL ( CR ) ) ! 794: { ! 795: case 0x00 : ! 796: rts_bit = 0; ! 797: break; ! 798: case 0x01 : ! 799: rts_bit = 0; ! 800: pACIA->TX_EnableInt = 1; ! 801: break; ! 802: case 0x02 : ! 803: rts_bit = 1; ! 804: break; ! 805: case 0x03 : ! 806: rts_bit = 0; ! 807: pACIA->TX_SendBrk = 1; /* We will send break bit until CR is changed */ ! 808: break; ! 809: } ! 810: ! 811: if ( Force_rts_bit >= 0 ) ! 812: rts_bit = Force_rts_bit; /* Use the value from ACIA_MasterReset */ ! 813: pACIA->Set_Line_RTS ( rts_bit ); ! 814: ! 815: /* Bits 7 : receive interrupt enable, see ACIA_UpdateIRQ */ ! 816: ! 817: pACIA->CR = CR; ! 818: ! 819: ACIA_UpdateIRQ ( pACIA ); ! 820: } ! 821: ! 822: ! 823: ! 824: ! 825: /*-----------------------------------------------------------------------*/ ! 826: /** ! 827: * Read RDR. This will clear RDRF and PE. ! 828: * - OVRN / DCD bits are cleared if SR was read before reading RDR. ! 829: * - OVRN bit is set only when reading RDR, not when the actual overrun happened ! 830: * during ACIA_Clock_RX. ! 831: * - IRQ bit should be updated depending on the new values of BIT_RDRF, ! 832: * BIT_DCD and BIT_OVRN. ! 833: */ ! 834: static Uint8 ACIA_Read_RDR ( ACIA_STRUCT *pACIA ) ! 835: { ! 836: pACIA->SR &= ~( ACIA_SR_BIT_RDRF | ACIA_SR_BIT_PE ); ! 837: ! 838: /* If we read RDR after reading SR, we clear OVRN / DCD bits */ ! 839: if ( pACIA->SR_Read == 1 ) ! 840: { ! 841: pACIA->SR_Read = 0; ! 842: pACIA->SR &= ~( ACIA_SR_BIT_DCD | ACIA_SR_BIT_OVRN ); ! 843: if ( pACIA->Get_Line_DCD () == 1 ) ! 844: pACIA->SR |= ACIA_SR_BIT_DCD; ! 845: } ! 846: ! 847: if ( pACIA->RX_Overrun ) ! 848: { ! 849: pACIA->SR |= ACIA_SR_BIT_OVRN; ! 850: pACIA->RX_Overrun = 0; ! 851: } ! 852: ! 853: ACIA_UpdateIRQ ( pACIA ); ! 854: ! 855: LOG_TRACE ( TRACE_ACIA, "acia %s read rdr data=0x%02x new sr=0x%02x overrun=%s VBL=%d HBL=%d\n" , pACIA->ACIA_Name , pACIA->RDR , ! 856: pACIA->SR , ( pACIA->SR & ACIA_SR_BIT_OVRN ) ? "yes" : "no" , nVBLs , nHBL ); ! 857: ! 858: return pACIA->RDR; ! 859: } ! 860: ! 861: ! 862: ! 863: ! 864: /*-----------------------------------------------------------------------*/ ! 865: /** ! 866: * Write to TDR. ! 867: * If the TX process is idle, we should not prepare a new transfer ! 868: * immediately, to ensure that BIT_TDRE remains clear until the next bit ! 869: * is sent (BIT_TDRE will be set again in ACIA_Clock_TX). ! 870: */ ! 871: static void ACIA_Write_TDR ( ACIA_STRUCT *pACIA , Uint8 TDR ) ! 872: { ! 873: LOG_TRACE ( TRACE_ACIA, "acia %s write tdr data=0x%02x overwrite=%s tx_state=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , TDR , ! 874: ( pACIA->SR & ACIA_SR_BIT_TDRE ) ? "no" : "yes" , pACIA->TX_State , nVBLs , nHBL ); ! 875: ! 876: pACIA->TDR = TDR; ! 877: pACIA->SR &= ~ACIA_SR_BIT_TDRE; /* TDR is not empty anymore */ ! 878: ! 879: ACIA_UpdateIRQ ( pACIA ); ! 880: } ! 881: ! 882: ! 883: ! 884: ! 885: /*-----------------------------------------------------------------------*/ ! 886: /** ! 887: * Prepare a new transfer. Copy TDR to TSR and initialize parity, data size ! 888: * and stop bits. ! 889: * Transfer will then start at the next call of ACIA_Clock_TX ! 890: */ ! 891: static void ACIA_Prepare_TX ( ACIA_STRUCT *pACIA ) ! 892: { ! 893: pACIA->TSR = pACIA->TDR; ! 894: pACIA->TX_Parity = 0; ! 895: pACIA->TX_Size = ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].DataBits; ! 896: pACIA->TX_StopBits = ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].StopBits; ! 897: ! 898: pACIA->SR |= ACIA_SR_BIT_TDRE; /* TDR was copied to TSR. TDR is now empty */ ! 899: ! 900: LOG_TRACE ( TRACE_ACIA, "acia %s prepare tx tsr=0x%02x size=%d stop=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , pACIA->TSR , ! 901: pACIA->TX_Size , pACIA->TX_StopBits , nVBLs , nHBL ); ! 902: } ! 903: ! 904: ! 905: ! 906: ! 907: /*-----------------------------------------------------------------------*/ ! 908: /** ! 909: * Prepare a new reception. Initialize parity, data size and stop bits. ! 910: */ ! 911: static void ACIA_Prepare_RX ( ACIA_STRUCT *pACIA ) ! 912: { ! 913: pACIA->RSR = 0; ! 914: pACIA->RX_Parity = 0; ! 915: pACIA->RX_Size = ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].DataBits; ! 916: pACIA->RX_StopBits = ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].StopBits; ! 917: ! 918: LOG_TRACE ( TRACE_ACIA, "acia %s prepare rx size=%d stop=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , ! 919: pACIA->RX_Size , pACIA->RX_StopBits , nVBLs , nHBL ); ! 920: } ! 921: ! 922: ! 923: ! 924: ! 925: /*-----------------------------------------------------------------------*/ ! 926: /** ! 927: * Write a new bit on the TX line each time the TX clock expires. ! 928: * This will send TDR over the serial line, using TSR, with additional ! 929: * parity and start/stop bits. ! 930: * We send bit 0 of TSR, then TSR is shifted to the right. ! 931: */ ! 932: static void ACIA_Clock_TX ( ACIA_STRUCT *pACIA ) ! 933: { ! 934: int StateNext; ! 935: Uint8 tx_bit; ! 936: ! 937: ! 938: LOG_TRACE ( TRACE_ACIA, "acia %s clock_tx tx_state=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , pACIA->TX_State , nVBLs , nHBL ); ! 939: ! 940: StateNext = -1; ! 941: switch ( pACIA->TX_State ) ! 942: { ! 943: case ACIA_STATE_IDLE : ! 944: if ( pACIA->TX_SendBrk ) ! 945: { ! 946: pACIA->Set_Line_TX ( 0 ); /* Send 1 break bit */ ! 947: break; ! 948: } ! 949: ! 950: /* If TDR is not empty when we are in idle state, */ ! 951: /* this means we have a new byte to send */ ! 952: if ( ( pACIA->SR & ACIA_SR_BIT_TDRE ) == 0 ) ! 953: ACIA_Prepare_TX ( pACIA ); ! 954: ! 955: if ( pACIA->TX_Size == 0 ) /* TSR is empty */ ! 956: pACIA->Set_Line_TX ( 1 ); /* Send stop bits when idle */ ! 957: ! 958: else /* TSR has some new bits to transfer */ ! 959: { ! 960: pACIA->Set_Line_TX ( 0 ); /* Send 1 start bit */ ! 961: StateNext = ACIA_STATE_DATA_BIT; ! 962: } ! 963: break; ! 964: ! 965: case ACIA_STATE_DATA_BIT : ! 966: tx_bit = pACIA->TSR & 1; /* New bit to send */ ! 967: pACIA->Set_Line_TX ( tx_bit ); ! 968: pACIA->TX_Parity ^= tx_bit; ! 969: pACIA->TSR >>= 1; ! 970: pACIA->TX_Size--; ! 971: ! 972: if ( pACIA->TX_Size == 0 ) ! 973: { ! 974: if ( ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].Parity != ACIA_PARITY_NONE ) ! 975: StateNext = ACIA_STATE_PARITY_BIT; ! 976: else ! 977: StateNext = ACIA_STATE_STOP_BIT; /* No parity */ ! 978: } ! 979: break; ! 980: ! 981: case ACIA_STATE_PARITY_BIT : ! 982: if ( ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].Parity == ACIA_PARITY_EVEN ) ! 983: pACIA->Set_Line_TX ( pACIA->TX_Parity ); ! 984: else ! 985: pACIA->Set_Line_TX ( ( ~pACIA->TX_Parity ) & 1 ); ! 986: ! 987: StateNext = ACIA_STATE_STOP_BIT; ! 988: break; ! 989: ! 990: case ACIA_STATE_STOP_BIT : ! 991: pACIA->Set_Line_TX ( 1 ); /* Send 1 stop bit */ ! 992: pACIA->TX_StopBits--; ! 993: ! 994: if ( pACIA->TX_StopBits == 0 ) /* All stop bits were sent : transfer is complete */ ! 995: { ! 996: StateNext = ACIA_STATE_IDLE; /* Go to idle state to see if a new TDR need to be sent */ ! 997: } ! 998: break; ! 999: } ! 1000: ! 1001: ACIA_UpdateIRQ ( pACIA ); ! 1002: ! 1003: if ( StateNext >= 0 ) ! 1004: pACIA->TX_State = StateNext; /* Go to a new state */ ! 1005: } ! 1006: ! 1007: ! 1008: ! 1009: ! 1010: /*-----------------------------------------------------------------------*/ ! 1011: /** ! 1012: * Handle a new bit on the RX line each time the RX clock expires. ! 1013: * This will fill RDR with bits received from the serial line, using RSR. ! 1014: * Incoming bits are stored in bit 7 of RSR, then RSR is shifted to the right. ! 1015: */ ! 1016: static void ACIA_Clock_RX ( ACIA_STRUCT *pACIA ) ! 1017: { ! 1018: int StateNext; ! 1019: Uint8 rx_bit; ! 1020: ! 1021: ! 1022: rx_bit = pACIA->Get_Line_RX(); ! 1023: ! 1024: LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx rx_state=%d bit=%d VBL=%d HBL=%d\n" , pACIA->ACIA_Name , pACIA->RX_State , rx_bit , nVBLs , nHBL ); ! 1025: ! 1026: StateNext = -1; ! 1027: switch ( pACIA->RX_State ) ! 1028: { ! 1029: case ACIA_STATE_IDLE : ! 1030: if ( rx_bit == 0 ) /* Receive 1 start bit */ ! 1031: { ! 1032: ACIA_Prepare_RX ( pACIA ); ! 1033: StateNext = ACIA_STATE_DATA_BIT; ! 1034: } ! 1035: break; /* If no start bit, we stay in idle state */ ! 1036: ! 1037: case ACIA_STATE_DATA_BIT : ! 1038: if ( rx_bit ) ! 1039: pACIA->RSR |= 0x80; ! 1040: pACIA->RX_Parity ^= rx_bit; ! 1041: pACIA->RX_Size--; ! 1042: ! 1043: if ( pACIA->RX_Size > 0 ) /* All bits were not received yet */ ! 1044: { ! 1045: pACIA->RSR >>= 1; ! 1046: } ! 1047: else ! 1048: { ! 1049: // [NP] : MC6850 doc is not very clear "the overrun condition begins at the midpoint of the last bit ! 1050: // of the second character received [...]". Is it the last bit of the data word, or the stop bit ? ! 1051: // It makes more sense to check for overrun after the stop bit, when RSR should be copied to RDR, ! 1052: // because RDR could be read between the last data bit and the stop bit, so RX_Overrun and ! 1053: // ACIA_SR_BIT_OVRN would need to be cancelled. ! 1054: // if ( pACIA->SR & ACIA_SR_BIT_RDRF ) ! 1055: // { ! 1056: // LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx overrun rsr=0x%02x VBL=%d HBL=%d\n" , ! 1057: // pACIA->ACIA_Name , pACIA->RSR , nVBLs , nHBL ); ! 1058: // pACIA->RX_Overrun = 1; /* Bit in SR will be set when reading RDR */ ! 1059: // } ! 1060: if ( ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].Parity != ACIA_PARITY_NONE ) ! 1061: StateNext = ACIA_STATE_PARITY_BIT; ! 1062: else ! 1063: StateNext = ACIA_STATE_STOP_BIT; /* No parity */ ! 1064: } ! 1065: break; ! 1066: ! 1067: case ACIA_STATE_PARITY_BIT : ! 1068: if ( ( ACIA_Serial_Params[ ACIA_CR_WORD_SELECT ( pACIA->CR ) ].Parity == ACIA_PARITY_EVEN ) ! 1069: && ( pACIA->RX_Parity != rx_bit ) ) ! 1070: pACIA->SR |= ACIA_SR_BIT_PE; ! 1071: ! 1072: else if ( pACIA->RX_Parity == rx_bit ) /* Odd parity */ ! 1073: pACIA->SR |= ACIA_SR_BIT_PE; ! 1074: ! 1075: if ( pACIA->SR & ACIA_SR_BIT_PE ) ! 1076: LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx parity error VBL=%d HBL=%d\n" , pACIA->ACIA_Name , nVBLs , nHBL ); ! 1077: ! 1078: StateNext = ACIA_STATE_STOP_BIT; ! 1079: break; ! 1080: ! 1081: case ACIA_STATE_STOP_BIT : ! 1082: if ( rx_bit == 1 ) /* Wait for 1 or 2 "1" stop bits */ ! 1083: { ! 1084: pACIA->RX_StopBits--; ! 1085: if ( pACIA->RX_StopBits == 0 ) /* All stop bits were received : reception is complete */ ! 1086: { ! 1087: pACIA->SR &= ~ACIA_SR_BIT_FE; ! 1088: ! 1089: if ( ( pACIA->SR & ACIA_SR_BIT_RDRF ) == 0 ) ! 1090: { ! 1091: pACIA->RDR = pACIA->RSR; ! 1092: pACIA->SR |= ACIA_SR_BIT_RDRF; ! 1093: LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx received rdr=0x%02x VBL=%d HBL=%d\n" , ! 1094: pACIA->ACIA_Name , pACIA->RDR , nVBLs , nHBL ); ! 1095: } ! 1096: else ! 1097: { ! 1098: LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx overrun rsr=0x%02x unread rdr=0x%02x VBL=%d HBL=%d\n" , ! 1099: pACIA->ACIA_Name , pACIA->RSR , pACIA->RDR , nVBLs , nHBL ); ! 1100: pACIA->RX_Overrun = 1; /* Bit in SR will be set when reading RDR */ ! 1101: } ! 1102: StateNext = ACIA_STATE_IDLE; /* Go to idle state and wait for start bit */ ! 1103: } ! 1104: } ! 1105: else /* Not a valid stop bit */ ! 1106: { ! 1107: LOG_TRACE ( TRACE_ACIA, "acia %s clock_rx framing error VBL=%d HBL=%d\n" , pACIA->ACIA_Name , nVBLs , nHBL ); ! 1108: ! 1109: /* According to the A6850 doc, RSR is copied to RDR in case of a framing error */ ! 1110: /* (Should be the same for the MC6850 ?) */ ! 1111: pACIA->SR |= ACIA_SR_BIT_FE; ! 1112: pACIA->RDR = pACIA->RSR; ! 1113: StateNext = ACIA_STATE_IDLE; /* Go to idle state and wait for start bit */ ! 1114: } ! 1115: break; ! 1116: } ! 1117: ! 1118: ACIA_UpdateIRQ ( pACIA ); ! 1119: ! 1120: if ( StateNext >= 0 ) ! 1121: pACIA->RX_State = StateNext; /* Go to a new state */ ! 1122: } ! 1123: ! 1124: ! 1125:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.