{	File: [Iris]<WMicro>DLion>BisyncInterrupts.asm
Modification History:
  Dennis Grundler:  1-Sep-84 16:51:46: Add copyright notice.
  Dennis Grundler:  9-Oct-83 17:33:41: Siemens 9750 support.
  Dennis Grundler: 29-Jun-83 14:15:54: ITB fixes.
  Tom Chang : 17-May-83 14:34:54Make sure use just 3 SIO interrupt bits
  Chuck Fay :  11-Nov-82  9:39:35:  Move POPs before EIs to avoid possible stack
    overflow.
  Jim Frandeen :  May 20, 1982  6:53 PM
  Jim Frandeen :  May 6, 1982  9:49 AM:  Created file.
}

{ 	Copyright (C) 1982, 1983 by Xerox Corporation.  All rights reserved.}

	Get "SysDefs"	
	Get "RS232CDefs"


	IMP	CurrentSyncCharacter	;From RS232CMisc
	IMP	IllegalBisyncCharacterFlag	;From RS232CPut
	IMP	PutCompletedFlag	;From RS232CPut
	IMP	RestartSIOCharacter	;From RS232CPut
	IMP	SetBisyncCompletion	;From BisyncInput
	IMP	StatusChangeFlag	;From RS232CGet
	IMP	TerminateBisyncFrame	;From BisyncInput
	IMP	TxBufferPointer		;From RS232CInterrupts
	IMP	TxUnderrunDetectedFlag	;From RS232CInterrupts
	IMP	TxWR5			;From RS232CMisc

	EXP	BisyncRS232CInterrupt
	EXP	BEL1
	EXP	DisableTxCRC1
	EXP	EnableTxCRC1
	EXP	ENQ1
	EXP	ENQ2
	EXP	ENQ4
	EXP	ENQ12
	EXP	EOT1
	EXP	ETB2
	EXP	ETB4
	EXP	ETB5
	EXP	ETB6
	EXP	ETB12
	EXP	NAK1
	EXP	PrevBisyncDCD
	EXP	SYN1
	EXP	SYN2
	EXP	SYN3
	EXP	SYN4
	EXP	SYN5
	EXP	SYN6
	EXP	SYN12
	EXP	OneSecondTimerLow
	EXP	OneSecondTimerHigh
	EXP	RxBisyncExternalInt
	EXP	RxBisyncSpecialInt
	EXP	SyncCharacterCount
	EXP	TxBisyncInitial
	EXP	TxBisyncStateSwitch
	EXP	TxInitBiSyncInterrupts
;
{NOTE: These routines are written for speed. Much code has been duplicated. If necessary, space could be saved by making the exit code common.

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
}
;
BisyncRS232CInterrupt:
{ Come here in Bisync mode from Common when we get a RST 6.5 Interrupt from the Zilog SIO chip. Save state }
	PUSH	PSW		
	PUSH	H

{Read the interruptVector to determine the cause of the interrupt. Multiply the vector by 2. This gives us a number which we can OR into the low bits of the jump table address. The jump table is in the Common so that we can assure its exact address and guarantee that the low 5 bits of the address are zero. }
	MVI	A,PointToWR2
	OUT	TxCont	
	IN	TxCont		; Read Interrupt Vector

{Test for TxDataInt first. We want to call this routine so that we can also call it from the input end of frame routine if necessary.}
{ remove ORA	A, replaced by the following}
	ANI	0EH		;use just 3 bits from SIO 5/17/83
	DB	opJZ
TxBisyncStateSwitch:
	DW	TxBisyncInitial

DispatchOnBisyncInterruptVector:
	RLC			;Interupt Vector * 2
	ORI	40H		;Low address is 40H
	MOV	L,A
	MVI	H,20H		;High address is 20H
	PCHL			;Jump to JumpTable

