h20891
s 00001/00007/00404
d D 1.3 83/03/17 20:51:18 bog 3 2
c Actually removed stack.
e
s 00008/00024/00403
d D 1.2 83/03/17 19:03:57 bog 2 1
c Put stack burden upon caller and avoid switching stacks
e
s 00427/00000/00000
d D 1.1 83/03/17 14:37:47 tes 1 0
c date and time created 83/03/17 14:37:47 by tes
e
u
4
U
t
T
I 1
	Title	'GSX_Comm  GSX-86 Character I/O Module (CP/M-86)'

; Ch[7..4]	Layer number	1
; Ch[3..0]	Function code	5 (GSX-86 Pass Through)
; Dx	Dx	Datum to Send or Receive if appropriate subfunction and status
; Bl		Channel number	0..MAXCHAN
; Bh		Subfunction:
;		  0:	Reset channel	(unimplemented)
;		  1:	Immediately return receive READY status (Dx unchanged)
;		  2:	Wait until receive channel READY, then return
;			  receive status and datum
;		  3:	Immediately return receive status; if receive channel
;			  READY, then return datum also else Dx unchanged
;		  4:	Reserved
;		  5:	Immediately return send READY status
;		  6:	Wait until send channel READY, then send datum
;			  and return send status
;		  7:	Immediately return send status; if send channel READY,
;			  then send datum also
;	Ax	Status of channel (bits):
;		 On both send and receive subfunctions:
;		  0000 0000 0000 0000	Channel not ready.  Dx unchanged.
;		  1xxx xxxx xxxx xxxx	Ready.  Datum sent or received if
;					 not status only subfunction.
;		  1X.. .... .... ....	1:  No connection to channel
;		 On receive subfunctions:
;		  1.X. .... .... ....	1:  EOF received (if supported)
;		  1... .... .... .X..	1:  Framing error on received datum
;		  1... .... .... ..X.	1:  Overrun error on received datum
;		  1... .... .... ...X	1:  Parity error on received datum
;		 On send subfunctions:
;		  1.X. .... .... ....	1:  On channels with send queuing in
;					     either software or hardware, send
;					     queue neither full nor empty;
;					     i.e. not all data enqueued has
;					     been sent
;		  			0:  Send queue (if any) empty
; Bh		Subfunction:
;		  8:	Read buffer	(currently only works on Con:)
;					Does Bdos 10 into Ds:Dx
;	Flags	As if "Or Ax,Ax" had been done just before returning.

; Send or receive the character (up to 16 bits) in Dx according to the
; subfunction in Bx.

; Note that no other registers than the ones specified above are changed.  In
; particular, the direction flag is not changed.

; By convention for 8-bit serial devices a BREAK is sent as 0fffeh (-2) in
; Dx.  A received BREAK can be either 0fffeh (-2) in Dx or 0 in Dx with the
; Framing Error bit set in Ax.

; Note that if no device is assigned to the channel the status always returns
; with READY and NO_ CONNECTION.  On Send, data sent goes away.  On receive,
; data received is always 0001ah (^Z) and the EOF bit is set.

; This routine entered as if Callf with above.  It returns with a Retf.
I 2
; Approximately 28 words of stack space are required in the caller.
E 2

	Eject

Bdos_Int	Equ	224	; Bdos interrupt number

MAXCHANNEL	Equ	7
MAXFUNCTION	Equ	8

Ready_Bit	Equ	08000h
No_Conn_Bit	Equ	04000h
EOF_Bit		Equ	02000h
Framing_Bit	Equ	00004h
Overrun_Bit	Equ	00002h
Parity_Bit	Equ	00001h

Queue_NotMT_Bit	Equ	02000h

	Eject

GSX_Comm_Code	CSeg	Para	Public

Comm_Begin	Rb	0

Nul_Bit		Equ	0	; Nul: is zero in map
Con_Bit		Equ	1
Aux_Bit		Equ	2
Lst_Bit		Equ	4

