{  File: [Iris]<WMicro>DLion>TTYTask.asm
Modification History:
Dennis Grundler:  1-Sep-84 17:17:29: Added copyright notice.
Jim Frandeen: October 7, 1982  9:14 AM: Fix SendBreak. Implement AbortPut command. Refresh TTY device status after On and after SetParameters.
Jim Frandeen: August 4, 1982  3:27 PM: new IO Page
Jim Frandeen: 22-Jun-82 15:23:09: add Break command 6
Rewritten by Jim Frandeen: April 1, 1982  8:09 AM
Created  by Ken Yamanaka: August 7, 1980  11:22 AM
}

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


	Get "SysDefs"		; system defs
	Get "CommonDefs"		; Common defs

	IMP	DoNakedNotify	; From CPSubs
	IMP	HLPlus2A		; From RS232CSubs
	IMP	PortBusyFlag	; From CPSubs
	IMP	ReadCPBuffer	; From CPsubs
	IMP	TTYCommand	; From Common
	IMP	TTYOutData	; From Common
	IMP	WriteCPBuffer	; From CPsubs

TTYInTask:
	DB	opJMP		;JMP TTYInTaskYield
TTYInTaskActiveSwitch:
	DW	TTYInTaskYield
;	JMP	BeginTTYInTask

	 
TTYOutCSB:	
{The TTY CSB is read in for some TTY commands.}
TTYParameter: 
	DS	1		;14022 low 
TTYParameterHi:
	DS	1		;14022 high byte
TTYTaskWakeMask:
	DS	2		;14023

TTYInCSB:
{The TTY In CSB is written to the IOPage when TTY input or status is ready to send to the CP.}

TTYInStatus:
	DB	0		;14024 low 
TTYInDataReady:
{TTYInDataReady is set to 80H by the TTYInTask when a character is ready to send to the CP. The CP resets this byte when the character has been processed. The TTYIn Task will not send a new character to the CP until this byte is zero.}
	DB	0		;14024  high 
TTYDeviceStatus:
	DB	0		;14025 low
TTYInData:
	DB	0		;14025 high 

BKDet 	EQU	40H		;Break Detected
BreakCode EQU	0		;Break Code
CRCode	EQU	0DH		;Carrige Return Code
CTS	EQU	20H		;Clear To Send Command (RTS)
DefaultBaud EQU	7		;Default Baud Rate index
DefaultMode EQU	0CAH		;2 stop, parity none, 7 bits, 16X
DSR	EQU	2		;Data Set Ready Command (DTR)
DTR	EQU	80H		;Data Terminal Ready Flag of UART Status (DSR)
EReset	EQU	10H		;Error Reset Command
FE	EQU	20H		;Framing Error
LFCode	EQU	0AH		;Line Feed Code
OE	EQU	10H		;Rx Over Run Error bit
OSCcmd	EQU	36H		;Counter#0, LSB & MSB, Mode3, Binary
PE	EQU	8H		;Parity Error bit
Reset0	EQU	80H		;First character of reset sequence
Reset1	EQU	0		;Second character of reset sequence
Reset2	EQU	40H		;Third character of reset sequence
SendBK	EQU	8H		;Send Break Command
SUBCode	EQU	1AH		;Erase Screen Code
RxEnable	EQU	4	;Rx Enable Command
RxError	EQU	PE+OE+FE+BKDet	;Framing, Overrun, Parity Error and Break detected
RxRDY	EQU	2		;Rx Ready Status
TxEmpty     EQU	4		;Tx TTYData Empty Status
TxEnable	EQU	1	;Tx Enable Command
TxRDY	EQU	1		;Tx Ready Status
UARTOff	EQU	0		;Rx/Tx Disable, CTS off.
DefaultCommand EQU  CTS+RxEnable+TxEnable ;  Rx /TxEnable, CTS On.


