h04479
s 00781/00000/00000
d D 1.1 83/03/23 16:01:41 bog 1 0
c date and time created 83/03/23 16:01:41 by bog
e
u
4
U
t
T
I 1
	Title	HSALTO	Communications Driver
$Title('Operating System or Hardware Configuration Dependent Equates')
	.Z80
 
;Interrupt vector location inside the O/S.  Only the Receive Character
;  Available interrupt is used, thus the vector address should be
;  xxxx xxxx xxxx y100 where y is 1 if Ch A, 0 if Ch B.  In case the
;  other channel has set Status Affects Vector, both y100 and y110
;  should be set to point to the Isr.
SIOV	Equ	0ee4ch		;Interrupt vector location
SIOVPOv	Equ	SIOV+00002h	;Interrupt vector when overrun or parity
 
;Count for one-half millisecond delay in Foo: Dec A; Jr NZ,Foo loop
HalfMs	Equ	122
 
;Hardware I/O addresses available
Con1Sio	Equ	01ch	;Console #1	JX	Y7  17E (DART Ch A)
Con1Ctc	Equ	00ch	;			Y3  17J (CTC Ch 0)
Lp1Sio	Equ	01eh	;Printer #1	JT	Y7  17E (DART Ch B)
Lp1Ctc	Equ	00eh	;			Y3  17J (CTC Ch 2)
Lp2Sio	Equ	028h	;Printer #2	JV	Y10 17A (SIO Ch A)
Lp2Ctc	Equ	032h	;			Y12 20L (CTC Ch 0)
Lp2Int	Equ	02bh	;Wr2 interrupt vector
Con4Sio	Equ	02ah	;Console #4	JZ	Y10 17A (SIO Ch B)
Con4Ctc	Equ	031h	; (Shared with Con3)	Y12 20L (CTC Ch 1)
Con4Int	Equ	02bh	;Wr2 interrupt vector
Con2Sio	Equ	02ch	;Console #2	JY	Y11 17C (SIO Ch A)
Con2Ctc	Equ	030h	; (opt JW network port)	Y12 20L (CTC Ch 0)
Con2Int	Equ	02fh	;Wr2 interrupt vector
Con3Sio	Equ	02eh	;Console #3	JU	Y11 17C (SIO Ch B)
Con3Ctc	Equ	031h	; (Shared with Con4)	Y12 20L (CTC Ch 1)
Con3Int	Equ	02fh	;Wr2 interrupt vector
 
;Hardware I/O addresses used
SIOD	Equ	Con2Sio		;Data port
SIOC	Equ	SIOD+1		;Control port
SIOI	Equ	Con2Int		;Channel B for Rr2/Wr2 vector
Ctc	Equ	Con2Ctc		;Clock for Sio
 
;SIO and clock control equates
SelWr1	Equ	001h		;Select write register 1
IniWr1	Equ	018h		; Int on Rx chars; vector always xxxx y100
DisInt	Equ	000h		; Disable Rx, Tx, external interrupts
SelWr2	Equ	002h		;Select write register 2
IniWr2	Equ	Low SIOV	; Interrupt vector
SelWr3	Equ	003h		;Select write register 3
IniWr3	Equ	001h		; Rx enable
SelWr4	Equ	004h		;Select write register 4
IniWr4	Equ	000h		; No sync
SelWr5	Equ	005h		;Select write register 5
IniWr5	Equ	08ah		; DTR, Tx enable, RTS
BREAKOn	Equ	010h		; Send BREAK in Wr5
DTRWr5	Equ	080h		; Bit for DTR in Wr5
SelRr0	Equ	000h		;Select status register for read
TxBufMT	Equ	2		; Bit number for Tx buffer empty in Rr0
TxCTS	Equ	5		; Bit number for CTS on in Rr0
RxBREAK	Equ	7		; Bit number for BREAK received in Rr0
SelRr1	Equ	001h		;Select read register 1
RxPar	Equ	4		; Bit number for parity error in Rr1
RxOver	Equ	5		; Bit number for overrun error in Rr1
 
ResExts	Equ	010h		;Reset external/status interrupts, sel reg 0
ChReset	Equ	018h		;Channel reset, select register 0
ResErrs	Equ	030h		;Reset receive errors, select register 0
 
 
CtcCmd	Equ	057h		;Disable, ctr mode, pos edge, ld time, reset
 