Channel_to_Device_Map	Dw	Con_Bit	; Channel 0 is Con:
			Dw	Aux_Bit	; Channel 1 is Axi:/Axo:
			Dw	Lst_Bit	; Channel 2 is Lst:
			Dw	Con_Bit	; Channel 3 is Con: (graphics)
			Dw	Aux_Bit	; Channel 4 is Axi:/Axo: (graphics)
			Dw	Lst_Bit	; Channel 5 is Lst: (graphics)
			Dw	Nul_Bit	; Channel 6 is not connected
			Dw	Nul_Bit	; Channel 7 is not connected

Vector	Dw	Offset Nul_TStat	; Return Ax[15] Ready
	Dw	Offset Nul_TData	; Assume Ready; send Dx data
	Dw	Offset Nul_RStat	; Return Ax[15] Ready
	Dw	Offset Nul_RData	; Return Ax[15] Ready; Dx data if so

	Dw	Offset Always_Ready
	Dw	Offset Con_TData
	Dw	Offset Con_RStat
	Dw	Offset Con_RData

	Dw	Offset Always_Ready
	Dw	Offset Aux_TData
	Dw	Offset Always_Ready
	Dw	Offset Aux_RData

	Dw	Offset Always_Ready
	Dw	Offset Lst_TData
	Dw	Offset Nul_RStat
	Dw	Offset Nul_RData

	Eject

	Public	GSX_Comm
GSX_Comm:
D 2
	Push	Si		; Save two registers in caller's stack
	Push	Di

	Mov	Si,Ss		; Save pointer to caller's stack
	Mov	Di,Sp		;  in Si:Di

	Mov	Ax,Cs		; Point to my code segment
	Mov	Ss,Ax		;  for local stack
	Mov	Sp,Offset Top_Stack

E 2
	Pushf			; Save caller's flags
	Push	Bx		;  & registers
	Push	Cx
	Push	Dx
D 2
	Push	Si		;   (Caller's Ss
	Push	Di		;     & Sp)
E 2
I 2
	Push	Si
	Push	Di
E 2
	Push	Ds
	Push	Es
	Push	Bp
	Mov	Bp,Sp		; Make local frame

Old_Bp		Equ	Ss:(Word Ptr 0)[Bp]	; Caller's registers
Old_Es		Equ	Old_Bp+2
Old_Ds		Equ	Old_Es+2
D 2
Old_Sp		Equ	Old_Ds+2
Old_Ss		Equ	Old_Sp+2
Old_Dx		Equ	Old_Ss+2
E 2
I 2
Old_Di		Equ	Old_Ds+2
Old_Si		Equ	Old_Di+2
Old_Dx		Equ	Old_Si+2
E 2
Old_Cx		Equ	Old_Dx+2
Old_Bx		Equ	Old_Cx+2
Old_Flags	Equ	Old_Bx+2

	Eject

Switch:
	Mov	Ax,0ffffh	; Assume error in channel or function

	Mov	Si,Bx		; Si <- channel #
	And	Si,0ffh		; Mask to just channel
	Cmp	Si,MAXCHANNEL	; Valid channel?
	Ja	Error_Quit	; Quit if no

	Mov	Bl,Bh		; Bx <- Subfunction
	Mov	Bh,0
	Cmp	Bl,MAXFUNCTION	; Valid function?
	Ja	Error_Quit	; Quit if no

	Shl	Si,1		; Channel is word index
	Mov	Cx,Cs:Channel_to_Device_Map[Si]; Get device bit map

	Shl	Bx,1		; Subfunction is word index

	Sub	Di,Di		; Device index starts at 00000h

	Sub	Ax,Ax		; Start with Not Ready assumed

; Ax:	Not Ready assumed
; Bx:	Subfunction*2
; Cx:	Channel_to_Device bitmap
; Si:	Channel*2
; Di:	Device index (initially 00000h)

	Call	Cs:Call_Vector[Bx]; Vector on subfunction

Error_Quit:
	Pop	Bp		; Restore caller's registers
	Pop	Es		;   -- possibly changed
	Pop	Ds
D 2
	Pop	Di		;    (Caller's Sp
	Pop	Si		;      & Ss)
E 2
I 2
	Pop	Di
	Pop	Si
E 2
	Pop	Dx
	Pop	Cx
	Pop	Bx
	Popf

D 2
	Mov	Ss,Si		; Back to caller's stack
	Mov	Sp,Di

	Pop	Di		; Restore caller's Si
	Pop	Si		;  & Di