{BisyncJumpTable: @2040H
	JMP	TxIllegalInt	;When Vecter =0 Tx Buffer Empty
	DB	0
	JMP	TxBisyncExternalInt	;When Vecter =2 Ex Stat
	DB	0
	JMP	TxIllegalInt	;When Vecter =4 Tx Char
	DB	0
	JMP	ExitInterrupt	;When Vecter =6 Sp Tx Cond
	DB	0
	JMP	RxIllegalInt	;When Vecter =8 Tx Buffer Empty
	DB	0
	JMP	RxBisyncExternalInt	;When Vecter =A Ex Stat
	DB	0
	DB	opJMP		;When Vecter =C Rx Char
RxBisyncStateSwitch:
	DW	RxBisyncInitial
	DB	0
	JMP	RxBisyncSpecialInt	;When Vecter =E Sp Rx Cond
	DB	0
}
;
{TxSubroutines used to simplify transmission so that most of the code used for Bisync can also be used for 9750}

TxDisableCRC:
{This routine disables, turns off, the CRC generator}
	NOP			;In 9750 mode we replace this NOP with a RET
	LXI	H,8000H+TxCont
	MVI	M,PointToWR5+ResetExternalStatusInterrupts
	DB	opMVIM
DisableTxCRC1:
	DB	0
	RET

TxEnableCRC:
{This routine enables, turns on, the CRC generator}
	NOP			;In 9750 mode we replace this NOP with a RET
	LXI	H,8000H+TxCont
	MVI	M,PointToWR5+ResetExternalStatusInterrupts
	DB	opMVIM
EnableTxCRC1:
	DB	0
	RET

SendChWithCRCorBCC:
{Transmit this character and accumulate the BCC}
	OUT	TxData
OptRet:
	RET			;This RET is replaced by a NOP for 9750 mode.
	PUSH	PSW
	PUSH	H		;Save contents of HL
	LXI	H,TxBCC		;Point to the BCC
	XRA	M		;Accumulate the BCC
	ANI	7FH		;Mask off the parity bit.
	MOV	M,A		;Restore the BCC
	POP	H		;Restore the contents of HL
	POP	PSW
	RET			;Continue with next instruction

TxBCC:
	DB	0
	
TxInitBiSyncInterrupts:
	PUSH	PSW
	PUSH	H
	CPI	Siemens9750Correspondent
	JNZ	BiSyncSetup

SiemensSetup:
	MVI	A,opRET
	STA	TxDisableCRC
	STA	TxEnableCRC
	XRA	A			;MVI	A,opNOP
	LXI	H,TxInterBlockBCCNext
	SHLD	TxITBCRCSwitch
	LXI	H,TxEndingBCCNext
	JMP	SetupExit
	
BiSyncSetup:
	XRA	A			;MVI	A,opNOP
	STA	TxDisableCRC
	STA	TxEnableCRC
	MVI	A,opRET
	LXI	H,TxInterBlockCRCNext
	SHLD	TxITBCRCSwitch
	LXI	H,TxEndingCRCNext
	
SetupExit:
	SHLD	EndBCCorCRCSwitch
	STA	OptRet
	POP	H
	POP	PSW
	RET

;
TxBisyncInitial:
{Come here to initialize the transmitter. We sent one ModemSYN character (alternate ones and zeros) to prime the transmitter. We send two more ModemSYN characters in this state.}
	LXI	H,TxBCC		;Set accumulated BCC to 0
	MVI	M,0
	
	MVI	A,ModemSYN
	OUT	TxData