$Title('GHxxxx/HSxxxx Dependent Equates')
;Queue equates
QLength	Equ	1024		;Allow a 1k char comm input queue
QXon	Equ	QLength/10	;Turn on hose when queue is 90% empty
QXOff	Equ	(QLength/4)*3	;Turn off hose when queue is 75% full
 
;Dimension of flag strings
FStDim	Equ	40		;40 ADE integer*2 characters
 
$Eject
$Title('HsRecv -- Return a Character from the Input Queue')
	CSeg
 
;Called by:
;	Call HsRecv(Ch,Error)
;		Output	Ch:	(^ in HL to) integer*2 ADE char
;				  in [BREAK,EMPTY,NUL..255]
;			Error:	(^ in DE to) integer*2 error code
;				  0:	No error
;				  1:	Parity error
;				  2:	Overrun error
;				  3:	Parity & overrun errors
;	    Return the next character from the host port or EMPTY if none.
;	    BREAK is returned if the port found a BREAK condition.
 
 
	Entry	HsRecv
HsRecv:	Push	IX		;Save registers -- index X
	Push	HL		; pointer to character parameter
	Push	DE		; pointer to error parameter
 
	Ld	HL,(QCount)	;Are there any characters there?
	Ld	A,H		;Check for zero
	Or	L
	Jr	NZ,MayXOn	;Jump if there is a character to return
	Ld	BC,EMPTY	;No char; return empty flag
	Ld	HL,0		; and no error
	Jr	Return
 
MayXOn:	Ld	A,(InStop)	;Have we sent an XOff?
	Or	A		;Non-zero if so
	Jr	Z,GivOne	;Jump if no XOff sent yet
 
	Ld	DE,-QXOn	;Low water mark
	Add	HL,DE		;Gone below XOn send point?
	Jr	C,GivOne	;Jump if not yet below XOn point
 
	Ld	A,(CIFMod)	;Is input flagging enabled?
	Or	A		;Non-zero if so
	Jr	Z,GivOne	;Jump if input flagging not enabled
 
	Call	HostGo		;Flag go:  send XOn or toggle DTR
	Xor	A		;Zero
	Ld	(InStop),A	; the input stopped flag
 
GivOne:	Di			; * Critical region
	Ld	HL,(QCount)	; *  Get count
	Dec	HL		; *  Decrement it
	Ld	(QCount),HL	; *  Stuff it back
	Ei			; * End critical region
	Ld	IX,(QTail)	;Get ptr to char word
	Ld	C,(IX)		;Get low-order byte
	Ld	B,(IX+1)	;Get high-order byte
	Call	IncPtr		;Wraparound increment HL
	Ld	(QTail),IX	; & stuff it back
 
; DE contains queue char word
	Ld	HL,0		;Assume no errors
	Bit	7,B		;BREAK?
	Jr	NZ,Return	;Yes -- return no error and BREAK
 
	Ld	L,B		;Error code to low order error code
	Ld	B,0		;Clear high half of character
 
; When arriving here, HL should contain error code and BC the character
Return:	Pop	IX		;Point to error parameter
	Ld	(IX),L		;Stuff error parameter
	Ld	(IX+1),H	; high byte
	Pop	IX		;Point to character
	Ld	(IX),C		;Stuff return character
	Ld	(IX+1),B	; high byte
	Pop	IX		;Restore index register
	Ret
$Eject
$Title('HsSend -- Send a Character to the Host')
;Called by:
;	Call HsSend(Ch,Error)
;		Input	Ch:	(^ in HL to) integer*2 ADE character
;				 in [BREAK,NUL..255]
;		Output	Error:	(^ in DE to) integer*2 busy flag
;				  -1:  busy; Ch not sent
;				   0:  Ch sent successfully
;	    Send a character out the host port
 
	Entry	HsSend
HsSend:	Push	IX		;Save index register
	Push	HL		;Pointer to char to send
	Pop	IX		; to index register
	Di			;Lock out input in critical region
	Ld	A,ResExts	;Have Rr0 show current CTS
	Out	(SIOC),A	; & select Rr0
	In	A,(SIOC)	;Get transmitter status
	Bit	TxBufMT,A	;Ready to send a character?
	Jr	NZ,HSFlMd	;Buffer empty.  Look for flagging
 
HSBusy:	Ld	A,-1		;Busy flag on in caller's variable
 
; Enter here with A containing 0 for not busy or -1 for busy
HSRetn:	Ei			;Reenable interrupts
	Ld	(DE),A		;Set busy or not busy
	Inc	DE		; in both halves
	Ld	(DE),A		; of caller's variable
	Pop	IX		;Restore index register
	Ret			; & return
 
