{ File: [Iris]DLion>BisyncInput.asm Modification History: Dennis Grundler: 6-Nov-84 15:34:54: Call DisableCRCSub after recieving DLE STX to disable sync stripping Dennis Grundler: 1-Sep-84 16:52:20: Add copyright notice. Dennis Grundler: 3-Apr-84 22:14:04: ITB checksum error in 2780 mode. Dennis Grundler: 12-Jan-84 16:43:57: screwup after ITB character. Dennis Grundler: 10-Jan-84 23:38:07: Another transparent data bug. Dennis Grundler: 30-Nov-83 20:20:49: Fix bug in 9750 mode of not throwing out filler character. Dennis Grundler: 28-Nov-83 11:37:09: Fix handling of transparent data. Dennis Grundler: 26-Oct-83 17:41:42: Fix bug introduced during changes to support 9750. Dennis Grundler: 9-Oct-83 16:40:47: Changes to support 9750. Dennis Grundler: 30-Jun-83 11:08:27: More fixes to meet IBM spec. Dennis Grundler: 29-Jun-83 15:01:50: ITB fixes Chuck Fay : 11-Nov-82 10:05:45: Move POPs before EI to avoid possible stack overflow. Jim Frandeen : September 17, 1982 9:28 AM: Allow Async mode to have client buffer size larger than our Rx buffer. Jim Frandeen : September 8, 1982 2:05 PM: Fix DLE SYN bug. Jim Frandeen : May 20, 1982 1:57 PM Jim Frandeen : May 10, 1982 8:10 AM: Created file. } { Copyright (C) 1982, 1983 by Xerox Corporation. All rights reserved.} Get "SysDefs" Get "RS232CDefs" IMP RxBisyncStateSwitch ;From BisyncInterrupts IMP StoreFrameHeader ;From RS232CInterrupts IMP CharactersUntilBoundary ;From RS232CInterrupts IMP CurrentCharLengthMask ;From RS232CMisc EXP BEL6 EXP EnableRxCRC1 EXP EnableRxCRC2 EXP EnableRxCRC3 EXP EnableRxCRC4 EXP EndOfBisyncFrame EXP EOTEndFrameSwitch EXP EOT3270 EXP DisableRxCRC1 EXP DisableRxCRC2 EXP DisableRxCRC3 EXP ENQ6 EXP ENQ9 EXP ENQ10 EXP ENQ11 EXP EnterHuntMode1 EXP EnterHuntMode2 EXP EOT6 EXP ETB7 EXP ETB8 EXP ETB9 EXP ETB10 EXP ETB11 EXP NAK6 EXP RxBisyncInitial EXP RxInitBiSyncInput EXP RxMaxFrameSize EXP SetBisyncCompletion EXP SYN7 EXP SYN8 EXP SYN9 EXP SYN10 EXP SYN11 EXP SYN13 {6/30/83} EXP SYN14 {6/30/83} EXP TerminateBisyncFrame ; {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 } ; BisyncSwitches: DW SOHContinue DW RxHeaderSyn DW Non9750CRCEnable DW RxNonTransparentModeSYN DW RxInterBlockCRC1 DW TModeCRCEnable DW Non9750CRCDisable DW RxEndingCRC1 DW RxDataAfterDLE DW StoreBisyncChar Siemens9750Switches: DW SOH9750Mode DW RxHeaderSyn1 DW CRC9750Enable DW RxNTModeSYN1 DW RxBCCNext DW ContinueRxTransparentMode DW DisableCRC9750 DW RxEndingBCC1 DW SkipCRCEnAfterDLE DW Filler9750Mode RxInitBiSyncInput: {RxInitBiSync is a procedure which on input contains the current correspondent (Siemens 9750 or other bisync correspondents). On exit all registers are unchanged.} PUSH D ;Save the contents of the DE register pair PUSH H ;Save the contents of the HL register pair LXI H,0 ;Prepare to get the value of the Stack Pointer DI ;Make sure that stack does not get modified DAD SP ;Find out where the stack lives XCHG ;save the old SP in DE CPI Siemens9750Correspondent JNZ BisyncSetup SiemensSetup: LXI SP,Siemens9750Switches JMP SetBisyncSwitches BisyncSetup: LXI SP,BisyncSwitches SetBisyncSwitches: POP H SHLD InputSOHSwitch POP H SHLD RxHeaderSwitch POP H SHLD CRCEnableSwitch POP H SHLD RxNTModeSwitch POP H SHLD RxITBCRCSwitch POP H SHLD TModeCRCSwitch POP H SHLD Non9750CRC1Switch POP H SHLD RxEndingCRCorBCCSwitch POP H SHLD ContRxAfterDLESwitch POP H SHLD ThrowOutFiller XCHG ;Prepare to restore old stack pointer SPHL ;Restore old stack pointer EI ;It is now safe to allow stack to change POP H ;Restore HL POP D ;Restore DE RET InputChar: {This routine masks off all uninteresting bits, ie. if the character length is 8 nothing happens to it otherwise the 8-n upper bits get masked off for n = 5..7. The routine is re-entrant as long as the PSW is not needed. On exit the Accumulator will have the input data} IN RxData PUSH H LXI H,CurrentCharLengthMask ANA M POP H RET RxBisyncInitial: {This is the initial receive state. The CRC generator is off. We are waiting for the first character. The receiver is in Hunt mode, which means it is searching for two contiguous sync characters. The SIO chip is set for SyncCharacterLoadInhibit so that leading Sync characters will not be loaded or cause interrupts. Come here when we receive the first character that is not a sync character.} XRA A ;set the BCC to zero (important only for STA BlockCheckChar ; 9750 mode) CALL InputChar ;Read character CPI STX JZ FirstRxCharIsSTX CPI SOH JZ FirstRxCharIsSOH CPI DLE JZ FirstRxCharIsDLE {EOT is a special character if the host is a 3270. In this case, we enter Hunt mode right away. If the host is not a 3270, we simply end the frame. This switch is set by Misc when the mode and the Correspondent is determined.} DB opCPI EOT6: DB 0 DB opJZ EOTEndFrameSwitch: DW EOT3270 ; JZ EOT3270 ; JZ EndOfBisyncFrame DB opCPI BEL6: DB 0 JZ EndOfBisyncFrame DB opCPI NAK6: DB 0 JZ EndOfBisyncFrame DB opCPI ENQ6: DB 0 JZ EndOfBisyncFrame DB opJMP ThrowOutFiller: DW StoreBisyncChar ; DW Filler9750Mode Filler9750Char EQU 7FH Filler9750Mode: CPI Filler9750Char JZ ExitBisyncDataInt {Continue if the character is not any of the above. We stay in this state.} JMP StoreBisyncChar EOT3270: LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;M ¬ EnterHuntMode EnterHuntMode1: DB 0 JMP StoreBisyncChar ; FirstRxCharIsSOH: LXI H,StartRxHeader JMP ChangeStateAndStoreBisyncChar StartRxHeader: {We are about to read the first Header character following SOH or continue after a SYN character. The CRC generator is off. Unless the next character is a SYN, we want to include it in the CRC.} CALL InputChar DB opCPI SYN7: DB 0 JZ ExitBisyncDataInt {The following code up to and including the label SOHContinue were added for Siemens 9750 support. In Siemens 9750 mode we turn on the BCC generator after the first SOH or first STX and it remains on until we finish receiving the message including the ETB or ETX.} DB opJMP InputSOHSwitch: DW SOHContinue ; DW SOHContinue ; DW SOH9750Mode SOH9750Mode: LXI H,AccumulateBCC SHLD InputBCCSwitch JMP RejoinSOH SOHContinue: {If the first character of the header is not SYN, turn on the CRC generator to include the character in the CRC. During receive, the CRC accumulation is delayed eight bits. We must read a character, decide whether or not to continue CRC accumulation, and disable/enable CRC before the next character is transferred to the buffer.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCEnable EnableRxCRC1: DB 0 RejoinSOH: CPI STX JZ ContinueRxNonTransparentMode CPI DLE JZ LookForSTXAfterRxDLENext {modified 6/30/83} CPI ETX JZ RxEndingCRCNext DB opCPI ETB7: DB 0 JZ RxEndingCRCNext {Continue if the character is not any of the above. Pass to RxHeader state.} LXI H,RxHeader JMP ChangeStateAndStoreBisyncChar ; RxHeader: {We are about to read the next Header character. The CRC generator is on. Unless the next character is a SYN, we want to include it in the CRC.} CALL InputChar DB opCPI SYN8: DB 0 DB opJZ RxHeaderSwitch: DW RxHeaderSyn ; JZ RxHeaderSyn ; JZ RxHeaderSyn1 CPI STX JZ ContinueRxNonTransparentMode CPI DLE JZ LookForSTXAfterRxDLENext {modified 6/30/83} CPI ETX JZ RxEndingCRCNext DB opCPI ETB8: DB 0 JZ RxEndingCRCNext {Continue if the character is not any of the above. Stay in this state. Leave the CRC generator on.} JMP StoreBisyncChar RxHeaderSyn: {Come here if we got a SYN character in the header. The SYN character does not get included in the checksum, and it does not get stored in the input buffer. Disable the CRC generator.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCEnable DisableRxCRC1: DB 0 RxHeaderSyn1: LXI H,StartRxHeader SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt ; FirstRxCharIsSTX: LXI H,StartRxNonTransparentMode JMP ChangeStateAndStoreBisyncChar EnableCRCSub: DB opJMP CRCEnableSwitch: DW Non9750CRCEnable ; DW Non9750CRCEnable ; DW CRC9750Enable CRC9750Enable: LXI H,AccumulateBCC SHLD InputBCCSwitch RET Non9750CRCEnable: {If the first character of the header is not SYN, turn on the CRC generator to include the character in the CRC. During receive, the CRC accumulation is delayed eight bits. We must read a character, decide whether or not to continue CRC accumulation, and disable/enable CRC before the next character is transferred to the buffer.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCEnable EnableRxCRC2: DB 0 RET StartRxNonTransparentMode: {We are about to read the first character in NonTransparent Mode or continue after a SYN character. The CRC generator is off. Unless the next character is SYN, we want to include it in the CRC.} CALL InputChar DB opCPI SYN9: DB 0 JZ ExitBisyncDataInt {The following code up to and including the label Non9750CRCEnable were added for Siemens 9750 support. In Siemens 9750 mode we turn on the BCC generator after the first SOH or first STX and it remains on until we finish receiving the message including the ETB or ETX.} CALL EnableCRCSub RejoinSTX: CPI ETX JZ RxEndingCRCNext DB opCPI ETB9: DB 0 JZ RxEndingCRCNext CPI ITB JZ RxInterBlockCRCNext DB opCPI ENQ9: DB 0 JZ EndOfBisyncFrame ContinueRxNonTransparentMode: LXI H,RxNonTransparentMode JMP ChangeStateAndStoreBisyncChar ; DisableCRCAndExit: CALL DisableCRCSub JMP ExitBisyncDataInt RxITBContinueNTMode: {After ITB we may optionally receive SYN (without including them in the checksum). } CALL InputChar DB opCPI SYN13: DB 0 JZ DisableCRCAndExit CALL EnableCRCSub LXI H,RxNonTransparentMode SHLD RxBisyncStateSwitch JMP RxNTMode RxNonTransparentMode: {We are receiving characters in NonTransparent mode. The CRC generator is on. Unless the next character is SYN, we want to include it in the CRC.} CALL InputChar RxNTMode: DB opCPI SYN10: DB 0 DB opJZ RxNTModeSwitch: DW RxNonTransparentModeSYN ; JZ RxNonTransparentModeSYN ; JZ RxNTModeSYN1 CPI ETX JZ RxEndingCRCNext DB opCPI ETB10: DB 0 JZ RxEndingCRCNext CPI ITB JZ RxInterBlockCRCNext DB opCPI ENQ10: DB 0 JZ EndOfBisyncFrame {Continue if the character is not any of the above. We stay in NonTransparent Mode.} JMP StoreBisyncChar RxNonTransparentModeSYN: {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+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCDisable DisableRxCRC2: DB 0 RxNTModeSYN1: LXI H,StartRxNonTransparentMode SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt ; RxInterBlockCRCNext: {Come here when we have just read an ITB character. The next two characters we receive will be CRC characters. The CRC generator is on.} {LXI H,RxInterBlockCRC1} DB opLXIH RxITBCRCSwitch: DW RxInterBlockCRC1 ; DW RxInterBlockCRC1 ; DW RxBCCNext JMP ChangeStateAndStoreBisyncChar RxInterBlockCRC1: {Read and store the first Interblock CRC character.} CALL InputChar LXI H,RxInterBlockCRC2 JMP ChangeStateAndStoreBisyncChar RxBCCNext: {Read and store the Block Check Character. This is what the 9750 uses for vertical parity checking.} RxInterBlockCRC2: {Read and store the second Interblock CRC character. The result of the CRC will not be available until two characters later. Maybe someday we will get around to checking the CRC. For now, we will wait until the end of the block.} CALL InputChar PUSH PSW ;save character LDA TransparentDataFlag ;If we were in transparent mode then ORA A ;stay there. 6/29/83 JNZ ContinueITBRxTransparentMode ContinueITBRxNonTransparentMode: {6/30/83} LXI H,RxITBContinueNTMode JMP SaveLastByteChecksum ContinueITBRxTransparentMode: LXI H,RxITBContinueTMode SaveLastByteChecksum: POP PSW ;restore character JMP ChangeStateAndStoreBisyncChar ; FirstRxCharIsDLE: {Come here if the first Rx character is DLE. Look for STX to enter transparent mode. Any other character will be EndOfFrame. The CRC generator is not on. The STX is NOT included in the checksum.} LXI H,LookForSTXAfterFirstRxDLE JMP ChangeStateAndStoreBisyncChar LookForSTXAfterFirstRxDLE: CALL InputChar CPI STX JNZ EndOfBisyncFrame CALL DisableCRCSub LXI H,StartRxTransparentMode JMP ChangeStateAndStoreBisyncChar ; {ITB fixes. 6/29/83} TransparentDataFlag: DB 0 StartRxTransparentMode: {We are about to receive the first character in Transparent Mode or continue after DLE SYN. We want to include the next character in the CRC unless it is DLE.} MVI A,1 ;Indicate Transparent mode. 6/29/83 STA TransparentDataFlag CALL InputChar CPI DLE JZ DisableCRCNow DB opJMP TModeCRCSwitch: DW TModeCRCEnable ; DW TModeCRCEnable ; DW ContinueRxTransparentMode TModeCRCEnable: {Turn on the CRC generator to include the character in the CRC. During receive, the CRC accumulation is delayed eight bits. We must read a character, decide whether or not to continue CRC accumulation, and disable/enable CRC before the next character is transferred to the buffer.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCEnable EnableRxCRC3: DB 0 JMP ContinueRxTransparentMode RxITBContinueTMode: {We can have SYN* followed by DLE STX only, after ITB in Transparent mode. The CRC generator is off.} CALL InputChar DB opCPI SYN14: DB 0 JZ DisableCRCAndExit CPI DLE JNZ IllegalRxSequence CALL EnableCRCSub ;Make sure the CRC generator is on. LookForSTXAfterRxDLENext: LXI H,LookForSTXAfterRxDLE JMP ChangeStateAndStoreBisyncChar LookForSTXAfterRxDLE: {Come here after the sequence ITB BCC SYN* DLE or SOH DLE. The only valid character that can follow is STX to start Transparent Mode. The CRC generator may or may not be on. The STX needs to be included in the CRC.} CALL InputChar CPI STX JNZ IllegalRxSequence CALL EnableCRCSub JMP ContinueRxTransparentMode NoRoomForDLE: {This is a sneaky way of saving the contents of the registers and faking a subroutine call while in the middle of a subroutine. E contains the completion code.} PUSH H ;Save the HL register temporarily. LXI H,RetAddr ;RetAddr is where we enventually want to return to. XTHL ;This restores HL while putting the return address on the stack. PUSH PSW ;Now set up the stack with the registers that the new subroutine is going to POP in the correct order. PUSH H PUSH D MVI E,4 ;Set EndOfBlock CompletionCode {The stack should now look like: TOS: DE HL PSW RetAddr Where TOS is what the Stack pointer is pointing to.} JMP SetNewBisyncBoundary ;CALL the subroutine. RetAddr: DI ;unfortunately we had an EI executed on us. JMP ReEnter RxTransparentMode: {We are receiving characters in Transparent mode. The only interesting character to look for is DLE. The CRC generator is on.} CALL InputChar CPI DLE JNZ StoreBisyncChar DisableCRCNow: CALL DisableCRCSub LookForRxDataNext: LXI H,LookForRxDataAfterDLE SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt DisableCRCSub: DB opJMP Non9750CRC1Switch: DW Non9750CRCDisable ; DW Non9750CRCDisable ; DW DisableCRC9750 DisableCRC9750: LXI H,CheckBoundary SHLD InputBCCSwitch RET Non9750CRCDisable: {Come here when we want to turn the CRC generator off.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCDisable DisableRxCRC3: DB 0 RET LookForRxDataAfterDLE: {Read the character following DLE in Transparent mode. The CRC geneator is off. Unless the character is SYN, we will include it in the checksum.} CALL InputChar DB opCPI SYN11: DB 0 JZ DLESyn DB opJMP ContRxAfterDLESwitch: DW RxDataAfterDLE ; DW RxDataAfterDLE ; DW SkipCRCEnAfterDLE RxDataAfterDLE: LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ¬ WR3 OR RxCRCEnable EnableRxCRC4: DB 0 SkipCRCEnAfterDLE: {This next section is to insert a DLE in the clients buffer except in the case of DLE SYN where the DLE SYN are both removed} PUSH PSW MVI A,DLE CALL StoreBSCChar JZ NoRoomForDLE ReEnter: POP PSW CPI DLE JZ ContinueRxTransparentMode DB opCPI ENQ11: DB 0 JZ EndOfBisyncFrame DB opCPI ETB11: DB 0 JZ RxEndingCRCNext CPI ETX JZ RxEndingCRCNext CPI AltoETX JZ RxEndingCRCNext CPI ITB JZ RxInterBlockCRCNext IllegalRxSequence: STAX B INX B PUSH D MVI E,8 ;Set CompletionCode IllegalSequence MVI A,38H ;Issue Return From Int Command OUT RxCont JMP TerminateBisyncFrame DLESyn: {Come here if we found DLE SYN in Transparent mode.} LXI H,StartRxTransparentMode SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt ; RxEndingCRCNext: {Come here when we have received the last character of the frame. The next two characters we receive will be CRC characters. The CRC generator is on.} LXI H,TransparentDataFlag ;set non-transparent mode. 6/29/83 MVI M,0 DB opLXIH RxEndingCRCorBCCSwitch: DW RxEndingCRC1 ; DW RxEndingCRC1 ; DW RxEndingBCC1 JMP ChangeStateAndStoreBisyncChar RxEndingBCC1: {Read and store the BCC. If all has went well the accumulated BCC should be zero after storing the BCC in the buffer.} CALL InputChar LXI H,RxEndingBCC2 JMP ChangeStateAndStoreBisyncChar RxEndingBCC2: PUSH D ;Save DE LDA BlockCheckChar ORA A ;Check to make sure BCC shows column parity (all zero). MVI A,80H ;Set up as good (does not affect flags) JZ SetBisyncCompletion ORI 40H ;Indicate bad BCC (CRC) JMP SetBisyncCompletion RxEndingCRC1: {Read and store the first Interblock CRC character.} CALL InputChar LXI H,RxEndingCRC2 JMP ChangeStateAndStoreBisyncChar RxEndingCRC2: {Read and store the second Interblock CRC character.} CALL InputChar LXI H,RxEndingCRC3 JMP ChangeStateAndStoreBisyncChar RxEndingCRC3: {Read and throw away the character following the second CRC character. We are guaranteed at least three fill characters following the CRC, so we are only throwing away fill characters. The CRC result will not be available until one character later.} CALL InputChar LXI H,RxEndingCRC4 SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt EndOfBisyncFrame: STAX B ;Store character INX B PUSH D MVI E,80H ;E ¬ EndOfFrame CompletionCode JMP SendEndingReturnFromInt RxEndingCRC4: {Read and throw away the second fill character following the second CRC character. The result of the CRC is now available in WR1.} PUSH D ;Save DE CALL InputChar LXI H,8000H+RxCont MVI M,PointToWR1 MOV A,M ANI 40H ;A ¬ 40 if CRC error ORI 80H SetBisyncCompletion: {Come here from RxSpecialInt in BisyncInterrupts.} MOV E,A ;Set CompletionCode SendEndingReturnFromInt: MVI A,38H ;Issue Return From Int Command OUT RxCont TerminateBisyncFrame: {We get called here from Get in case an abort is requested. The CompletionCode is in E. Turn off the CRC generator, Enter Hunt Phase, turn on InhibitSyncCharacterLoad.} LXI H,8000H+RxCont MVI M,ResetRxCRCChecker+PointToWR3 DB opMVIM EnterHuntMode2: DB 0 LXI H,TransparentDataFlag ;set non-transparent mode. 6/29/83 MVI M,0 LXI H,CheckBoundary ;Turn off the BCC mechanism SHLD InputBCCSwitch LXI H,RxBisyncInitial SHLD RxBisyncStateSwitch JMP SetNewBisyncBoundary StoreBSCChar: {A = last character read. Store this character in the RxFifo. Decrement CharactersUntilBoundary and test for boundary. If we have filled a block, ship this frame back to the CP and start a new frame.} STAX B INX B {The code from here up to and including the label CheckBoundary were added for Klamath 11.0b and beyond to support Siemens' 9750 terminal. The major problem with the Siemens terminal is that it does not use the standard Cyclic Redundancy Check mechanism so we need to support their flakey method. In the normal case we will always jump to CheckBoundary, thereby only paying only a 10 state time penalty for the JMP instruction. In 9750 mode we will jump to CheckBoundary until the character following the first SOH (start of heading) or STX (start of text) is found.} DB opJMP InputBCCSwitch: DW CheckBoundary ; JMP CheckBoundary ; JMP AccumulateBCC BCCMask EQU 7FH BlockCheckChar: DB 0 AccumulateBCC: CPI AsciiSYN ;check to see if character is sync character. JZ CheckBoundary ;If it is then do not modify BCC. LXI H,BlockCheckChar ;Reference the Block Check Character. XRA M ;calculate the modulo 2 sum of each column. ANI BCCMask ;mask off the parity bit. MOV M,A ;save the new Block Check Character. CheckBoundary: LHLD CharactersUntilBoundary DCX H SHLD CharactersUntilBoundary MOV A,H ORA L RET ContinueRxTransparentMode: LXI H,RxTransparentMode ChangeStateAndStoreBisyncChar: SHLD RxBisyncStateSwitch StoreBisyncChar: CALL StoreBSCChar JZ BisyncBlockFull ExitBisyncDataInt: MVI A,38H ;Issue Return From Int Command OUT RxCont POP H POP PSW EI ;Enable interrupts RET BisyncBlockFull: {End this Bisync frame and start a new frame. Then continue in the same state when we get the next input character.} PUSH D ;Save DE MVI E,4 ;Set EndOfBlock CompletionCode MVI A,38H ;Issue Return From Int Command OUT RxCont SetNewBisyncBoundary: {RxMaxFrameSize is the number of characters until our next boundary.} DB opLXIH ;HL ¬ RxMaxFrameSize RxMaxFrameSize: DW 0 SHLD CharactersUntilBoundary JMP StoreFrameHeader END