{ File: BisyncInput.asm Modification History: 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. } Get "SysDefs" Get "RS232CDefs" IMP RxBisyncStateSwitch ;From BisyncInterrupts IMP StoreFrameHeader ;From RS232CInterrupts IMP CharactersUntilBoundary ;From RS232CInterrupts 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 RxMaxFrameSize EXP SetBisyncCompletion EXP SYN7 EXP SYN8 EXP SYN9 EXP SYN10 EXP SYN11 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 } ; 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.} IN RxData ;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 {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.} IN RxData DB opCPI SYN7: DB 0 JZ ExitBisyncDataInt {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 CPI STX JZ ContinueRxNonTransparentMode CPI DLE JZ LookForSTXAfterRxDLE 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.} IN RxData DB opCPI SYN8: DB 0 JZ RxHeaderSyn CPI STX JZ ContinueRxNonTransparentMode CPI DLE JZ LookForSTXAfterRxDLE 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 LXI H,StartRxHeader SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt ; FirstRxCharIsSTX: LXI H,StartRxNonTransparentMode JMP ChangeStateAndStoreBisyncChar 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.} IN RxData DB opCPI SYN9: DB 0 JZ ExitBisyncDataInt {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 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 ; 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.} IN RxData DB opCPI SYN10: DB 0 JZ RxNonTransparentModeSYN 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 RxCRCEnable DisableRxCRC2: DB 0 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 JMP ChangeStateAndStoreBisyncChar RxInterBlockCRC1: {Read and store the first Interblock CRC character.} IN RxData LXI H,RxInterBlockCRC2 JMP ChangeStateAndStoreBisyncChar 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.} IN RxData JMP ContinueRxNonTransparentMode ; 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: IN RxData CPI STX JNZ EndOfBisyncFrame LXI H,StartRxTransparentMode JMP ChangeStateAndStoreBisyncChar LookForSTXAfterRxDLE: {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 is included in the CRC.} IN RxData CPI STX JNZ IllegalRxSequence LXI H,RxTransparentMode JMP ChangeStateAndStoreBisyncChar ; 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.} IN RxData CPI DLE JZ LookForRxDataNext {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 RxTransparentMode: {We are receiving characters in Transparent mode. The only interesting character to look for is DLE. The CRC generator is on.} IN RxData CPI DLE JNZ StoreBisyncChar {Come here if we got a DLE character in Transparent Mode. The DLE character does not get included in the checksum or stored in the input buffer, so we must turn off the CRC generator.} LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ← WR3 OR RxCRCEnable DisableRxCRC3: DB 0 LookForRxDataNext: LXI H,LookForRxDataAfterDLE SHLD RxBisyncStateSwitch JMP ExitBisyncDataInt 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.} IN RxData DB opCPI SYN11: DB 0 JZ DLESyn LXI H,8000H+RxCont MVI M,PointToWR3 DB opMVIM ;RxCont ← WR3 OR RxCRCEnable EnableRxCRC4: DB 0 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,RxEndingCRC1 JMP ChangeStateAndStoreBisyncChar RxEndingCRC1: {Read and store the first Interblock CRC character.} IN RxData LXI H,RxEndingCRC2 JMP ChangeStateAndStoreBisyncChar RxEndingCRC2: {Read and store the second Interblock CRC character.} IN RxData 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.} IN RxData 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 IN RxData 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,RxBisyncInitial SHLD RxBisyncStateSwitch JMP SetNewBisyncBoundary ContinueRxTransparentMode: LXI H,RxTransparentMode ChangeStateAndStoreBisyncChar: SHLD RxBisyncStateSwitch StoreBisyncChar: {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 LHLD CharactersUntilBoundary DCX H MOV A,H ORA L JZ BisyncBlockFull SHLD CharactersUntilBoundary 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