HSFlMd:	Ld	HL,(COFMod)	;Look at output flagging mode
	Dec	L		; to -1: none, 0: string, 1: RTS/CTS
	Jp	M,HSTBrk	;Jump if no output flagging -- try BREAK
	Jr	Z,HSFStr	;Flagging with strings -- go check if stopped
 
				;Output RTS/CTS hardware flagging
	Bit	TxCTS,A		;Clear to send?
	Jr	Z,HSBusy	;Wait some more if not CTS
 
HSTBrk:	Ld	A,(IX+1)	;High byte of char to send to accum
	Inc	A		;Break?
	Ld	A,(IX)		;How about low byte -- preserve flags
	Jr	NZ,HSChar	;Jump if not break -- flags from Inc
	Cp	BREAK		;Is it a BREAK?
	Jr	Z,HSBreak	;Jump if yes
 
HSChar:	Out	(SIOD),A	;Poop out the char
 
HSSent:	Xor	A		;Not busy in caller's variable
	Jr	HSRetn		;Return setting not busy status
 
HSFStr:	Ld	A,(OutStop)	;Output flagged STOP?
	Or	A		;Non-zero if so
	Jr	NZ,HSBusy	;So spin until flag says GO
	Jr	HSTBrk		; else go ahead and send
 
HSBreak:
	Ld	A,SelWr5	;Select write register 5
	Out	(SIOC),A	; for setting BREAK
	Ld	A,(Wr5)		;Get the current write reg 5 value
	Or	BREAKOn		;Set the Sio as needed to send a break
	Ld	(Wr5),A		;Save it back in case someone else sets Wr5
	Out	(SIOC),A	;Turn on `send BREAK' bit
	Ei			;Now can enable interrupts
 
	Ld	HL,(CBkTim)	;Get BREAK time milliseconds
	Add	HL,HL		;Make it half milliseconds
 
BrkLpO:
	Ld	A,HalfMs	;Loop count for one-half millisecond
 
BrkLpI:	Dec	A		;Decrement inner loop count		 4t
	Jr	NZ,BrkLpI	; & loop until inner counted down	12t
 
	Dec	HL		;Decrement half-millisecond count
	Ld	A,H		;Test for zero
	Or	L		; both bytes
	Jr	NZ,BrkLpO	; & loop until BREAK timed out
 
	Di			;Disable interrupts
	Ld	A,SelWr5	;Select write register 5
	Out	(SIOC),A	; for resetting BREAK
	Ld	A,(Wr5)		;Get current Wr5 value
	And	0ffh-BREAKOn	;Turn off BREAK bit
	Ld	(Wr5),A		;Save for future users of Wr5
	Out	(SIOC),A	;Turn off `send BREAK' bit
	Jr	HsSent		;Return, enabling interrupts, not busy
 
$Eject
$Title('HsInit -- Initialize Communications Channel')
;Called by:
;	Call HsInit
;		Input	Parameters in Common /GHStat/
;	    Initialize communications channel with parameters in GHStat.
 
	Entry	HsInit
HsInit:	Ld	DE,(RBaudI)	;Baud rate index
	Ld	HL,Bauds-1	;1-base of divisor table
	Add	HL,DE		;Make indexed access
	Ld	A,(HL)		;Get divisor
	Ld	(Clk),A		;Save away
	Ld	HL,SIOClk-1	;1-base of SIO clock mode table
	Add	HL,DE		;Make indexed access
	Ld	A,(HL)		;Get SIO clock mode
 
	Ld	DE,(CurPar)	;Parity code
	Ld	HL,Parity	;0-base of parity table
	Add	HL,DE		;Make indexed access
	Or	(HL)		;Set parity bits in Wr4 appropriately
 
	Ld	DE,(StoBtI)	;Number of stop bits index
	Ld	HL,StopBits-1	;1-base of table
	Add	HL,DE		;Make indexed access
	Or	(HL)		;Set stop bits in Wr4
	Ld	(Wr4),A		;Save Wr4
 
	Ld	DE,(DatBtI)	;Number of data bits index
	Ld	HL,Dat3Bt-1	;1-base of table
	Add	HL,DE		;Make indexed access
	Ld	A,(HL)		;Get Wr3 data bits setting
	Ld	(Wr3),A		;Save Wr3
	Ld	HL,Dat5Bt-1	;1-base of table
	Add	HL,DE		;Make indexed access
	Ld	A,(HL)		;Get Wr5 data bits setting
	Ld	(Wr5),A		;Save Wr5
 
	Ld	A,CtcCmd	;Clock counter mode etc.
	Out	(Ctc),A		; to clock
	Ld	A,(Clk)		;Baud rate divisor
	Out	(Ctc),A		; to clock
 
