{	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