E 2
	Or	Ax,Ax		; Set caller's flags
D 2

E 2
	Retf			;  & return to caller

	Eject

; Scan status of devices connected to channel.  Return status of first one
; found Ready, or, if none Ready, Not Ready.  If no devices connected,
; return Ready via Nul_RStat.

Rx_IStat:		;  1  Rx immediate status only
	And	Ah,07fh		; Assume devs are Not Ready
	Jcxz	Rx_IStat_Call	; Call for Nul: if nothing connected

Rx_IStat_Loop:
	Add	Di,8		; Point to next device table entry
	Shr	Cx,1		; Shift next connection bit into carry

	Ja	Rx_IStat_Loop	; Spin if ~C&~Z -- not this dev & more to try

	Jnb	Rx_IStat_Ret	; Quit if ~C&Z -- out of devices

Rx_IStat_Call:
	Call	Cs:Vector+4[Di]	; Fetch this device status

	Jns	Rx_IStat_Loop	; Next dev if this Not Ready

Rx_IStat_Ret:
	Or	Ax,Ax		; Set S flag to Ready
	Ret			; Return Not Ready or first Ready

; Use Rx_IStat to wait for first device ready.  Then get the character
; from that device.

Rx_WData:		;  2  Rx wait for data and status
	Mov	Di,2		; Point at RData routine pointer
	Push	Cx		; Save Channel_to_Device_Map
	Call	Rx_IStat	; Get a character if Ready
	Pop	Cx		; Restore Channel_to_Device_Map
	Jns	Rx_WData	; Retry if not ready
	Mov	Old_Dx,Dx	; Ready -- return character to caller
	Ret			; Return Ready and Data

; Use Rx_IStat to see if some device is Ready.  If so, read from the
; device.

Rx_IData:		;  3  Rx immediate status; data if available
	Mov	Di,2		; Point at RData routine pointer
	Call	Rx_IStat	; Get a character if Ready
	Jns	Rx_IData_Return	; Quit if not ready
	Mov	Old_Dx,Dx	; Ready -- return character to caller

Rx_IData_Return:
	Ret			; Return Ready and Data or Not Ready

	Eject

; Scan status of devices connected to channel.  Return status of Ready if all
; are found Ready, of, if one or more is Not Ready, Not Ready.  If no device
; is connected, return Ready via Nul_RStat.

Tx_IStat:		;  5  Tx immediate status only
	Jcxz	Tx_IStat_Call	; Call for Nul: if nothing connected

Tx_IStat_Loop:
	Add	Di,8		; Point to next device table entry
	Shr	Cx,1		; Shift next connection bit into carry

	Ja	Tx_IStat_Loop	; Spin if ~C&~Z -- not this dev & more to try

	Jnb	Tx_IStat_Ret	; Quit if ~C&Z -- out of devices

Tx_IStat_Call:
	And	Ah,07fh		; Assume devs are Not Ready
	Call	Cs:Vector[Di]	; Fetch this device status

	Js	Tx_IStat_Loop	; Next dev if this Ready

Tx_IStat_Ret:
	Or	Ax,Ax		; Set S flag to Ready
	Ret			; Return Not Ready or All Ready

; Spin until all devices are Ready.  Then send each the character.

Tx_WData:		;  6  Tx wait until ready, send, status
	Push	Cx		; Save Channel_to_Device_Map
	Sub	Di,Di		; Start with Nul:
	Call	Tx_IStat	; Look at device status
	Pop	Cx		; Restore original Channel_to_Device_Map
	Jns	Tx_WData	; Spin until ALL Ready

Tx_GData:
	Mov	Di,2		; Start with Nul_TData
	Call	Tx_IStat	; Poop out to all devices
	Ret			;  & return

; Use Tx_IStat to see if all devices are Ready.  If so, send the character.

Tx_IData:		;  7  Tx immediate status; send if ready
	Call	Tx_IStat	; See if all devices Ready
	Js	Tx_GData	; If so, send to all
	Ret			;  else return 

Error:	Dec	Ax		; Return -1 in Ax if bad function

Reset:	Ret			; Return with value in Ax

; ********************* T E M P O R A R Y ************ (sure...)
Get_Buffer:
	Mov	Cl,10		; Bdos "Get Console Buffer" function
	Int	Bdos_Int	; Get buffer
	Jmps	Always_Ready	; Return Ready on

	Eject