; Set QHead, QTail, QCount
	Ld	HL,Queue	;Point at beginning of queue
	Ld	(QHead),HL	;Isr puts next char at (QHead)
	Ld	(QTail),HL	;HsRecv gets next char from (QTail)
	Ld	HL,0		;Queue initially empty
	Ld	(QCount),HL	; so count is zero
 
; Show neither direction currently Stopped
	Ld	(InStop),HL	;Clear input & output stopped flags
 
; Show no match so far for output stop/go string search
	Ld	(Matchd),HL	;Clear bytes matched so far count
	Ld	HL,COtStL	;Look for stop string
	Ld	(LookStr),HL	; since going
	Ld	HL,IsMStk	;Rescan stack initially
	Ld	(IsMTos),HL	; empty
 
; Reset our channel of the SIO
	Ld	A,ChReset	;Command channel reset
	Out	(SIOC),A	;Reset our channel of the SIO; must wait 4t
 
; Tell interrupt system we exist
	Ld	DE,(SIOV)	;Get old interrupt vector
	Ld	(SavVec),DE	; for HsStop
	Ld	DE,(SIOVPOv)	;Also Spec Recv Cond vector
	Ld	(SavVec1),DE	; should be saved
	Ld	DE,RxIsr	;SIO receive interrupt service routine
	Ld	(SIOV),DE	; pointed to in interrupt table
	Ld	(SIOVPOv),DE	; also in case of Spec Recv Cond
 
; Set up SIO completely
	Di			;No interrupts between accesses
	Ld	A,SelWr2	;Select Wr2 (may be in Ch B)
	Out	(SIOI),A	;Point to Wr2
	Ld	A,IniWr2	;Get initial value
	Out	(SIOI),A	;Stuff vector register
	Ld	HL,Commands	;Point to first command
	Ld	B,8		;Send 8 commands
	Ld	C,SIOC		; to SIO command port
	Otir			;Initialize Wr4, Wr5, Wr3, Wr1
	Ei
 
	Ret
$Eject
$Title('HsStop -- Close Communications Channel')
;Called by:
;	Call HsStop
;	    Close the open communications channel.
 
	Entry	HsStop
HsStop:	Di			;Disable interrupts during accesses
	Ld	A,SelWr1	;Select interrupt control register
	Out	(SIOC),A	;Wr1 is interrupt control
	Ld	A,DisInt	;Disable interrupts command
	Out	(SIOC),A	; into Wr1
	Ld	HL,(SavVec)	;Get old vector back
	Ld	(SIOV),HL	; for stock box
	Ld	HL,(SavVec1)	;Get old spec recv cond vector
	Ld	(SIOVPOv),HL	; & stuff it back, too
	Ei			;Re-enable interrupts
	Ret			; & return
 
$Eject
$Title('IncPtr -- Wraparound Increment QHead or QTail')
;Increment IX (QHead or QTail) and wrap around queue if necessary
; HL is crashed
 
IncPtr:	Inc	IX		;Point to next word
	Inc	IX
	Push	IX		;Incremented pointer
	Pop	DE		; to DE for arithmetic
	Ld	HL,QLast	;Addr of last char of queue to HL
	And	A		;Clear carry
	Sbc	HL,DE		;Last-Current
	Ret	NC		;Return if not beyond end
	Ld	IX,Queue	;Wrapped -- point at beginning
	Ret			; & return
$Eject
$Title('HostGo -- Set DTR or Send XOn or Go String to Host')
; May crash A, HL, BC
HostGo:	Ld	HL,CInGoL	;Point to go string
				;Fall through to send XOn or set DTR
 
; Send go or stop string or set or reset DTR bit
;  HL points to CInGoL or CInStL
XOnOff:	Ld	A,(CIFMod)	;Look at current input flagging mode
	Cp	2		;0: none, 1: string, 2: DSR/DTR
	Jr	Z,HoXoHw	;Jump if DSR/DTR flagging
 
; Can get here only if string flagging mode
	Ld	B,(HL)		;Get length of go/stop string; assume 0<n<257
 
HoXoSL:	Inc	HL		;Point to
	Inc	HL		; next char to send
	Push	BC		;Save loop count
	Push	DE		; & register
 
