{	File: [Iris]<WMicro>DLion>BisyncInput.asm
Modification History:
  Dennis DEG     : 27-Mar-85  1:19:45: Make changes to handle PAD character in 9750 mode.
  Dennis DEG     :  6-Nov-84 15:34:54: Call DisableCRCSub after recieving DLE STX to disable sync stripping
  Dennis DEG     :  1-Sep-84 16:52:20: Add copyright notice.
  Dennis DEG     :  3-Apr-84 22:14:04: ITB checksum error in 2780 mode.
  Dennis DEG     : 12-Jan-84 16:43:57: screwup after ITB character.
  Dennis DEG     : 10-Jan-84 23:38:07: Another transparent data bug.
  Dennis DEG     : 30-Nov-83 20:20:49: Fix bug in 9750 mode of not throwing out filler character.
  Dennis DEG     : 28-Nov-83 11:37:09: Fix handling of transparent data.
  Dennis DEG     : 26-Oct-83 17:41:42: Fix bug introduced during changes to support 9750.
  Dennis DEG     :  9-Oct-83 16:40:47: Changes to support 9750.
  Dennis DEG     : 30-Jun-83 11:08:27: More fixes to meet IBM spec.
  Dennis DEG     : 29-Jun-83 15:01:50: ITB fixes
  CrF   CRF :  11-Nov-82 10:05:45: Move POPs before EI to avoid possible stack
    overflow.
  Jim JXF      :  September 17, 1982  9:28 AM: Allow Async mode to have client
    buffer size larger than our Rx buffer.
  Jim JXF      :  September 8, 1982  2:05 PM: Fix DLE SYN bug.
  Jim JXF      :  May 20, 1982  1:57 PM
  Jim JXF      :  May 10, 1982  8:10 AM:  Created file.
}

{ 	Copyright (C) 1982, 1983, 1984, 1985 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	PadAfterBCC
	EXP	RxBisyncInitial
	EXP	RxEndBCC2
	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,PadAfterBCC		;Mark the fact that we are expecting a PAD
	MVI	M,1			;character next.
	
	LXI	H,RxEndingBCC2
	JMP	ChangeStateAndStoreBisyncChar

PadAfterBCC	DB	0

RxEndingBCC2:
	PUSH	D			;Save DE
	MVI	E,80H			;Set up as good (does not affect flags)
	
RxCheckForGoodBCC:
	XRA	A
	STA	PadAfterBCC
	
	LDA	BlockCheckChar
	ORA	A			;Check to make sure BCC shows column parity (all zero).
	MOV	A,E			
	JZ	SetBisyncCompletion
	ORI	40H			;Indicate bad BCC (CRC)
	JMP	SetBisyncCompletion

RxEndBCC2:
	POP	PSW			;get current error status
	MOV	E,A			;move it to the E register
	JMP	RxCheckForGoodBCC
	
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