Nul_RStat:			; Received status of Nul:
	Or	Ax,EOF_Bit	; Receive from Nul: gives EOF

Nul_TStat:
	Or	Ax,No_Conn_Bit	; Nul: never connected

Always_Ready:

Nul_TData:
	Or	Ax,Ready_Bit	; If no status avail from Bdos, always ready
	Ret

Nul_RData:
	Mov	Dx,0001ah	; ^Z is only char received from Nul:
	Jmps	Nul_TData	; Set Ready & return

Con_RStat:
	Push	Dx		; Save caller's Dx
	Mov	Dh,6		; Bdos "Direct Console I/O" function
	Mov	Dl,0feh		; Enquire status subfunction
	Call	All_RData	; Use common Bdos caller

	And	Dl,080h		; Dh <- ready ? 080h : 000h

	Or	Ah,Dl		; Turn on Ready_Bit if Con: ready
	Pop	Dx		; Restore caller's Dx
	Ret

	Eject

Aux_RData:
	Mov	Dh,3		; Bdos "Get Axi: Character" function
	Call	All_RData	; Get data
	Or	Ax,Ready_Bit	; Force status ready
	Ret			;  & return

Con_RData:
	Mov	Dh,6		; Bdos "Direct Console I/O" function
	Mov	Dl,0ffh		; Bdos "Get Console Character" subfunction
	Call	All_RData	; Get status and data
	Or	Dx,Dx		; Ready?
	Jz	Con_RData_Return; Return if not
	Or	Ax,Ready_Bit	; Set Ready in Ax

Con_RData_Return:
	Ret			; Return with Ready in Ax[15] and data in Dx

All_RData:
	Push	Ax		; Save registers
	Push	Bx
	Push	Cx
	Push	Si
	Push	Di

	Mov	Cl,Dh		; Bdos function into Cl
	Int	Bdos_Int	; Bdos Get Character from somewhere

	Mov	Dl,Al		; Character into Dl
	Mov	Dh,000h		; Clear high half

	Pop	Di
	Pop	Si
	Pop	Cx
	Pop	Bx
	Pop	Ax
	Ret

	Eject

Lst_TData:
	Push	Dx		; Save caller's Dx
	Mov	Dh,5		; Bdos "List Output" function
	Jmps	All_TData	; Go to common put

Aux_TData:
	Push	Dx		; Save caller's Dx
	Mov	Dh,4		; Bdos "Axo: Output" function
	Jmps	All_TData	; Go to common put

Con_TData:
	Push	Dx		; Save caller's Dx
	Mov	Dh,6		; Bdos "Direct Console I/O" function

All_TData:
	Call	All_RData	; Poop out a character
	Or	Ax,Ready_Bit	; Flag device as Ready for looping
	Pop	Dx		; Restore caller's Dx
	Ret			;  & return

	Eject

Call_Vector	Rw	0	; Vectors to each subfunction
	Dw	Offset Reset	;  0  Reset channel
	Dw	Offset Rx_IStat	;  1  Rx immediate status only
	Dw	Offset Rx_WData	;  2  Rx wait for data and status
	Dw	Offset Rx_IData	;  3  Rx immediate status; data if available
	Dw	Offset Error	;  4  (Reserved)
	Dw	Offset Tx_IStat	;  5  Tx immediate status only
	Dw	Offset Tx_WData	;  6  Tx wait until ready, send, status
	Dw	Offset Tx_IData	;  7  Tx immediate status; send if ready
	Dw	Offset Get_Buffer; 8  Bdos "Get Console Buffer" call

Comm_Here	Rs	0

D 3
		Rs	((Offset Comm_Here)-(Offset Comm_Begin)) And 1

		Rs	128	; Reserve room for local stack

Top_Stack	Rw	0

E 3
			Public	GSX_Comm_Paragraphs
D 3
GSX_Comm_Paragraphs	Equ	((Offset Top_Stack)-(Offset Comm_Begin)+15)/16
E 3
I 3
GSX_Comm_Paragraphs	Equ	((Offset Comm_Here)-(Offset Comm_Begin)+15)/16
E 3

	End
E 1