HoXoBL:	Push	HL		;Save pointer to string
	Ld	DE,Error	;Point to garbage error value
	Call	HsSend		;Send a character of go/stop string
	Pop	HL		;Restore pointer to string
	Ld	A,(Error)	;See if busy
	Or	A		;Non-zero if so
	Jr	NZ,HoXoBL	;Loop until not busy
	Pop	DE		;Restore busy pointer
	Pop	BC		;Get loop count back
	Djnz	HoXoSL		;Loop until string sent
	Ret			; & return
 
HoXoHw:	Di			;Turn off interrupts during cntl pair
	Ld	A,SelWr5	;Point to write register 5
	Out	(SIOC),A	;Select register 5
	Ld	A,(Wr5)		;Get current Wr5 value
	Xor	DTRWr5		;Complement DTR state
	Ld	(Wr5),A		;Save for future users of Wr5
	Out	(SIOC),A	;Set/reset Data Terminal Ready
	Ei			;Re-enable interrupts
	Ret			; & return to caller
$Eject
$Title('HostStop -- Reset DTR or Send XOff or Stop String to Host')
HostStop:
	Push	AF		;Save user Psw (crash ^HostStop)
	Push	HL		;Save user registers
	Push	DE
	Push	IX
	Push	BC
	Ld	HL,CInStL	;Point to input stop string
	Call	XOnOff		;Go send stop string or reset DTR
	Pop	BC		;Restore user registers
	Pop	IX
	Pop	DE
	Pop	HL
	Pop	AF		;Restore user Psw
	Ld	Sp,(TaskSp)	;Restore user stack
	Ret			;Return to user program
$Eject
$Title('RxIsr -- Receiver Interrupt Service Routine')
RxIsr:	Ld	(UserSp),Sp	;Save interrupted routine's Sp
	Ld	Sp,IsrStack	;Point to my stack
	Push	AF		;Save Psw
	Push	HL		;Save any registers used
	Push	IX		;Save index register
	Push	DE		; & scratch
	Ld	A,SelRr0	;Set up to read status register
	Out	(SIOC),A	; by pointing to read reg 0
	In	A,(SIOC)	;Get status, looking for BREAK
	Ld	D,A		;BREAK status in D
	Ld	A,SelRr1	;Set up to read error register
	Out	(SIOC),A	; by pointing to read register 1
	In	A,(SIOC)	;Get error status
	Rrca			;Move Overrun/Parity to bits 1/0
	Rrca
	Rrca
	Rrca
	And	3		;Mask to just Overrun/Parity
	Ld	HL,ORun		;Point to buffer overrun flag
	Or	(HL)		;OR in buffer overrun
	Ld	H,A		;Error status into H
	In	A,(SIOD)	;Data byte into A
	Ld	L,A		; then into L
	Ld	A,ResErrs	;Command to reset error flags
	Out	(SIOC),A	;Reset error flags
	Bit	RxBREAK,D	;Was BREAK set?
	Jr	Z,NBReset	;No -- bypass BREAK reset
	Ld	A,ResExts	;Command to reset external/status bits
	Out	(SIOC),A	;Reset BREAK latch
	Ld	HL,BREAK	; & return BREAK code
 
; HL contains word to buffer
NBReset:
	Ld	A,(COFMod)	;Get current output flagging mode
	Dec	A		;String output flagging?
	Jr	Z,IsMchL	;Go look for match if output string flagging
	Call	IsStuf		;Stuff HL in the buffer
 
IsrRet:	Pop	DE		;Restore registers
	Pop	IX
	Pop	HL
	Pop	AF
	Ld	Sp,(UserSp)	;Restore interrupted routine's stack
	Ei			;Re-enable interrupts
	Reti			; & return
 
;Stuff a received character in HL in the buffer
IsStuf:	Ld	DE,(QCount)	;Get count
	Inc	DE		;Increment it
	Ld	IX,-QXOff	;Test against hose turn-off value
	Add	IX,DE		;Current-XOffLevel
	Jr	NC,INXOff	;Jump if no XOff needed
 
	Ld	A,(InStop)	;XOff already?
	Or	A		;Non-zero if so
	Jr	NZ,INXOff	;Jump if no XOff needed
 
	Ld	A,(CIFMod)	;Input flagging enabled?
	Or	A		;Non-zero if so
	Jr	Z,INXOff	;Jump if flagging not enabled
 
