{ File: BisyncInterrupts.asm Modification History: Chuck Fay : 11-Nov-82 9:39:35: Move POPs before EIs to avoid possible stack overflow. Jim Frandeen : May 20, 1982 6:53 PM Jim Frandeen : May 6, 1982 9:49 AM: Created file. } Get "SysDefs" Get "RS232CDefs" IMP CurrentSyncCharacter ;From RS232CMisc IMP IllegalBisyncCharacterFlag ;From RS232CPut IMP PutCompletedFlag ;From RS232CPut IMP RestartSIOCharacter ;From RS232CPut IMP SetBisyncCompletion ;From BisyncInput IMP StatusChangeFlag ;From RS232CGet IMP TerminateBisyncFrame ;From BisyncInput IMP TxBufferPointer ;From RS232CInterrupts IMP TxUnderrunDetectedFlag ;From RS232CInterrupts IMP TxWR5 ;From RS232CMisc EXP BisyncRS232CInterrupt EXP BEL1 EXP DisableTxCRC1 EXP DisableTxCRC2 EXP DisableTxCRC3 EXP DisableTxCRC4 EXP DisableTxCRC5 EXP DisableTxCRC6 EXP DisableTxCRC7 EXP EnableTxCRC1 EXP EnableTxCRC2 EXP EnableTxCRC3 EXP EnableTxCRC4 EXP EnableTxCRC5 EXP ENQ1 EXP ENQ2 EXP ENQ4 EXP ENQ12 EXP EOT1 EXP ETB2 EXP ETB4 EXP ETB5 EXP ETB6 EXP ETB12 EXP NAK1 EXP PrevBisyncDCD EXP SYN1 EXP SYN2 EXP SYN3 EXP SYN4 EXP SYN5 EXP SYN6 EXP SYN12 EXP OneSecondTimerLow EXP OneSecondTimerHigh EXP RxBisyncExternalInt EXP RxBisyncSpecialInt EXP SyncCharacterCount EXP TxBisyncInitial EXP TxBisyncStateSwitch ; {NOTE: These routines are written for speed. Much code has been duplicated. If necessary, space could be saved by making the exit code common. The following characters are used in Bisync mode. Characters marked with an asterisk are the same in Ascii and Ebcdic. Other characters are different depending on the character set. Characters that differ are initialized by Misc. AltoETX* Alto ETX so that Dandelions can talk to Altos. BEL is a special 860 character used to change to voice mode. It has meaning when it appears at the beginning of a frame. In the middle of a frame, it is treated as data. DLE* Data Link Escape is used for two character sequences. ENQ Enquiry is used to bid for the line when using point to point connections. It indicates the end of a selection sequence. It is also used to request retransmission of the ACK/NAK response. EOT End of Transmission indicates the end of a message which may contain a number of blocks. ETB End of Transmission Block indicates the end of a block of characters that started with SOH or STX and indicates that the block check is coming next. ETX* End of Text terminates a block which started with SOH or STX. It is the same as ETB except that it also means that there are no more data blocks to be sent. ITB* End of Intermediate Transmission Block is used to separate the message into sections for error detection purposes. ITB indicates that the block check is coming next. NAK Negative Acknowledgement indicates that the previous block was received in error. SOH* Start of Heading STX* Start of Text SYN Sync character } ; BisyncRS232CInterrupt: { Come here in Bisync mode from Common when we get a RST 6.5 Interrupt from the Zilog SIO chip. Save state } PUSH PSW PUSH H {Read the interruptVector to determine the cause of the interrupt. Multiply the vector by 2. This gives us a number which we can OR into the low bits of the jump table address. The jump table is in the Common so that we can assure its exact address and guarantee that the low 5 bits of the address are zero. } MVI A,PointToWR2 OUT TxCont IN TxCont ; Read Interrupt Vector {Test for TxDataInt first. We want to call this routine so that we can also call it from the input end of frame routine if necessary.} ORA A DB opJZ TxBisyncStateSwitch: DW TxBisyncInitial DispatchOnBisyncInterruptVector: RLC ;Interupt Vector * 2 ORI 40H ;Low address is 40H MOV L,A MVI H,20H ;High address is 20H PCHL ;Jump to JumpTable {BisyncJumpTable: @2040H JMP TxIllegalInt ;When Vecter =0 Tx Buffer Empty DB 0 JMP TxBisyncExternalInt ;When Vecter =2 Ex Stat DB 0 JMP TxIllegalInt ;When Vecter =4 Tx Char DB 0 JMP ExitInterrupt ;When Vecter =6 Sp Tx Cond DB 0 JMP RxIllegalInt ;When Vecter =8 Tx Buffer Empty DB 0 JMP RxBisyncExternalInt ;When Vecter =A Ex Stat DB 0 DB opJMP ;When Vecter =C Rx Char RxBisyncStateSwitch: DW RxBisyncInitial DB 0 JMP RxBisyncSpecialInt ;When Vecter =E Sp Rx Cond DB 0 } ; TxBisyncInitial: {Come here to initialize the transmitter. We sent one ModemSYN character (alternate ones and zeros) to prime the transmitter. We send two more ModemSYN characters in this state.} MVI A,ModemSYN OUT TxData {Turn on the one second timer (i8253 Programmable Interval Timer Counter # 2).} MVI A,TimeCMD OUT OSCCont DB opMVIA ;A ← OneSecondTimerLow OneSecondTimerLow: DB 0 OUT TimeReg DB opMVIA ;A ← OneSecondTimerHigh OneSecondTimerHigh: DB 0 OUT TimeReg LXI H,TxInitial1 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TxInitial1: {We sent one ModemSYN character to prime the transmitter and one more ModemSYN character. Send one more ModemSYN character.} MVI A,ModemSYN OUT TxData {Initialize WR6 and WR7 with the current sync character. These characters will be sent by the chip automatically whenever we get transmit underrun.} LXI H,8000H+TxCont MVI M,PointToWR6 LDA CurrentSyncCharacter MOV M,A MVI M,PointToWR7+ResetTxCRCGenerator MOV M,A LXI H,SendSyncCharacters SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET SendSyncCharacters: {We send the number of Sync Characters specified by the client.} LDA CurrentSyncCharacter OUT TxData DB opMVIA ;A ← SyncCharacterCount SyncCharacterCount: DB 0 DCR A ;Decrement SyncCharacterCount JZ SyncCharactersSent STA SyncCharacterCount POP H POP PSW EI ;Enable Interrupts RET SyncCharactersSent: LXI H,StartTx SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; StartTx: {This is the first Transmit state. We have sent the initial characters, and we are looking for SOH or STX. Send the next character from the client's buffer. The CRC generator is not turned on, and the next character sent will not be included in the CRC.} LHLD TxBufferPointer MOV A,M OUT TxData ;Send the next character INX H SHLD TxBufferPointer CPI ETX JZ TxEndingCRCNext CPI STX JZ FirstTxCharIsSTX CPI SOH JZ FirstTxCharIsSOH CPI DLE JZ FirstTxCharIsDLE DB opCPI EOT1: DB 0 JZ TxEndOfFrameNext DB opCPI BEL1: DB 0 JZ TxEndOfFrameNext DB opCPI NAK1: DB 0 JZ TxEndOfFrameNext DB opCPI ENQ1: DB 0 JZ TxEndOfFrameNext {Continue if the character is not any of the above. We stay in this state.} POP H POP PSW EI ;Enable Interrupts RET ; TxHeaderSyn: {Come here if we got a SYN character in the header. The SYN character does not get included in the checksum, so we must turn off the CRC generator.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM DisableTxCRC1: DB 0 OUT TxData ;Send the next character {The next time we get a TxData interrupt, we want to turn the CRC generator back on.} FirstTxCharIsSOH: LXI H,StartTxHeader SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET StartTxHeader: LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer DB opCPI SYN5: DB 0 JZ StartHeaderSyn {We are about to send the first Header character following SOH. Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM EnableTxCRC1: DB 0 OUT TxData ;Send the next character CPI STX JZ ContinueTxNonTransparentMode CPI DLE JZ LookForSTXAfterTxDLE CPI ETX JZ TxEndingCRCNext DB opCPI ETB5: DB 0 JZ TxEndingCRCNext {Continue if the character is not any of the above. Pass to TxHeader state.} LXI H,TxHeader SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET StartHeaderSyn: {Come here if we got a SYN character in the header. The SYN character does not get included in the checksum.} OUT TxData ;Send the next character POP H POP PSW EI ;Enable Interrupts RET TxHeader: {We are sending header characters. The CRC generator is on. The next character will be included in the CRC unless we turn off the CRC checker.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer DB opCPI SYN6: DB 0 JZ TxHeaderSyn OUT TxData ;Send the next character CPI STX JZ ContinueTxNonTransparentMode CPI DLE JZ LookForSTXAfterTxDLE CPI ETX JZ TxEndingCRCNext DB opCPI ETB6: DB 0 JZ TxEndingCRCNext {Continue if the character is not any of the above. Stay in this state.} POP H POP PSW EI ;Enable Interrupts RET ; TxNonTransparentModeSYN: {Come here if we got a SYN character in non transparent mode. The SYN character does not get included in the checksum, so we must turn off the CRC generator.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM DisableTxCRC2: DB 0 OUT TxData ;Send the next character {The next time we get a TxData interrupt, we want to turn the CRC generator back on.} FirstTxCharIsSTX: LXI H,StartTxNonTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET StartTxNonTransparentMode: {We are about to send the first character in NonTransparent Mode, or we are continuing after a one second timeout or a SYN character. The CRC generator is off.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer DB opCPI SYN2: DB 0 JZ StartNonTransparentModeSYN {Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM EnableTxCRC2: DB 0 OUT TxData ;Send the next character CPI ETX JZ TxEndingCRCNext DB opCPI ETB2: DB 0 JZ TxEndingCRCNext CPI ITB JZ TxInterBlockCRCNext DB opCPI ENQ2: DB 0 JZ TxEndOfFrameNext {Continue if the character is not any of the above. We pass to NonTransparent Mode.} ContinueTxNonTransparentMode: LXI H,TxNonTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET StartNonTransparentModeSYN: {Come here if we got a SYN character in non transparent mode. The SYN character does not get included in the checksum.} OUT TxData ;Send the next character POP H POP PSW EI ;Enable Interrupts RET ; TxNonTransparentMode: {We are sending characters in NonTransparent mode. The CRC generator is on.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer DB opCPI SYN12: DB 0 JZ TxNonTransparentModeSYN OUT TxData ;Send the next character CPI ETX JZ TxEndingCRCNext DB opCPI ETB12: DB 0 JZ TxEndingCRCNext CPI ITB JZ TxInterBlockCRCNext DB opCPI ENQ12: DB 0 JZ TxEndOfFrameNext {Continue if the character is not any of the above. We stay in NonTransparent Mode. Check the timer to see if one second has elapsed since we started sending.} IN RS366Reg ANI TimeUp JNZ ExitTxDataInt ;Enable Interrupts {The one second timer has expired. We must send two sync characters.} LXI H,NonTransparentModeTimeout1 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; NonTransparentModeTimeout1: {Come here to send the first sync character after a one second timeout. The sync character does not get included in the checksum, so we must turn off the CRC generator.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM DisableTxCRC3: DB 0 LDA CurrentSyncCharacter OUT TxData LXI H,NonTransparentModeTimeout2 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET NonTransparentModeTimeout2: {Come here to send the second sync character after a one second timeout. Turn the timer back on.} LDA CurrentSyncCharacter OUT TxData MVI A,TimeCMD OUT OSCCont LDA OneSecondTimerLow OUT TimeReg LDA OneSecondTimerHigh OUT TimeReg LXI H,StartTxNonTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; TxInterBlockCRCNext: {Come here when we have just sent an ITB character. The next time we get an interrupt for Transmit Buffer Empty, we will simply clear the interrupt. This will cause the CRC to be sent if we reset the Transmit Underrun/EOM bit.} MVI A,ResetTxEOM OUT TxCont LXI H,TxInterBlockCRC SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TxInterBlockCRC: {Send the InterBlock CRC. Set SendSyncFlag for the Put routine. We will never get another wakeup unless the Put routine primes the chip again by sending a sync character. Disable the CRC generator so that the Sync character will not be included in the CRC.} LXI H,8000H+TxCont MVI M,PointToWR5+ResetTxIntPending DB opMVIM DisableTxCRC4: DB 0 LDA CurrentSyncCharacter STA RestartSIOCharacter LXI H,ContinueAfterTxInterBlockCRC SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ContinueAfterTxInterBlockCRC: {Continue here when the CRC has been sent following the ITB character. Start sending data again. The CRC generator is off.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer DB opCPI SYN3: DB 0 JZ TxInterBlockSYN LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM EnableTxCRC3: DB 0 OUT TxData ;Send the next character CPI DLE JZ LookForSTXAfterTxDLE {Continue if the character is not any of the above. We go back to Non Transparent state.} LXI H,TxNonTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TxInterBlockSYN: {Come here if we got a SYN character following the ITB character. The SYN character does not get included in the checksum.} OUT TxData ;Send the next character POP H POP PSW EI ;Enable Interrupts RET ; FirstTxCharIsDLE: {Come here if the first Tx character is DLE. Look for STX to enter transparent mode. Any other character will be EndOfFrame. The CRC generator is off. The STX is NOT included in the checksum.} LXI H,LookForSTXAfterFirstTxDLE SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET LookForSTXAfterFirstTxDLE: LHLD TxBufferPointer MOV A,M OUT TxData ;Send the next character INX H SHLD TxBufferPointer CPI STX JNZ TxEndOfFrameNext LXI H,StartTxTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET LookForSTXAfterTxDLE: {Come here after the sequence ITB DLE or SOH DLE. The only valid character that can follow is STX to start Transparent Mode. The CRC generator is on. The STX in included in the CRC.} LHLD TxBufferPointer MOV A,M OUT TxData ;Send the next character INX H SHLD TxBufferPointer CPI STX JNZ IllegalTxSequence {In Transparent Mode, we must change WR6 to DLE so that the SIO will send DLE SYN when it gets TxUnderrun.} LXI H,8000H+TxCont MVI M,PointToWR6 MVI M,DLE ContinueTransparentMode: LXI H,TxTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; StartTxTransparentMode: {We are about to send the first character in Transparent Mode or continue after a one second timeout. Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer CPI DLE JZ StartTransparentModeDLE LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM EnableTxCRC4: DB 0 OUT TxData ;Send the next character {In Transparent Mode, we must change WR6 to DLE so that the SIO will send DLE SYN when it gets TxUnderrun.} LXI H,8000H+TxCont MVI M,PointToWR6 MVI M,DLE LXI H,TxTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; TxTransparentMode: {We are sending characters in Transparent mode. The CRC generator is on. The only interesting character to look for is DLE.} LHLD TxBufferPointer MOV A,M INX H SHLD TxBufferPointer CPI DLE JZ TxTransparentModeDLE OUT TxData ;Send the next character {Check the timer to see if one second has elapsed since we started sending.} IN RS366Reg ANI TimeUp JNZ ExitTxDataInt ;Enable Interrupts {The one second timer has expired. We must send DLE and a sync character.} LXI H,TransparentModeTimeout1 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TransparentModeTimeout1: {Come here to send the DLE after a one second timeout. The DLE character does not get included in the checksum, so we must turn off the CRC generator.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM DisableTxCRC5: DB 0 MVI A,DLE OUT TxData LXI H,TransparentModeTimeout2 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TransparentModeTimeout2: {Come here to send the sync character after a one second timeout. Turn the timer back on.} LDA CurrentSyncCharacter OUT TxData {Turn the timer back on.} MVI A,TimeCMD OUT OSCCont LDA OneSecondTimerLow OUT TimeReg LDA OneSecondTimerHigh OUT TimeReg LXI H,StartTxTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET TxTransparentModeDLE: {Come here if we got a DLE character in Transparent Mode. The DLE character does not get included in the checksum, so we must turn off the CRC generator. We want to turn the CRC generator back on when we get the next interrupt.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM DisableTxCRC6: DB 0 StartTransparentModeDLE: OUT TxData ;Send the next character LXI H,LookForTxDataAfterDLE SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET LookForTxDataAfterDLE: {Turn on the CRC generator and send the character following DLE in Transparent Mode.} LXI H,8000H+TxCont MVI M,PointToWR5 DB opMVIM EnableTxCRC5: DB 0 LHLD TxBufferPointer MOV A,M OUT TxData ;Send the next character INX H SHLD TxBufferPointer MOV H,A ;Save character sent in H CPI DLE JZ ContinueTransparentMode {Assume we are going to exit Transparent Mode. Restore WR6 to the sync character. WR6 and WR7 get sent automatically by the SIO when it get TxUnderrun.} LXI H,8000H+TxCont MVI M,PointToWR6 DB opMVIM ;M ← SYN SYN1: DB 0 DB opCPI ENQ4: DB 0 JZ TxEndOfFrameNext DB opCPI ETB4: DB 0 JZ TxEndingCRCNext CPI ETX JZ TxEndingCRCNext CPI AltoETX JZ TxEndingCRCNext CPI ITB JZ TxInterBlockCRCNext DB opCPI SYN4: DB 0 JNZ IllegalTxSequence {Come here if we got a SYN character in transparent mode. The SYN character does not get included in the checksum, so we must turn off the CRC generator. HL still points to TxCont.} MVI M,PointToWR5 DB opMVIM DisableTxCRC7: DB 0 {The next time we get a TxData interrupt, we want to turn the CRC generator back on.} LXI H,StartTxTransparentMode SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET ; IllegalTxSequence: MVI A,1 STA IllegalBisyncCharacterFlag JMP TxEndOfFrameNext TxEndOfFrameNext: {Come here to end a frame with no CRC.} LXI H,EndOfFrameNoCRC SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET EndOfFrameNoCRC: {Turn on the TxUnderrunDetectedFlag. Since we are not sending a CRC, we will not get underrun.} MVI A,1 JMP TxEndOfFrame TxEndingCRCNext: {Come here when we have sent the last character of the frame. The next time we get an interrupt for Transmit Buffer Empty, we will simply clear the interrupt. This will cause the CRC to be sent if we reset the Transmit Underrun/EOM bit.} MVI A,ResetTxEOM OUT TxCont LXI H,EndingCRC SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET EndingCRC: {Reset TxUnderrunDetected. When the CRC has been sent, TxUnderrunDetectedFlag will be set again. This lets the Put routine know that the CRC has been sent and it is OK to begin sending the Filler characters.} XRA A TxEndOfFrame: {Reset TxIntPending. This will cause the CRC to be sent if TxEOM is reset. The chip will then send whatever is loaded into WR6 and WR7. We will load WR6 and WR7 with filler characters. We must send at least 3 filler characters. We will set RestartSIOCharacter so that the Put routine will send a filler character to get us started again. Otherwise we will never get another wakeup. We also reset TxUnderrunDetected. When the CRC has been sent, TxUnderrunDetectedFlag will be set again. This lets the Put routine know that the CRC has been sent and it is OK to begin sending the Filler characters.} STA TxUnderrunDetectedFlag LXI H,8000H+TxCont MVI A,Filler STA RestartSIOCharacter MVI M,PointToWR6 MOV M,A MVI M,PointToWR7+ResetTxIntPending MOV M,A LXI H,SendFiller2 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET SendFiller2: {Come here when the Put routine has restarted the chip by sending a filler character. Send the second filler character.} MVI A,Filler OUT TxData LXI H,SendFiller3 SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET SendFiller3: {Send the last filler character.} MVI A,Filler OUT TxData LXI H,PutCompleted SHLD TxBisyncStateSwitch POP H POP PSW EI ;Enable Interrupts RET PutCompleted: MVI A,ResetTxIntPending OUT TxCont STA PutCompletedFlag ExitTxDataInt: POP H POP PSW EI ;Enable Interrupts RET ; RxBisyncExternalInt: { Come here when we get an External/Status interrupt. Register RR0 indicates the cause of the interrupt: 08: 00001000 Data Carrier Detect (DCD)} IN RxCont ;Read RR0 ANI DCD DB opCPI ;Compare to previous DCD PrevBisyncDCD: DB 0 STA PrevBisyncDCD ;Save current DCD MVI A,ResetExternalStatusInterrupts OUT RxCont JNZ ExitBisyncInterrupt {Continue if DataCarrierDetect has changed state. Notify the Get loop so that it will do a NakedNotify. We store ResetExternalStatusInterrupts in StatusChangeFlag.} STA StatusChangeFlag ExitBisyncInterrupt: MVI A,38H ; Issue Return From Int Command (Ch-A Only) OUT RxCont POP H POP PSW EI ;Enable interrupts RET ; RxBisyncSpecialInt: { Come here when we get a Special interrupt. Register RR1 indicates the cause of the interrupt: 20: 00100000 RxOverrun 10: 00010000 Parity error RxOverrun means data is being overwritten because the channel's three-byte receiver buffer is full and a new character is being received. A Parity Error occurs when the parity bit of the character does not match with the programmed parity. Once this bit is set, it remains set until the Error Reset Command is given.} PUSH D ;Save DE {Read the character that caused the interrupt and place it in the RxFifo as we would a normal character.} IN RxData ;A ← RxData STAX B ;Store character in Fifo INX B LXI H,8000H+RxCont ;Point to RxCont register MVI M,PointToWR1 MOV A,M ;Read CompletionCode from RR1 ANI 0F0H MVI M,ErrorReset JMP SetBisyncCompletion ;In BisyncInput END