{Internal Constants}
FlagMask	EQU	80H		;FlagMask
DoneMask	EQU	7FH		;Flag erase Mask
KindMask	EQU	7H		;Kind of Parameter Separate Mask
ValueMask	EQU	0FH		;Parameter Value Mask
CPCTSMask	EQU	2		;CP clearToSend change Value Mask
CPDSRMask	EQU	1		;CP dataSetReady change Value Mask
InitialCount	EQU	0FFH		;Initial Count of Interval Counter
TimeToSend	EQU	InitialCount+1	;Up to date count of Interval Counter

; [UART Mode Clear Mask]
StopBitClear	EQU	3FH		;Stopbit Mode bit clear Mask
ParityClear	EQU	0CFH		;Parity Mode bit clear Mask
CharLClear	EQU	0F3H		;Character Length Mode bit clear Mask

; [ UART Mode Mask]
StopBitMask	EQU	0C0H		;Stopbit Mode bit Separate  Mask
ParityMask	EQU	30H		;Parity Mode bit Separate  Mask
CharLMask	EQU	0CH		;Character Length Mode bit Separate  Mask

BaudMask	EQU	0FH		;Baud RateMode bit Separate  Mask

; [Head Command]
PutCommand	EQU	80H		;Character Put Command
SetParameter	EQU	81H		;SetParameter Command
On	EQU	83H		;On Command
Off	EQU	84H		;Off Command
AbortPut	EQU	85H		;Off Command
TTYBreakOn	EQU	86H	;Break On command
TTYBreakOff	EQU	87H	;Break Off command

; [Head Status]
NotReady	EQU	1		;UART Not Ready Status
ParityError	EQU	8H		;Parity ErrorStatus
DataLost	EQU	10H		;Rx Overrun Error Status
FrameErr	EQU	20H		;Framing Error Status
BreakDet	EQU	40H		;UART Break Detected Status
Success	EQU	80H		;R/W Succeeded Status
FullFlag	EQU	80H		;Character Full Flag on Get Command

; [Parameter Change Mask]
DTRChangeMask	EQU	1	;Change DTR Mask
RTSChangeMask	EQU	2	;Change RTS Mask
CharacterChangeMask  EQU	4	;Change Character Length Mask
ParityChangeMask 	EQU	8H	;Change Parity Mask
StopBitChangeMask	EQU	10H	;Change Stop Bits Mask
BaudChangeMask	EQU	20H	;Change BaudRate Mask

; [SetParameter constants]
SetOnlyCommand	equ	1	;Set only the Command
SetModeCommand	equ	3	;Set both Mode and Command

; [Internal Storage Area]
CurrentMode:
	DB	0		;For UART Current Mode
CurrentCommand:
	DB	0		;For UART Current Command

ResetCommand:
	DB	Success		;Success status in low byte
	DB	0		;Reset full flag in high byte

; PCB to read TTY Out CSB
ReadTTYOutCSB:
	DW	TTYOutCSBLoc	;CP Buffer Pointer(Low)
	DW	CPIOPageHi	;CP Buffer Pointer(Hi)
	DW	TTYOutCSBSize	;CP Buffer Count (Bytes)
	DW	TTYOutCSB	;Pointer to IOP Buffer

; PCB to Reset TTY Out Command and return Status in low byte
ResetTTYCommand:
	DW	TTYCommandLoc	;CP Buffer Pointer(Low)
	DW	CPIOPageHi	;CP Buffer Pointer(Hi)
	DW	2		;CP Buffer Count (Bytes)
	DW	ResetCommand	;Pointer to IOP Buffer

ReadTTYInCSB:
	DW	TTYInCSBLoc	;CP Buffer Pointer(Low)
	DW	CPIOPageHi	;CP Buffer Pointer(Hi)
	DW	TTYInCSBSize	;CP Buffer Count (Bytes)
	DW	TTYInCSB	;Pointer to IOP Buffer

SendTTYDeviceStatus:
	DW	TTYDeviceStatusLoc	;CP Buffer Pointer(Low)
	DW	CPIOPageHi	;CP Buffer Pointer(Hi)
	DW	2		;CP Buffer Count (Bytes)
	DW	TTYDeviceStatus	;Pointer to IOP Buffer
