{ 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