;Make resume stack be HostStop stack so he will go rather than
; interrupted routine.  When he's done, he will return to interrupted
; routine.
	Push	HL		;Save error/data word
	Ld	HL,(UserSp)	;Get interrupted routine's Sp
	Ld	(TaskSp),HL	; to HostStop resume Sp
	Ld	HL,HoStack	;Point Isr resume at
	Ld	(UserSp),HL	; HostStop stack
	Ld	HL,HostStop	;Make Reti return to
	Ld	(HoStack),HL	; HostStop
	Ld	A,0ffh		;Flag input stopped to avoid
	Ld	(InStop),A	; re-entrancy problems
	Pop	HL		;Restore error/data word
 
INXOff:	Ld	IX,-(QLength+1)	;Test against Max+1
	Add	IX,DE		;Current-(Max+1)
	Sbc	A,A		;A -1 if full, 0 if not
	And	2		;ORun bit on if full
	Ld	(ORun),A	;Set overrun for next time
	Ret	NZ		;Don't stuff into queue if overrun; just quit
 
	Ld	(QCount),DE	;Queue is now one fuller
	Ld	IX,(QHead)	;Pointer to place to stuff
	Ld	(IX),L		;Save data byte in buffer
	Ld	(IX+1),H	;Save error flag byte in buffer
	Call	IncPtr		;Wraparound increment buffer pointer
	Ld	(QHead),IX	; & stuff pointer back for next time
	Ret			; & return
 
; Loop trying matches on current and any rescanned characters
IsMchL:	Call	IsMtch		;Try to match new character
	Call	PopRscn		;Pop rescan stack to HL
	Jr	NZ,IsMchL	;Jump if more matches to try
	Jr	IsrRet		; else return to interrupted routine
 
; HL contains new char to match against stop/go string
IsMtch:	Call	IsGMtch		;Get char to match and point IX to error code
	Cp	L		;Match?
	Jr	NZ,IsNMtch	;Jump if no
 
	Ld	(IX),H		;Save error byte in case later unmatch
 
	Inc	DE		;Matched another byte
	Ld	(Matchd),DE	;Save for next time through
 
	Ld	IX,(LookStr)	;See if full match.. point to match length
	Ld	L,(IX)		;Length into HL
	Ld	H,(IX+1)
	Scf			;Set carry
	Sbc	HL,DE		;Length-(number matched)-1
	Ret	NC		;Return if not yet complete match.. look more
 
	Ld	A,(OutStop)	;Get Stop Sending flag
	Cpl			; ..toggle it
	Ld	(OutStop),A	; ..& stuff it back
	Ld	HL,COtStL	;Assume looking for stop string
	Or	A		;Test for stopped or going
	Jr	Z,IsLSt		;Going.. looking for stop string
	Ld	HL,COtGoL	; else looking for go string
 
IsLSt:	Ld	(LookStr),HL	;Point to correct match string for next time
 
IsZMat:	Ld	HL,0		;No bytes matched so far
	Ld	(Matchd),HL	; ..stuff matched count
	Ret			; & return
	
; HL contains char which did not match.  DE (Matchd) contains count
;  of chars in LookSave and (LookStr) which must be rescanned.
;   Push HL, nth thru 2nd chars in LookSave and (LookStr) on IsMStk.
;   Deliver 1st char from LookSave and (LookStr) to Queue.
;  Then chars on IsMStk will be rescanned for potential matches.
IsNMtch:
	Ld	IX,(IsMTos)	;Get rescan stack pointer
	Dec	IX		; & decrement it
	Dec	IX
	Ld	(IsMTos),IX	;Save decremented rescan Sp
	Ld	(IX),L		;Push character to be rescanned
	Ld	(IX+1),H	; and error code
 
	Ld	A,D		;See if more to push
	Or	E		;Non-zero if so
	Jr	Z,IsNMQ		;Jump if done pushing
	Dec	DE		;Decrement match count
	Ld	(Matchd),DE	;No characters match so far
	Call	IsGMtch		;Get match character and point to error code
	Ld	L,A		;Character to rescan to L
	Ld	H,(IX)		;Get error code corresponding
	Jr	IsNMtch		; & go push char for rescan
 
IsNMQ:	Call	PopRscn		;Pop character from rescan stack for Queue
	Call	IsStuf		;Stuff first char of match string in Queue
	Ret			; & return for rescan if any
 