;
BeginTTYInTask:
	LDA	PortBusyFlag
	ORA	A
	JNZ	TTYInTaskYield	;Jump if port is busy

	IN	IntReq		;Watch Condition of USART
	ANI	PtrRxReqMask
	JNZ	CheckTTYStatus	;IF Not RxRDY check status

	LXI	H,ReadTTYInCSB	;Read TTY In CSB
	CALL	ReadCPBuffer
	LDA	TTYInDataReady	;Check CP Ready
	ORA	A		;See if CP has processed last char
	JM	TTYInTaskYield	;If  Not Ready, Yield 

	MVI	A,80H
	STA	TTYInDataReady	;Set flag: DataReady
	STA	TTYInStatus	;Assume Success

	IN	PrinterData	;Read character
	STA	TTYInData

	IN	PrinterStatus	;Check Error
	ANI	RxError
	JZ	SendTTYInData

	STA	TTYInStatus	;Error bit set
	LDA	CurrentCommand	; Issue Error Reset Command
	ORI	EReset		; Error Reset bit Set
	OUT	PrinterCommand

SendTTYInData:
	LXI	H,ReadTTYInCSB
	CALL	WriteCPBuffer
	LHLD	TTYTaskWakeMask
	CALL	DoNakedNotify
	JMP	TTYInTaskYield
;
RefreshTTYDeviceStatus:
{Device Status Refresh Routine
This routine refreshes the contents of Device Status in Main memory intermittently. This task is not executed when a character is received, and it is not executed when the Tx buffer is not  empty because CTS cannot be checked. The counter resets itself to zero when it gets up to FF. When we come here, we know the port is free.}
	IN	PrinterStatus	;IF Yes, Read UART Status
	STA	TTYDeviceStatus	;and check TxBuffer Empty
	ANI	TxEMPTY		;IF Not Empty, Cannnot check CTS
	RZ			;Because TxRDY Pin =TxEmpty (CTS=0)(TxEn=1)
	IN	IntReq		;Watch Condition of USART
	ANI	PtrTxReqMask	;IF TxNot Ready, then CTS might be Off.
	JZ	SendTTYStatus	;IF Tx Ready, then CTS might be On.

CTSOff:
	LDA	TTYDeviceStatus	;Reset clearToSend bit
	SUI	TxEMPTY
	STA	TTYDeviceStatus

SendTTYStatus:
	LXI	H,SendTTYDeviceStatus
	JMP	WriteCPBuffer	;and RET

CheckTTYStatus:
	DB	opMVIA		;A ← IntervalCounter
IntervalCounter:
	DB	0
	INR	A
	STA	IntervalCounter
	CZ	RefreshTTYDeviceStatus	;IF No, Check Count value

TTYInTaskYield:

;
TTYOutTask:
	LDA	PortBusyFlag
	ORA	A
	JNZ	TTYOutTaskYield

{For the rest of TTYOutTask, we know we can use the CP Port.}
	DB	opJMP		;  JMP BeginTTYOutTask
TTYOutTaskResumeAddress:
	DW	BeginTTYOutTask
;	JMP	WaitForPrinter

BeginTTYOutTask:
	LDA	TTYCommand	; Check if bit 0 #0
	ORA	A		; Set Flags
	JP	TTYOutTaskYield	; z => Don't Activate the TTY task.

	CPI	PutCommand
	JZ	TTYPutTask

	LXI	H,ReadTTYOutCSB
	CALL	ReadCPBuffer		;Read the CSB

	LDA	TTYCommand	;Check the requested command
	CPI	SetParameter
	JZ	TTYSetParameter
	CPI	Off
	JZ	TTYOff
	CPI	TTYBreakOn
	JZ	TurnOnBreak
	CPI	TTYBreakOff
	JZ	TurnOffBreak