{Turn on the one second timer (i8253 Programmable Interval Timer Counter # 2).}
	MVI	A,TimeCMD
	OUT	OSCCont
	DB	opMVIA		;A ← OneSecondTimerLow
OneSecondTimerLow:
	DB	0
	OUT	TimeReg
	DB	opMVIA		;A ← OneSecondTimerHigh
OneSecondTimerHigh:
	DB	0
	OUT	TimeReg
	LXI	H,TxInitial1
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TxInitial1:
{We sent one ModemSYN character to prime the transmitter and one more ModemSYN character. Send one more ModemSYN character.}
	MVI	A,ModemSYN
	OUT	TxData

{Initialize WR6 and WR7 with the current sync character. These characters will be sent by the chip automatically whenever we get transmit underrun.}
	LXI	H,8000H+TxCont
	MVI	M,PointToWR6
	LDA	CurrentSyncCharacter
	MOV	M,A
	MVI	M,PointToWR7+ResetTxCRCGenerator
	MOV	M,A
	LXI	H,SendSyncCharacters
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

SendSyncCharacters:
{We send the number of Sync Characters specified by the client.}
	LDA	CurrentSyncCharacter
	OUT	TxData
	DB	opMVIA		;A ← SyncCharacterCount
SyncCharacterCount:
	DB	0
	DCR	A		;Decrement SyncCharacterCount
	JZ	SyncCharactersSent

	STA	SyncCharacterCount
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

SyncCharactersSent:
	LXI	H,StartTx
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
StartTx:
{This is the first Transmit state. We have sent the initial characters, and we are looking for SOH or STX. Send the next character from the client's buffer. The CRC generator is not turned on, and the next character sent will not be included in the CRC.}
	LHLD	TxBufferPointer
	MOV	A,M
	OUT	TxData		;Send the next character
	INX	H
	SHLD	TxBufferPointer

	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	CPI	STX
	JZ	FirstTxCharIsSTX

	CPI	SOH
	JZ	FirstTxCharIsSOH

	CPI	DLE
	JZ	FirstTxCharIsDLE

	DB	opCPI
EOT1:	DB	0
	JZ	TxEndOfFrameNext

	DB	opCPI
BEL1:	DB	0
	JZ	TxEndOfFrameNext

	DB	opCPI
NAK1:	DB	0
	JZ	TxEndOfFrameNext

	DB	opCPI
ENQ1:	DB	0
	JZ	TxEndOfFrameNext

{Continue if the character is not any of the above. We stay in this state.}
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
TxHeaderSyn:
{Come here if we got a SYN character in the header. The SYN character does not get included in the checksum, so we must turn off the CRC generator.}
	CALL	TxDisableCRC
	OUT	TxData		;Send the next character

{The next time we get a TxData interrupt, we want to turn the CRC generator back on.}

FirstTxCharIsSOH:
	LXI	H,StartTxHeader
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

StartTxHeader:
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer
	DB	opCPI
SYN5:	DB	0
	JZ	StartHeaderSyn

{We are about to send the first Header character following SOH. Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.}
	CALL	TxEnableCRC
	CALL	SendChWithCRCorBCC		;Send the next character

	CPI	STX
	JZ	ContinueTxNonTransparentMode

	CPI	DLE
	JZ	LookForSTXAfterTxDLE

	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	DB	opCPI
ETB5:	DB	0
	JZ	TxEndingBCCorCRCNext

{Continue if the character is not any of the above. Pass to TxHeader state.}
	LXI	H,TxHeader
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

StartHeaderSyn:
{Come here if we got a SYN character in the header. The SYN character does not get included in the checksum.}

StartNonTransparentModeSYN:
{Come here if we got a SYN character in non transparent mode. The SYN character does not get included in the checksum.}

TxInterBlockSYN:
{Come here if we got a SYN character following the ITB character. The SYN character does not get included in the checksum.}

	OUT	TxData		;Send the next character
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TxHeader:
{We are sending header characters. The CRC generator is on. The next character will be included in the CRC unless we turn off the CRC checker.}
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer
	DB	opCPI
SYN6:	DB	0
	JZ	TxHeaderSyn

	CALL	SendChWithCRCorBCC		;Send the next character
	CPI	STX
	JZ	ContinueTxNonTransparentMode

	CPI	DLE
	JZ	LookForSTXAfterTxDLE

	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	DB	opCPI
ETB6:	DB	0
	JZ	TxEndingBCCorCRCNext

{Continue if the character is not any of the above. Stay in this state.}
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
TxNonTransparentModeSYN:
{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.}
	CALL	TxDisableCRC
	OUT	TxData		;Send the next character

{The next time we get a TxData interrupt, we want to turn the CRC generator back on.}

FirstTxCharIsSTX:
	LXI	H,StartTxNonTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

StartTxNonTransparentMode:
{We are about to send the first character in NonTransparent Mode, or we are continuing after a one second timeout or a SYN character. The CRC generator is off.}
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer

	DB	opCPI
SYN2:	DB	0
	JZ	StartNonTransparentModeSYN

{Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.}
	CALL	TxEnableCRC
	CALL	SendChWithCRCorBCC		;Send the next character
	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	DB	opCPI
ETB2:	DB	0
	JZ	TxEndingBCCorCRCNext

	CPI	ITB
	JZ	TxInterBlockBCCorCRCNext

	DB	opCPI
ENQ2:	DB	0
	JZ	TxEndOfFrameNext

{Continue if the character is not any of the above. We pass to NonTransparent Mode.}

ContinueTxNonTransparentMode:
	LXI	H,TxNonTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
TxNonTransparentMode:
{We are sending characters in NonTransparent mode. The CRC generator is on.}
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer

	DB	opCPI
SYN12:	DB	0
	JZ	TxNonTransparentModeSYN

	CALL	SendChWithCRCorBCC		;Send the next character
	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	DB	opCPI
ETB12:	DB	0
	JZ	TxEndingBCCorCRCNext

	CPI	ITB
	JZ	TxInterBlockBCCorCRCNext

	DB	opCPI
ENQ12:	DB	0
	JZ	TxEndOfFrameNext

{Continue if the character is not any of the above. We stay in NonTransparent Mode. Check the timer to see if one second has elapsed since we started sending.}
	IN	RS366Reg
	ANI	TimeUp
	JNZ	ExitTxDataInt		;Enable Interrupts

{The one second timer has expired. We must send two sync characters.}
	LXI	H,NonTransparentModeTimeout1
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

;
NonTransparentModeTimeout1:
{Come here to send the first sync character after a one second timeout. The sync character does not get included in the checksum, so we must turn off the CRC generator.}
	CALL	TxDisableCRC
	LDA	CurrentSyncCharacter
	OUT	TxData
	LXI	H,NonTransparentModeTimeout2
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

NonTransparentModeTimeout2:
{Come here to send the second sync character after a one second timeout. Turn the timer back on.}
	LDA	CurrentSyncCharacter
	OUT	TxData
	MVI	A,TimeCMD
	OUT	OSCCont
	LDA	OneSecondTimerLow
	OUT	TimeReg
	LDA	OneSecondTimerHigh
	OUT	TimeReg
	LXI	H,StartTxNonTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
TxInterBlockBCCorCRCNext:
	DB	opJMP
TxITBCRCSwitch:
	DW	TxInterBlockCRCNext
;	DW	TxInterBlockCRCNext
;	DW	TxInterBlockBCCNext

TxInterBlockBCCNext:
	LXI	H,TxInterBlockBCC
	JMP	TxITBSet

TxInterBlockCRCNext:
{Come here when we have just sent an ITB character. The next time we get an interrupt for Transmit Buffer Empty, we will simply clear the interrupt. This will cause the CRC to be sent if we reset the Transmit Underrun/EOM bit.}
	MVI	A,ResetTxEOM
	OUT	TxCont
	LXI	H,TxInterBlockCRC
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TxInterBlockBCC:
	LDA	TxBCC
	CALL	SendChWithCRCorBCC

TxInterBlockCRC:
{Send the InterBlock CRC. Set SendSyncFlag for the Put routine. We will never get another wakeup unless the Put routine primes the chip again by sending a sync character. Disable the CRC generator so that the Sync character will not be included in the CRC.}
	LXI	H,8000H+TxCont
	MVI	M,PointToWR5+ResetTxIntPending
	CALL	TxDisableCRC
	LDA	CurrentSyncCharacter
	STA	RestartSIOCharacter
	LXI	H,ContinueAfterTxInterBlockCRC
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

ContinueAfterTxInterBlockCRC:
{Continue here when the CRC has been sent following the ITB character. Start sending data again. The CRC generator is off.}
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer
	DB	opCPI
SYN3:	DB	0
	JZ	TxInterBlockSYN

	CALL	TxEnableCRC
	CALL	SendChWithCRCorBCC		;Send the next character
	CPI	DLE
	JZ	LookForSTXAfterTxDLE

{In transparent mode we expect DLE after the BCC (CRC) or SYN SYN.  Mod. to meet IBM spec.s 6/29/83}	
	LDA	TransparentDataFlag	 
	ORA	A
	JNZ	IllegalTxSequence

{Continue if the character is not any of the above. We go back to Non Transparent state.}
	LXI	H,TxNonTransparentMode
	
TxITBSet:
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

;
FirstTxCharIsDLE:
{Come here if the first Tx character is DLE. Look for STX to enter transparent mode. Any other character will be EndOfFrame. The CRC generator is off. The STX is NOT included in the checksum.}
	LXI	H,LookForSTXAfterFirstTxDLE
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

LookForSTXAfterFirstTxDLE:
	LHLD	TxBufferPointer
	MOV	A,M
	OUT	TxData		;Send the next character
	INX	H
	SHLD	TxBufferPointer
	CPI	STX
	JNZ	TxEndOfFrameNext

	LXI	H,StartTxTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

LookForSTXAfterTxDLE:
{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 in included in the CRC.}
	LHLD	TxBufferPointer
	MOV	A,M
	CALL	SendChWithCRCorBCC		;Send the next character
	INX	H
	SHLD	TxBufferPointer
	CPI	STX
	JNZ	IllegalTxSequence

{In Transparent Mode, we must change WR6 to DLE so that the SIO will send DLE SYN when it gets TxUnderrun.}
	LXI	H,8000H+TxCont
	MVI	M,PointToWR6
	MVI	M,DLE

ContinueTransparentMode:
	LXI	H,TxTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
{ITB fix of 6/29/83}
TransparentDataFlag:
	DB	0
	
StartTxTransparentMode:
{We are about to send the first character in Transparent Mode or continue after a one second timeout. Turn on the CRC generator. If the CRC generator is turned on before the character is shifted into the serial shift register, the character will be included in the CRC.}

	MVI	A,1			;Store non-zero value to indicate we are in transparent mode.
	STA	TransparentDataFlag	;mod of 6/29/83
	
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer

	CPI	DLE
	JZ	StartTransparentModeDLE

	CALL	TxEnableCRC
	CALL	SendChWithCRCorBCC		;Send the next character

{In Transparent Mode, we must change WR6 to DLE so that the SIO will send DLE SYN when it gets TxUnderrun.}
	LXI	H,8000H+TxCont
	MVI	M,PointToWR6
	MVI	M,DLE
	LXI	H,TxTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
TxTransparentMode:
{We are sending characters in Transparent mode. The CRC generator is on. The only interesting character to look for is DLE.}
	LHLD	TxBufferPointer
	MOV	A,M
	INX	H
	SHLD	TxBufferPointer

	CPI	DLE
	JZ	TxTransparentModeDLE
	CALL	SendChWithCRCorBCC		;Send the next character

{Check the timer to see if one second has elapsed since we started sending.}
	IN	RS366Reg
	ANI	TimeUp
	JNZ	ExitTxDataInt		;Enable Interrupts

{The one second timer has expired. We must send DLE and a sync character.}
	LXI	H,TransparentModeTimeout1
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TransparentModeTimeout1:
{Come here to send the DLE after a one second timeout. The DLE character does not get included in the checksum, so we must turn off the CRC generator.}
	CALL	TxDisableCRC
	MVI	A,DLE
	OUT	TxData
	LXI	H,TransparentModeTimeout2
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TransparentModeTimeout2:
{Come here to send the sync character after a one second timeout. Turn the timer back on.}
	LDA	CurrentSyncCharacter
	OUT	TxData

{Turn the timer back on.}
	MVI	A,TimeCMD
	OUT	OSCCont
	LDA	OneSecondTimerLow
	OUT	TimeReg
	LDA	OneSecondTimerHigh
	OUT	TimeReg
	LXI	H,StartTxTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

TxTransparentModeDLE:
{Come here if we got a DLE character in Transparent Mode. The DLE character does not get included in the checksum, so we must turn off the CRC generator. We want to turn the CRC generator back on when we get the next interrupt.}
	CALL	TxDisableCRC
	
StartTransparentModeDLE:
	OUT	TxData		;Send the next character
	LXI	H,LookForTxDataAfterDLE
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

LookForTxDataAfterDLE:
{Turn on the CRC generator and send the character following DLE in Transparent Mode.}
	CALL	TxEnableCRC
	LHLD	TxBufferPointer
	MOV	A,M
	CALL	SendChWithCRCorBCC		;Send the next character
	INX	H
	SHLD	TxBufferPointer
	MOV	H,A		;Save character sent in H
	CPI	DLE
	JZ	ContinueTransparentMode

{Assume we may exit Transparent Mode. Restore WR6 to the sync character. WR6 and WR7 get sent automatically by the SIO when it gets TxUnderrun.}
	LXI	H,8000H+TxCont
	MVI	M,PointToWR6
	DB	opMVIM		;M ← SYN
SYN1:	DB	0

	DB	opCPI
ENQ4:	DB	0
	JZ	TxEndOfFrameNext

	DB	opCPI
ETB4:	DB	0
	JZ	TxEndingBCCorCRCNext

	CPI	ETX
	JZ	TxEndingBCCorCRCNext

	CPI	AltoETX
	JZ	TxEndingBCCorCRCNext

	CPI	ITB			;We should not leave Transparent Mode.
	JZ	TxInterBlockBCCorCRCNext

	DB	opCPI
SYN4:	DB	0
	JNZ	IllegalTxSequence

{Come here if we got a SYN character in transparent mode. The SYN character does not get included in the checksum, so we must turn off the CRC generator. HL still points to TxCont.}
	CALL	TxDisableCRC

{The next time we get a TxData interrupt, we want to turn the CRC generator back on.}
	LXI	H,StartTxTransparentMode
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
IllegalTxSequence:
	
	MVI	A,1
	STA	IllegalBisyncCharacterFlag

{Fall through to TxEndOfFrameNext. 6/29/83}

TxEndOfFrameNext:
{Come here to end a frame with no CRC.}

	XRA	A			;clear transparent mode.
	STA	TransparentDataFlag	;mod of 6/29/83

	LXI	H,EndOfFrameNoCRC
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

EndingBCC:
	LDA	TxBCC
	CALL	SendChWithCRCorBCC

EndOfFrameNoCRC:
{Turn on the TxUnderrunDetectedFlag. Since we are not sending a CRC, we will not get underrun.}
	MVI	A,1
	JMP	TxEndOfFrame

TxEndingBCCorCRCNext:
	XRA	A			;clear transparent mode.
	STA	TransparentDataFlag	;mod of 6/29/83

	DB	opJMP
EndBCCorCRCSwitch:
	DW	TxEndingCRCNext
;	DW	TxEndingCRCNext
;	DW	TxEndingBCCNext

TxEndingBCCNext:
	LXI	H,EndingBCC
	JMP	EndCheckSumSet
	
TxEndingCRCNext:
{Come here when we have sent the last character of the frame. The next time we get an interrupt for Transmit Buffer Empty, we will simply clear the interrupt. This will cause the CRC to be sent if we reset the Transmit Underrun/EOM bit.}

	MVI	A,ResetTxEOM
	OUT	TxCont

	LXI	H,EndingCRC

EndCheckSumSet:
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

EndingCRC:
{Reset TxUnderrunDetected. When the CRC has been sent, TxUnderrunDetectedFlag will be set again. This lets the Put routine know that the CRC has been sent and it is OK to begin sending the Filler characters.}
	XRA	A

TxEndOfFrame:
{Reset TxIntPending. This will cause the CRC to be sent if TxEOM is reset. The chip will then send whatever is loaded into WR6 and WR7. We will load WR6 and WR7 with filler characters. We must send at least 3 filler characters. We will set RestartSIOCharacter so that the Put routine will send a filler character to get us started again. Otherwise we will never get another wakeup. We also reset TxUnderrunDetected. When the CRC has been sent, TxUnderrunDetectedFlag will be set again. This lets the Put routine know that the CRC has been sent and it is OK to begin sending the Filler characters.}
	STA	TxUnderrunDetectedFlag
	LXI	H,8000H+TxCont
	MVI	A,Filler
	STA	RestartSIOCharacter
	MVI	M,PointToWR6
	MOV	M,A
	MVI	M,PointToWR7+ResetTxIntPending
	MOV	M,A
	LXI	H,SendFiller2
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

SendFiller2:
{Come here when the Put routine has restarted the chip by sending a filler character. Send the second filler character.}
	MVI	A,Filler
	OUT	TxData
	LXI	H,SendFiller3
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

SendFiller3:
{Send the last filler character.}
	MVI	A,Filler
	OUT	TxData
	
PutCompletedNext:
	LXI	H,PutCompleted
	SHLD	TxBisyncStateSwitch
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET

PutCompleted:
	MVI	A,ResetTxIntPending
	OUT	TxCont
	STA	PutCompletedFlag

ExitTxDataInt:
	POP	H
	POP	PSW
	EI			;Enable Interrupts
	RET
;
RxBisyncExternalInt:
{ Come here when we get an External/Status interrupt. Register RR0 indicates the cause of the interrupt:

08: 00001000	Data Carrier Detect (DCD)}

	IN	RxCont	;Read RR0
	ANI	DCD
	DB	opCPI		;Compare to previous DCD
PrevBisyncDCD:
	DB	0
	STA	PrevBisyncDCD	;Save current DCD
	MVI	A,ResetExternalStatusInterrupts
	OUT	RxCont
	JNZ	ExitBisyncInterrupt

{Continue if DataCarrierDetect has changed state. Notify the Get loop so that it will do a NakedNotify. We store ResetExternalStatusInterrupts in StatusChangeFlag.}
	STA	StatusChangeFlag

ExitBisyncInterrupt:
	MVI	A,38H		; Issue Return From Int Command (Ch-A Only)
	OUT	RxCont
	POP	H
	POP	PSW
	EI			;Enable interrupts
	RET
;
RxBisyncSpecialInt:
{ Come here when we get a Special interrupt. Register RR1 indicates the cause of the interrupt:

20: 00100000	RxOverrun
10: 00010000	Parity error

RxOverrun means data is being overwritten because the channel's three-byte receiver buffer is full and a new character is being received.

A Parity Error occurs when the parity bit of the character does not match with the programmed parity. Once this bit is set, it remains set until the Error Reset Command is given.}

	PUSH	D		;Save DE
{Read the character that caused the interrupt and place it in the RxFifo as we would a normal character.}
	IN	RxData		;A ← RxData
	STAX	B		;Store character in Fifo
	INX	B
	LXI	H,8000H+RxCont	;Point to RxCont register
	MVI	M,PointToWR1
	MOV	A,M		;Read CompletionCode from RR1
	ANI	0F0H
	MVI	M,ErrorReset
	JMP	SetBisyncCompletion	;In BisyncInput

	END