; Pop HL from rescan stack.  Z set and no pop if stack was empty.  Crash DE.
PopRscn:
	Ld	DE,(IsMTos)	;Get rescan Sp
	Ld	HL,IsMStk	;Get address of base of rescan Sp
	And	A		;Reset carry
	Sbc	HL,DE		;See if stack empty
	Ret	Z		;Return with Z set if stack empty
	Ex	DE,HL		;Rescan Sp to HL
	Ld	E,(HL)		;Get actual character
	Inc	HL		;Bump rescan Sp
	Ld	D,(HL)		;Get error code
	Inc	HL		;Bump rescan Sp for pop
	Ld	(IsMTos),HL	;Save rescan Sp after pop
	Ex	DE,HL		;Popped char & error code to HL
	Ret			; & return
 
; Get next match character into A and point IX at corresponding error slot
;  in LookSave
IsGMtch:
	Ld	IX,(LookStr)	;Get pointer to COtStL or COtGoL
	Ld	DE,(Matchd)	;Get count of chars matched so far
	Add	IX,DE		;Word pointer
	Add	IX,DE		; from byte index
	Ld	A,(IX+2)	;Get match character into A
	Ld	IX,LookSave	;Point to error code save area
	Add	IX,DE		;Point to error code slot corresponding
	Ret			; & return
$Eject
$Title('Fortran Common Parameters')
; Fortran length definitions
CHAR	Equ	1		;1-byte character
SMALL	Equ	1		;1-byte integer
INT	Equ	2		;2-byte integer
LONG	Equ	4		;4-byte integer
LOG	Equ	1		;1-byte logical
 
; Fortran funny characters
EMPTY	Equ	-1		;No characters ready
BREAK	Equ	-2		;BREAK condition
 
; Communications parameter area in Fortran Common
	Common	/GHStat/
COpen:	Dw	0		;NOT currently open
RBaudI:	Ds	INT		;Current receive baud rate index
CRBaud:	Ds	INT		;Current receive baud rate
TBaudI:	Ds	INT		;Current transmit baud rate index
CTBaud:	Ds	INT		;Current transmit baud rate
CurPar:	Ds	INT		;Current parity setting
DatBtI:	Ds	INT		;Current data bits per char index
CDatBt:	Ds	INT		;Current data bits per character
StoBtI:	Ds	INT		;Current stop bits per char index
CStoBt:	Ds	INT		;Current stop bits per character
CBkTim:	Ds	INT		;Current BREAK milliseconds
CIFMod:	Ds	INT		;Current receive flagging mode
COFMod:	Ds	INT		;Current transmit flagging mode
CInStL:	Ds	INT		;Current Rx stop str len
CInStS:	Ds	INT*FStDim	;Current Rx stop str
CInGoL:	Ds	INT		;Current Rx go str len
CInGoS:	Ds	INT*FStDim	;Current Rx go str
COtStL:	Ds	INT		;Current Tx stop str len
COtStS:	Ds	INT*FStDim	;Current Tx stop str
COtGoL:	Ds	INT		;Current Tx go str len
COtGoS:	Ds	INT*FStDim	;Current Tx go str
 
; Communications capability area in Fortran Common
	Common	/GHCmCp/
RBdCpL:	Dw	11		;Number of baud rates
RxBdCp:	Dw	134,150,200,300,600,1200,1800,2000,2400,4800,9600
	Dw	0,0,0,0		;Receive baud rate table(15)
TBdCpL:	Dw	0		;Transmit matches receive
TxBdCp:	Dw	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
ParCap:	Dw	-1		;Can change parity
DtBCpL:	Dw	4		;Number of data bit formats
DtBtCp:	Dw	5,6,7,8		;Data bit formats
StBCpl:	Dw	3		;Number of stop bit formats
StBtCp:	Dw	1,2,3		;1, 1.5, 2 stop bits
TxBkCp:	Dw	-1		;Can send BREAK
TBkTCp:	Dw	-1		;Can change break timing
RHwFCp:	Dw	-1		;Can hardware flag receive
RStFCp:	Dw	2		;Can arbitrary string flag receive
THwFCp:	Dw	-1		;Can hardware flag transmit
TStFCp:	Dw	2		;Arbitrary string flag transmit
SpFMCp:	Dw	-1		;Can have Rx & Tx flagging differ
 
$Eject
$Title('          Data Areas')
	DSeg
 
; Baud rate divisors for clocks
Bauds:
	Db	232		;134.5 baud (134.698 really -- 0.147% high)
	Db	208		;150 baud (150.240 really -- 0.160% high)
	Db	156		;200 baud (200.321 really -- 0.160% high)
	Db	208		;300 baud (300.481 really -- 0.160% high)
	Db	208		;600 baud (600.962 really -- 0.160% high)
	Db	104		;1200 baud (1201.923 really -- 0.160% high)
	Db	69		;1800 baud (1811.594 really -- 0.644% high)
	Db	63		;2000 baud (1984.127 really -- 0.794% low)
	Db	52		;2400 baud (2403.846 really -- 0.160% high)
	Db	26		;4800 baud (4807.692 really -- 0.160% high)
	Db	13		;9600 baud (9615.385 really -- 0.160% high)
 