TTYOn:
	MVI	A,InitialCount		;Send Status on first entry to TTYInTask
	STA	IntervalCounter
	MVI	A,DefaultBaud	; Set Default Frequency into OSC
	CALL	SetBaud
	MVI	A,DefaultMode	; Set Default Mode & Command...
	STA	CurrentMode	; ... into UART
	MVI	A,DefaultCommand
	STA	CurrentCommand
	CALL	RefreshTTYDeviceStatus
	LXI	H,BeginTTYInTask
	SHLD	TTYInTaskActiveSwitch
	JMP	ResetTTYOutFlag
	
TurnOnBreak:
	LDA	CurrentCommand
	ORI	SendBK
	OUT	PrinterCommand
	JMP	ResetTTYOutFlag
	
TurnOffBreak:
	LDA	CurrentCommand
	OUT	PrinterCommand
	JMP	ResetTTYOutFlag
	
TTYSetParameter:
	LDA	TTYOutData
	ANI	BaudChangeMask
	CNZ	ChangeBaudRate	; No UART Mode or Command
	LDA	TTYOutData
	ANI	StopBitChangeMask
	CNZ	ChangeStopBit		; UART Mode, Command
	LDA	TTYOutData
	ANI	ParityChangeMask
	CNZ	ChangeParity		;UART Mode, Command
	LDA	TTYOutData
	ANI	CharacterChangeMask
	CNZ	ChangeCharLength	;UART Mode, Command
	LDA	TTYOutData
	ANI	RTSChangeMask
	CNZ	ChangeRTS		;UART Command
	LDA	TTYOutData
	ANI	DTRChangeMask
	CNZ	ChangeDTR		;UART Command

{  This sequence will guarantee correct initialization after both a hardware (expecting Mode), or a software (expecting Command) reset. After the subroutne is executed, a command must be sent to the UART.}
	LXI	H,8000H+PrinterCommand
	MVI	M,Reset0		; Reset UART
	MVI	M,Reset1
	MVI	M,Reset2
	NOP			; Needed for B-step chips
	LDA	CurrentMode	; Set UART Mode
	MOV	M,A
	LDA	CurrentCommand	; Set UART Command
	MOV	M,A		;Send command
	CALL	RefreshTTYDeviceStatus
	JMP	ResetTTYOutFlag


;  RTS bit:
ChangeRTS:
	LDA	TTYParameter	;Check required RTS Condition
	ANI	CPCTSMask
	MOV	D,A
	LDA	CurrentCommand 	;Check Current RTS Condition
	ANI	CTS
	ADD	D
	RZ			;z => no change
	CPI	CPCTSMask+CTS	; IF both 1, make no change as well
	RZ			;  z => no change
	CPI	CPCTSMask	; IF required=1, current=0
	JZ	SetRTS		; ..then must be set
ResetRTS:
	LDA	CurrentCommand	; IF required =0, current=1...
	SUI	CTS		; ..then must be reset.
FinishRTS:
	STA	CurrentCommand
	RET

SetRTS:
	LDA	CurrentCommand	; Set routine
	ADI	CTS
	JMP	FinishRTS

ChangeDTR:
	LDA	TTYParameter	;Check required DTR Condition
	ANI	CPDSRMask
	MOV	D,A
	LDA	CurrentCommand 	;Check Current DTR Condition
	ANI	DSR
	ADD	D
	RZ			;z => no change
	CPI	CPDSRMask+DSR	;IF both 1, make no change as well
	RZ			;z => no change
	CPI	CPDSRMask	;IF required=1, current=0
	JZ	SetDTR		;..then must be set
ResetDTR:
	LDA	CurrentCommand	;IF required =0, current=1...
	SUI	DSR		;..then must be reset.
	JMP	FinishRTS

SetDTR:
	LDA	CurrentCommand	;Set routine
	ADI	DSR
	JMP	FinishRTS

;  Stop bits:  (change both Mode and Command)
ChangeStopBit:
	LDA	CurrentMode	;Stop bits mode change
	ANI	StopBitClear	;Clear old contents of Stopbit
	MOV	D,A
	LDA	TTYParameter	;Set new Stopbits Mode
	ANI	StopBitMask