; SIO clock settings & initial value for Wr4
SIOClk:
	Db	IniWr4+0c0h	;134.5 baud
	Db	IniWr4+0c0h	;150 baud
	Db	IniWr4+0c0h	;200 baud
	Db	IniWr4+080h	;300 baud
	Db	IniWr4+040h	;600 baud
	Db	IniWr4+040h	;1200 baud
	Db	IniWr4+040h	;1800 baud
	Db	IniWr4+040h	;2000 baud
	Db	IniWr4+040h	;2400 baud
	Db	IniWr4+040h	;4800 baud
	Db	IniWr4+040h	;9600 baud
	Db	IniWr4+040h	;19200 baud
 
; Parity setting in Wr4
Parity:	Db	000h		;No parity
	Db	001h		;Odd parity
	Db	003h		;Even parity
 
; Number of stop bits for Wr4
StopBits:
	Db	004h		;1 stop bit
	Db	008h		;1.5 stop bits
	Db	00ch		;2 stop bits
 
; Number of Rx data bits and Wr3 initial setting
Dat3Bt:	Db	IniWr3+000h	;5 data bits
	Db	IniWr3+080h	;6 data bits
	Db	IniWr3+040h	;7 data bits
	Db	IniWr3+0c0h	;8 data bits
 
; Number of Tx data bits and Wr5 initial setting
Dat5Bt:	Db	IniWr5+000h	;5 data bits
	Db	IniWr5+040h	;6 data bits
	Db	IniWr5+020h	;7 data bits
	Db	IniWr5+060h	;8 data bits
 
; Hardware register settings:  set at init, kept for futzing
Commands:			;Looped through at Init time
	Db	SelWr4		;Select Wr4
Wr4:	Db	0		;Stop bits, parity, etc.
	Db	SelWr5		;Select Wr5
Wr5:	Db	0		;Bits/char, Tx Enable, etc.
	Db	SelWr3		;Select Wr3
Wr3:	Db	0		;Bits/char etc.
	Db	SelWr1		;Select Wr1
	Db	IniWr1		;Interrupt enables, etc.
 
Clk:	Db	0		;Clock divisor
 
;Original interrupt vectors saved from O/S
SavVec:	Dw	0		;Saved interrupt vector
SavVec1:
	Dw	0		;Special Receive Condition interrupt vector
 
;Stacks for Isr and HostStop
	Ds	40		;40 bytes plenty for a 12-byte deep stack
IsrStack:			;Nothing on top of empty stack
 
	Ds	40		;40 bytes plenty for HostStop
HoStack:
	Dw	HostStop	;Reti to HostStop, not interrupted routine
 
;Error location for internal call to HsSend
Error:	Ds	2
 
;Saved stack pointers
UserSp:	Dw	0		;Interrupted routine's stack pointer
 
TaskSp:	Dw	0		;Interrupted routine's Sp if HostStop goes
 
;Output string flagging variables
LookStr:
	Ds	2		;Ptr to COtStL or COtGoL depending on OutStop
Matchd:	Ds	2		;Number bytes matching stop/go string so far
LookSave:
	Ds	FStDim		;Save area for error bytes in match string
IsMTos:	Ds	2		;Rescan stack pointer
	Ds	INT*FStDim	;Match search rescan stack
IsMStk	Equ	$		; ..works down, empty when IsMTos is zero
 
;Flag for buffer overran
ORun:	Ds	1		;2 if buffer has been overrun
 
;Stopped/going state of host hoses.  Must be ordered, adjacent.
InStop:	Db	0		;Non-zero if XOff has been sent
OutStop:			;Non-zero if output stop string received to
	Db	0		; stop our sending
 
;Queue state and buffer area
QHead:	Dw	0		;Pointer to place to put next input char
QTail:	Dw	0		;Pointer to next char to return
QCount:	Dw	0		;Number of words in queue
Queue:	Ds	QLength*2	;Comm input queue
QLast	Equ	$-1		;Last char in queue
 
; Encoding in queue:
;	-2	BREAK
;	0..255	data byte
;	| 256	parity error on data byte (ORed in)
;	| 512	overrun error on data byte (ORed in)
 
	End
E 1