FinishStopBit:
	ORA	D
	STA	CurrentMode	;Rewrite Current Mode
	RET

;  Parity bit:  (change both Mode and Command)
ChangeParity:
	LDA	CurrentMode	; Parity mode Change
	ANI	ParityClear	; Clear old contents of Parity
	MOV	D,A
	LDA	TTYParameter
	ANI	ParityMask	; Set new Stopbits Mode
	JMP	FinishStopBit

;  Character length:  (change both Mode and Command)
ChangeCharLength:
	LDA	CurrentMode	; Character Length mode change
	ANI	CharLClear	; Clear old contents of Character Length
	MOV	D,A
	LDA	TTYParameter
	ANI	CharLMask	; Set new Character Length Mode
	JMP	FinishStopBit

ChangeBaudRate:
	LDA	TTYParameterHi	; OSC frequency change
	ANI	BaudMask
{Fall through to SetBaud.}

SetBaud:
{  This Routine sets suitable Frequency Divisor and Oscillation Modefor i8253 Programmable  Interval Timer. On entry, A = Baud rate.}
	LXI	H,Divisor
	CALL	HLPlus2A	;HL ← HL + 2*CurrentBaud
	MVI	A,OSCcmd
	OUT	TimerMode		
	MOV	A,M		; A ← ((H,L))
	OUT	TimerCount0
	INX	H		; H,L ← (H,L)+1
	MOV	A,M		; A ← MSB, 
	OUT	TimerCount0
	RET			

Divisor:
{ Asynchronous Mode ( SIO 16Xmode)  Divisors Table 
Unfortunately, this is not quite like the table in RS232CSubs} 
	DW	2304		; Divisor for 50Hz
	DW	1536		; Divisor for 75Hz
	DW	1047		; Divisor for 110Hz
	DW	856		; Divisor for 134.5Hz
	DW	768		; Divisor for 150Hz
	DW	384		; Divisor for 300Hz
	DW	192		; Divisor for 600Hz
	DW	96		; Divisor for 1200Hz
	DW	64		; Divisor for 1800Hz
	DW	58		; Divisor for 2000Hz
	DW	48		; Divisor for 2400Hz
	DW	32		; Divisor for 3600Hz
	DW	24		; Divisor for 4800Hz
	DW	16		; Divisor for 7200Hz
	DW	12		; Divisor for 9600Hz
	DW	6		; Divisor for 19200Hz

TTYOff:
	LXI	H,TTYInTaskYield
	SHLD	TTYInTaskActiveSwitch
	MVI	A,UARTOff		;TTYOff  Command
	OUT	PrinterCommand
	JMP	ResetTTYOutFlag

PrinterNotReady:
	LXI	H,WaitForPrinter
	SHLD	TTYOutTaskResumeAddress
	JMP	TTYOutTaskYield

WaitForPrinter:
	IN	IntReq		; Watch Condition of USART
	ANI	PtrTxReqMask
	JZ	SendCharacter
	LDA	TTYCommand
	CPI	AbortPut
	JNZ	TTYOutTaskYield

	JMP	InitializeOutTaskResumeAddress

TTYPutTask:
{ PutCommand : Send one character to the Printer.} 
	IN	IntReq		; Watch Condition of USART
	ANI	PtrTxReqMask
	JNZ	PrinterNotReady	

SendCharacter:
	LDA	TTYOutData	; Character Data Load
	OUT	PrinterData		; Data Send to TTY

InitializeOutTaskResumeAddress:
	LXI	H,BeginTTYOutTask
	SHLD	TTYOutTaskResumeAddress	
ResetTTYOutFlag:
	LXI	H,ResetTTYCommand
	CALL	WriteCPBuffer
	LHLD	TTYTaskWakeMask
	CALL	DoNakedNotify

TTYOutTaskYield:
{Pass control to the next task specified in Domino.cfg}
	DS	0

	END