DataMuseum.dk

Presents historical artifacts from the history of:

CP/M

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about CP/M

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦7183671ab⟧ TextFile

    Length: 49152 (0xc000)
    Types: TextFile
    Names: »CHARIO.Z80«

Derivation

└─⟦21f5a1bd4⟧ Bits:30003500 CP/M Plus (tm) Version 3.0 BIOS Revision F
    └─ ⟦this⟧ »CHARIO.Z80« 
└─⟦67f37b9ce⟧ Bits:30003503 JET80/W20FT systemdisk
    └─ ⟦this⟧ »CHARIO.Z80« 

TextFile

	Title	Chario.Z80
;------------------------------------------------------------;
; This module takes care of all character I/O functions for  ;
; CP/M 3.0 .                                                 ;
; A table of device names is defined together with a device  ;
; handler table with addresses and and routines.             ;
; The interrupt driven keyboard and aux-input routine is     ;
; here.                                                      ;
; The global subroutine 'IniStm' is also located here.       ;
;------------------------------------------------------------;
; Latest update: 1985-11-15. PSW
; Biosrevision: F
;
	.Z80
False		Equ	0
True		Equ	Not False
NetWork		Equ	False
WrkStn		Equ	False


GrOBufZ		Equ	1		; Graphic output buffer size (1-255 is ok)

	Entry	?Cinit,?CI,?CO,?CiSt,?CoSt	; Procedures
	Entry	@CTbl
	Entry	IniStm,Bank0Call
	Entry	SetLptBuff,UFunc

	Entry	KbdIrq,UnkInt,LptIrq		; Interrupts
	Entry	KbdErRq,LptErRq,ClkIrq

	If	Not WrkStn
	Entry	PioGAI,PioGBI

	Entry	PIAVec,PIBVec			; Table paramters
	Endif

	Entry	SIOVec,CTC0Vec,CTC1Vec,RestTbl

	Extrn	BnkMsk,MuxByte,ExtMcl,@LoVec
	Extrn	?PMsg,@Fx,@ConMd,@QueFl,@CBnk,?BnkSl,@Sec
	Extrn	Stack1,StSav1,?Mov,?XMov
	Page	66

; Port addresses:
	If	WrkStn
Sio1AD		Equ	0E0h		; MODEM/PRINTER - DATA
	Else
Sio1AD		Equ	0		; MODEM/PRINTER - DATA
	Endif
Sio1AC		Equ	Sio1AD+1	; MODEM/PRINTER - CONTROL/STATUS
Sio1BD		Equ	Sio1AD+2	; V24,TERMINAL - DATA
Sio1BC		Equ	Sio1AD+3	; V24,TERMINAL - CONTROL/STATUS


					; SUPPORTED WITH 1,228,800 Hz
	If	WrkStn
Ctc0		Equ	0E8h		; Ctc CHAN 0 - BAUDRATE Sio1A/TIMER
	Else
Ctc0		Equ	8		; Ctc CHAN 0 - BAUDRATE Sio1A/TIMER
	Endif
Ctc1		Equ	Ctc0+1		; Ctc CHAN 1 - BAUDRATE Sio1B/TIMER
Ctc2		Equ	Ctc0+2		; Ctc CHAN 2 - TIMER TO Ctc3 (HALVED)
Ctc3		Equ	Ctc0+3		; Ctc CHAN 3 - REALTIMECLOCK/COUNTER

	If	Not WrkStn					;
PioAD		Equ	0CH		; Pio A DATA - CENTRONICS DATA
PioAC		Equ	PioAD+1		; Pio A CONTROL (WRITE ONLY)
PioBD 		Equ	PioAD+2		; Pio B DATA - CENTRONICS CTRL
					;         	   + MODEM CTRL
					; BIT0 CEN. *BUSY
					; BIT1 CEN. *PAPER EMPTY
					; BIT2 CEN. *SELECT
					; BIT3 CEN. *FAULT
					; BIT4 CEN. *STROBE
					; BIT5 CEN. *ACK
					; BIT6 Pio BUFFER DIRECTION CH. B
					; BIT7 Pio BUFFER DIRECTION CH. A
PioBC		Equ	PioAD+3		; Pio B CONTROL (WRITE ONLY)

SplitSw		Equ	16H		; SPLIT SPEED OPTION
BnkMux		Equ	1BH


PioGAD		Equ	20H		; Pio A GRAPHIC PORT DATA OUT (DISPLAY)
PioGAC		Equ	PioGAD+1	; Pio A GRAPHIC PORT CONTROL (WRITE ONLY)
PioGBD		Equ	PioGAD+2	; Pio B GRAPHIC PORT DATA IN (Kbd)
PioGBC		Equ	PioGAD+3	; Pio B GRAPHIC PORT CONTROL (WRITE ONLY)

; Two extra serial ports. Need SIO-2 board, address 28H
; Only DTR/CTS handshaking ( NO XON/XOFF )
; Note: Move strap S12 from A to C, and S13 from A to C on SIO-2 board
;       for correct baudrate.

MSio2		Equ	28H		; EXTRA Sio BOARD
Ctc4		Equ	MSio2
Ctc5		Equ	MSio2+1
Sio3AD		Equ	MSio2+4		; V24,SERIE PRINTER 1 - DATA          
Sio3AC		Equ	MSio2+5		; V24,SERIE PRINTER - CONTROL/STATUS
Sio3BD		Equ	MSio2+6		; V24,SERIE PRINTER 2 - DATA
Sio3BC		Equ	MSio2+7		; V24,SERIE PRINTER - CONTROL/STATUS
	Else

BnkMux		Equ	0F4h

	Endif


; SPECIAL CHARACTERS AND CONSTANS:

Eof		Equ	1AH		; CP/M END OF FILE CHAR (^Z)
CtrlC		Equ	'C'-'@'
Dtr		Equ	7		; BIT 7 IN Wr5

MB$Input	Equ	00000001B	; DEVICE HANDLES INPUT
MB$Output	Equ	00000010B	; DEVICE HANDLES OUTPUT
MB$In$Out	Equ	MB$Input+MB$Output
MB$SoftBaud	Equ	00000100B	; SOFTWARE SELECTABLE BAUD RATE
MB$Serial	Equ	00001000B	; DEVICE USES PROTOCOL
MB$Xon$Xoff	Equ	00010000B	; XON/XOFF PROTOCOL ON

;------------------------------------------------------------;
; Flags definition:                                          ;
;                                                            ;
;               Byte0              Byte1                     ;
;          7 6 5 4 3 2 1 0    7 6 5 4 3 2 1 0                ;
;          A V I B B B B B    D D H - S S P P                ;
;                                                            ;
;          A = Available for modifications                   ;
;          V = Using IniStm-Vector in Init                   ;
;          I = Using Ix-index before IniStm                  ;
;          B = Baud rate (0 -31) in table below              ;
;          D = Data bits                                     ;
;          H = Handshake (auto enable)                       ;
;          S = Stop bits                                     ;
;          P = Parity                                        ;
;------------------------------------------------------------;
; Equates:
	
ModifyYes	Equ	10000000b
ModifyNo	Equ	00000000b

IniStmYes	Equ	01000000b
IniStmNo	Equ	00000000b

IxYes		Equ	00100000b
IxNo		Equ	00000000b


Baud0		Equ	0
Baud50		Equ	1
Baud75		Equ	2
Baud110		Equ	3
Baud134		Equ	4
Baud150		Equ	5
Baud300		Equ	6
Baud600		Equ	7
Baud1200	Equ	8
Baud1800	Equ	9
Baud2400	Equ	10
Baud3600	Equ	11
Baud4800	Equ	12
Baud7200	Equ	13
Baud9600	Equ	14
Baud19k		Equ	15
Baud38k		Equ	16
Baud76k		Equ	17
Baud75_1200	Equ	18
Baud1200_75	Equ	19
BaudAsync	Equ	20

ParityN		Equ	00b
ParityE		Equ	11b
ParityO		Equ	01b

StopB1		Equ	0100b
StopB1_5	Equ	1000b
StopB2		Equ	1100b

HandShN		Equ	000000b
HandShY		Equ	100000b

DataB5		Equ	00000000b
DataB6		Equ	10000000b
DataB7		Equ	01000000b
DataB8		Equ	11000000b
	Page
	Cseg				; Bank0
;------------------------------------------------------------;
;               Table for devices in system.                 ;
;------------------------------------------------------------;
Flag00:		Db	ModifyYes+IniStmYes+IxYes+Baud9600	; CRT
		Db	DataB8+HandShN+StopB1+ParityN		;
		Dw	VecSi1B					;
		Db	ModifyYes+IniStmYes+IxYes+Baud9600	; LPT
		Db	DataB8+HandShY+StopB1+ParityN		;
		Dw	VecSi1A					;
	If	Not WrkStn
		Db	ModifyNo+IniStmYes+IxNo+Baud0		; CEN
		Db	0					;
		Dw	VecPio					;
		Db	ModifyNo+IniStmYes+IxNo+Baud0		; GRAPH
		Db	DataB8+HandShY+StopB1+ParityN		;
		Dw	VecPioG					;
	Endif
	If	NetWork
		Db	ModifyNo+IniStmNo+IxNo+Baud0		; SPOOL
		Db	0					;
		Dw	0					;
	Endif
	If	Not WrkStn
		Db	ModifyYes+IniStmYes+IxYes+Baud9600	; LPT1
		Db	DataB8+HandShY+StopB1+ParityN		;
		Dw	VecSi3A				;
		Db	ModifyYes+IniStmYes+IxYes+Baud9600	; LPT2
		Db	DataB8+HandShY+StopB1+ParityN		;
		Dw	VecSi3B					;
	Endif

MaxDev		Equ	($-Flag00)/4
NoDev:		Db	MaxDev					; No of devices

@CTbl:
		Db	'CRT   '			; Dev0
C0Mode:		Db	MB$In$Out+MB$Serial+MB$SoftBaud	;
C0Baud:		Db	Baud9600			;

		Db	'LPT   '			; Dev1
C1Mode:		Db	MB$In$Out+MB$Serial+MB$SoftBaud	;
C1Baud:		Db	Baud9600			;

	If	Not WrkStn
		Db	'CEN   '			; Dev2
		Db	MB$Output			; 
		Db	Baud0				; 

		Db	'GRAPH '			; Dev3
		Db	MB$In$Out			;
		Db	Baud0				;
	Endif
	If	NetWork
		Db	'SPOOL '			; Dev4
		Db	Mb$Output			;
		Db	Baud0				; 
	Endif
	If	Not WrkStn
		Db	'LPT1  '			; Dev5
C4Mode:		Db	MB$Output+MB$Serial+MB$SoftBaud	;
C4Baud:		Db	Baud9600			; 

		Db	'LPT2  '			; Dev6
C5Mode:		Db	MB$Output+MB$Serial+MB$SoftBaud	; 
C5Baud:		Db	Baud9600			; 
	Endif
		Db	0				; End table

	Dseg

BaudTbl:
	Db	-1,0			;; 0:  NONE
	Db	-1,0			;; 1:    50
	Db	0,0C0h			;; 2:    75
	Db	174,0C0h		;; 3:   110
	Db	143,0C0h		;; 4:   134.5
	Db	0,80h			;; 5:   150
	Db	128,80h			;; 6:   300
	Db	64,80h			;; 7:   600
	Db	32,80h			;; 8:  1200
	Db	21,80h			;; 9:  1800
	Db	16,80h			;;10:  2400
	Db	11,80h			;;11:  3600
	Db	8,80h			;;12:  4800
	Db	5,80h			;;13:  7200
	Db	4,80h			;;14:  9600
	Db	2,80h			;;15: 19200
	Db	1,80h			;;16: 38400
	Db	1,40h			;;17: 76800
	Db	32,80h			;;18:  75/1200
	Db	32,80h			;;19:  1200/75
	Db	0,0h			;;20:  SYNKRONT

	Page
	Cseg
;------------------------------------------------------------;
; IniStm -- Write a number of bytes to 1 or more ports.      ;
;                                                            ;
; At entry:	Hl = Table address.                          ;
;		Table view (byte by byte):                   ;
;		#of bytes, port#, byte1, byte2,...,          ;
;		#of bytes, port#, byte1, byte2,...,          ;
;		0 (end table)                                ;
;------------------------------------------------------------;

IniStm:	Ld	A,(Hl)		; Load counter
	Or	A		; End table ?
	Ret	Z		; Yes...
	Ld	B,A		; No...save counter
	Inc	Hl		; Get port#
	Ld	C,(Hl)		; into C.
	Inc	Hl		; Point 1st data byte
	Otir			; Send (B) bytes to port (C)
	Jr	IniStm		; Loop...

;------------------------------------------------------------;
; Bank0Call -- Make a call in Bank0.                         ;
;                                                            ;
; At entry:	Hl = Call address.                           ;
;------------------------------------------------------------;
 
Bank0Call:	
	Ld	(SpSave),Sp		; Switck stack
	Ld	Sp,CommonStack		;
	Ld	(Call+1),Hl		; Set up call address
	Ld	A,(@CBnk)		; Get current Bank
	Push	Af			; and save
	Xor	A			; Select Bank0
	Call	?BnkSl			;
Call:	Call	0			; Execute in Bank0
	Ld	L,A			; Save statusbyte
	Pop	Af			; Restore old Bank
	Call	?BnkSl			;
	Ld	A,L			; 
	And	A			;
	Ld	Sp,(SpSave)		;
	Ret				;

SpSave:		Dw	0
HlXSave:	Ds	40
CommonStack:
	
;------------------------------------------------------------;
; UFunc -- Some user functions in Bank0.                     ;
;------------------------------------------------------------;

UFunc:
	Ld	(HlXSave),Hl		; Save Hl
	Ld	Hl,UFuncB0		;
	Jp	Bank0Call		;
	
	Dseg

UFuncB0:				;;
	Ld	Hl,(HlXSave)		;; Restore Hl

;------------------------------------------------------------;
; UFunc5 -- Set LPT input ringbuffer. Buffer must be located ;
;           in common memory >=C000h.                        ;
;                                                            ;
; At entry:	Hl = Address                                 ;
;		De = Size                                    ;
;		If Hl=0 restore to original default buffer   ;
;		which will be called on warmboot.            ;
;------------------------------------------------------------;

UFunc5:
	Djnz	UFunc6			;; If not UFunc5
SetLptBuff:				;; UFunc5
	Di				;;
	Ld	A,H			;;
	Or	L			;;
	Jr	Nz,SETLpt10		;;

	Ld	Hl,LpBuff		;; Use default buffer
	Ld	De,LpRngBfZ-LpBuff	;;
SETLpt10:
	Ld	(LpRngIn),Hl		;;
	Ld	(LpRngOut),Hl		;;
	Ld	(LpRngBeg),Hl		;;
	Ld	(LpRngBfZ),De		;;
	Ld	Hl,0			;;
	Ld	(LpRngCnt),Hl		;;
	Ld	A,5			;;
	Out	(Sio1AC),A		;;
	Ld	A,(LptWr5)		;;
	Set	Dtr,A			;;
	Ld	(LptWr5),A		;;
	Out	(Sio1AC),A		;; SET DTR
	Ei				;;
	Ret				;;

;------------------------------------------------------------;
; UFunc6 -- Copy Sio/Ctc init table from Bank 0 to Tpa.      ;
;                                                            ;
; At entry:	Hl = Destination address in Tpa.             ;
;		D  = Device number. (0...                    ;
; At exit:	A  = 0 if Ok.                                ;
;		A  =-1 if device not found.                  ;
;------------------------------------------------------------;

UFunc6:
	Djnz	UFunc7			;;
	Call	CalcAdr			;;
	Jr	C,UFunc6Err		;; Return if fault.
	Ld	Bc,1*256+0		;; Bank0 --> Bank1
	Call	?XMov			;; (Does not affect De,Hl)
	Ld	Bc,SioLen		;;
	Call	?Mov			;;
	Xor	A			;; No error
	Ret				;;

UFunc6Err:
	Ld	A,-1
	Ret
CalcAdr:
	Ld	A,D			;; Get device number
	Cp	MaxDev			;;
	Ccf				;;
	Ret	C			;;
	Add	A,A			;;
	Add	A,A			;; *4 for offset in Flag00
	Ex	De,Hl			;; Save Tpa address in De
	Ld	Hl,Flag00		;;
	Ld	B,0			;;
	Ld	C,A			;;
	Add	Hl,Bc			;; Point Flag0
	Ld	A,(Hl)			;;
	Scf				;;
	Bit	5,A			;; Using Ix ?
	Ret	Z			;; No...error
	Inc	Hl			;;
	Inc	Hl			;;
	Ld	A,(Hl)			;;
	Inc	Hl			;;
	Ld	H,(Hl)			;;
	Ld	L,A			;;
	Ex	De,Hl			;; Hl=Tpa, De=Table
	And	A			;; Reset carry
	Ret

;------------------------------------------------------------;
; UFunc7 -- Copy Sio/Ctc init table from Tpa to Bank0.       ;
;                                                            ;
; At entry:	Hl = Source address in Tpa.                  ;
;		D  = Device number. (0...                    ;
; At exit:	A  = 0 if Ok.                                ;
;		A  =-1 if device not found.                  ;
;------------------------------------------------------------;

UFunc7:
	Djnz	UFunc8			;;
	Call	CalcAdr			;;
	Jr	C,UFunc6Err		;; Return if fault.
	Ld	Bc,0*256+1		;; Bank1 --> Bank0
	Call	?XMov			;; (Does not affect De,Hl)
	Ld	Bc,SioLen		;;
	Ex	De,Hl			;;
	Call	?Mov			;;
	Xor	A			;; No error
	Ret				;;

;------------------------------------------------------------;
; UFunc8 -- Make a patch in console input routine.           ;
;                                                            ;
; At entry:	Hl = Address to patch area in Tpa            ;
;		If Hl=0, patch will be deactivated.          ;
; At exit:	De = Patch area address (in Bank0).          ;
;------------------------------------------------------------;

UFunc8:					;;
	Djnz	UFunc9			;;
	Ld	A,H			;; Deactivate patch
	Or	L			;;
	Jr	Z,UFunc81		;; Yes...

	Ld	Bc,0*256+1		;; Bank1 --> Bank0
	Call	?XMov			;;
	Ex	De,Hl			;;
	Ld	Hl,ConInPatch		;;
	Ld	Bc,100h			;;
	Jp	?Mov			;;
UFunc81:				;; Deactivate patch
	Di				;;
	Ld	A,0C9H			;; Ret
	Ld	(ConInPatch),A		;;
	Ld	(ConInPatch+2),A	;;
	Ei				;;
	Ld	De,ConInPatch		;;
	Ret				;;

;------------------------------------------------------------;
; UFunc9 -- Stop Ctc Interrupt.                              ;
;------------------------------------------------------------;

UFunc9:	Djnz	UFunc10			;;
	Ld	A,3			;;
	Out	(Ctc3),A		;;
	Ret

;------------------------------------------------------------;
; UFunc10 -- Start Ctc Interrupt.                            ;
;------------------------------------------------------------;

UFunc10:
	Djnz	UFunc11			;;
	Ld	A,0C5h			;;
	Out	(Ctc3),A		;; Enable Ctc
	Ld	A,240			;;
	Out	(Ctc3),A		;; Interrupt 10 Hz
	Ret

;------------------------------------------------------------;
; UFunc11 -- Assign List Device to a physical device.        ;
;                                                            ;
; At entry:	Hl = Device number (0...6)                   ;
;                    0='CRT   '                              ;
;		     1='LPT   '                              ;
;		     2='CEN   '                              ;
;		     3='GRAPH '                              ;
;		     4='SPOOL '                              ;
;		     5='LPT1  '                              ;
;                    6='LPT2  '                              ;
; At exit:	A =  0 successful assignment.                ;
;		A = -1 device does not exists.               ;
;------------------------------------------------------------;

UFunc11:
	Djnz	UFunc12			;;
	Ld	A,H			;; Test if correct value
	And	A			;;
	Jr	Nz,Fkn11err		;;
	Ld	A,L			;;
	Cp	7			;;
	Jr	Nc,Fkn11err		;;
	Add	A,A			;; *2
	Add	A,A			;; *4
	Add	A,L			;; *5
	Add	A,L			;; *6 Name is 6 bytes
	Ld	E,A			;;
	Ld	D,0			;;
	Ld	Hl,InternTbl		;;
	Add	Hl,De			;; Point to name in table
	Call	GetDev			;; 
	Ld	A,C			;; Check if installed
	Cp	-1			;;
	Jr	Z,Fkn11err		;; No...return error
Fkn11_A:					;;
	Ld	B,C			;; Get counter
	Inc	B			;; Offset 1
	Ld	Hl,0			;;
	Scf				;; Carry will rotate B times from
Fkn11_B:				;; the left into Hl.
	Rr	H			;;
	Rr	L			;;
	Djnz	Fkn11_B			;;
	Ld	(@LoVec),Hl		;; Save bit vector
	Xor	A			;; No error...return
	Ret				;;
Fkn11err:				;;
	Ld	A,-1			;;
	Ret				;;

UFunc12:				;; Not installed.
	Ret				;;

InternTbl:
	Db	'CRT   '		;; #0
	Db	'LPT   '		;; #1
	Db	'CEN   '		;; #2
	Db	'GRAPH '		;; #3
	Db	'SPOOL '		;; #4
	Db	'LPT1  '		;; #5
	Db	'LPT2  '		;; #6

;------------------------------------------------------------;
; GetDev -- Get Device Number.                               ;
;                                                            ;
; At entry:	Hl = Pointing Device Name String (6 chars).  ;
; At exit:	C  = Device Number.                          ;
;               C  = 0FFh if device does not exist.          ;
;------------------------------------------------------------;

GetDev: Ex	De,Hl			;; De = Name string
	Ld	B,MaxDev		;; Counter = max dev.			; Save it as a counter
	Ld	C,0			;; Later used as device number
	Ld	Hl,@CTbl		;; Get Table Address in Hl
GetDev1:				;;
	Push	De			;;
	Push	Bc			;;
	Push	Hl			;;
	Ld	B,6			;; 6 bytes in name
GetDev2:				;;
	Ld	A,(De)			;;
	Cp	(Hl)			;;
	Jr	Nz,GetDev3		;;
	Inc	Hl			;;
	Inc	De			;;
	Djnz	GetDev2			;;
	Pop	Hl			;; Here on match
	Pop	Bc			;;
	Pop	De			;;
	Ret				;;
GetDev3:				;;
	Pop	Hl			;; Restore table pointer
	Pop	Bc			;; Restore counter and device number
	Ld	De,8			;; Next Name
	Add	Hl,De			;;
	Pop	De			;; Restore string pointer
	Inc	C			;;
	Djnz	GetDev1			;;
	Ld	C,-1			;; Return not found
	Ret				;;
	Page
;------------------------------------------------------------;
; ?Cinit -- Init character device.                           ;
;                                                            ;
; At entry:	C = Logical device # (0...                   ;
;------------------------------------------------------------;

	Cseg

?Cinit:					;
	Ld	Hl,CInitB0		;
	Jp	Bank0Call		;

	Dseg

CInitB0:
	Ld	A,C			;; No in A
	Cp	MaxDev			;; Fit in system ?
	Ret	Nc			;; No...return
	Add	A,A			;;
	Add	A,A			;; *4 for offset in FlagTable
	Ld	B,0			;;
	Ld	C,A			;; Bc=Offset in FlagTable
	Add	A,A			;; *8 for offset in @CTbl
	Ld	D,0			;;
	Ld	E,A			;; De=Offset in @CTbl
	Ld	Hl,Flag00		;;
	Add	Hl,Bc			;; Pointing to Flag0
	Ld	B,(Hl)			;; B=Flag0
	Inc	Hl			;;
	Ld	C,(Hl)			;; C=Flag1
	Inc	Hl			;;
	Ld	A,(Hl)			;;
	Inc	Hl			;;
	Ld	H,(Hl)			;;
	Ld	L,A			;; Hl=DeviceVector
	Bit	6,B			;; Using IniStm ?
	Jr	Nz,CIni1B0		;; Yes...
	Ld	A,H			;; Test if valid CallVector
	Or	L			;;
	Ret	Z			;; No...return
	Jp	(Hl)			;; Call and do return from subroutine
CIni1B0:				;;
	Bit	5,B			;; Using Ix ?
	Jp	Z,IniStm		;; No...Init dev. and return
					;; Here using IniStm and Ix
	Push	Ix			;; Save Ix
	Push	Hl			;;
	Pop	Ix			;; Ix=VectorTable
	Ld	Hl,@CTbl		;;
	Add	Hl,De			;;
	Ld	De,7			;;
	Add	Hl,De			;; Hl=Pointing to baudrate
	Ld	A,(Hl)			;; Get baudrate
	Cp	22			;; Check if in table
	Jr	Nc,CIni9B0		;; No...quit
	Add	A,A			;; Offset in LookUpTbl
	Ld	E,A			;;
	Ld	D,0			;;
	Ld	Hl,BaudTbl		;;
	Add	Hl,De			;; Correct address in BaudTbl
	Ld	A,(Hl)			;; Get Ctc-byte
	Cp	-1			;; Valid ?
	Jr	Z,CIni9B0		;; No...
	Ld	(Ix+CtcBaud),A		;; Set CtcCounter
	Inc	Hl			;;
	Ld	B,(Hl)			;; Get ClockMode
	Ld	A,C			;; Get Flag1
	And	00001111b		;; Get StopB/Parity
	Or	B			;;
	Ld	(Ix+SioWr4),A		;;
	Ld	A,(Ix+SioWr3)		;;
	And	00011111b		;; Keep Bit0-4
	Ld	D,A			;;
	Ld	A,C			;;
	And	11100000b		;; Get DataB/HandSh
	Or	D			;;
	Ld	(Ix+SioWr3),A		;;
	And	11000000b		;; Keep DataB
	Rra				;;
	Ld	D,A			;;
	Ld	A,(Ix+SioWr5)		;;
	And	10011111b		;; Keep Bit0-4,7
	Or	D			;;
	Ld	(Ix+SioWr5),A		;;
	Push	Ix			;;
	Pop	Hl			;;
	Call	IniStm			;; Init dev.
	Dec	C			;; Point to data port
	In	A,(C)			;; Clear input port
	In	A,(C)			;;
CIni9B0:
	Pop	Ix			;; Restore Ix
	Ret
	Page
;------------------------------------------------------------;
; Patcharea for console input and console input status.      ;
;------------------------------------------------------------;
					;; Two useful jumps for the patch-code.
	Jp	CiB0X			;; Jump to console input
	Jp	CISTB0X			;; Jump to console input status
ConInPatch:				;;
	Ret				;; Call from CiSt enter here
	Nop				;;
	Ret				;; Call from Ci enter here
	Db	'This is a patch area reserved for '		;;
	Db	'inplementations of function keys, and '	;;
	Db	' other "hacking" in consoleinput'		;;
	Db	' Use Bios function 30 (user function 8)'	;;
	Ds	115			;; 256 bytes to use.
	Page	
;------------------------------------------------------------;
; ?Ci -- Character input.                                    ;
;                                                            ;
; At entry:	B = Device number (0...)                     ;
; At exit:	A = Character.                               ;
;------------------------------------------------------------;

?Ci:	Call	ConInPatch+2		;; Maybe a patch

CiB0X:	Inc	B			;; Device# (relative 1)
	Djnz	CiDev1

;------------------------------------------------------------;
; CrtIn -- Input from device CRT.                            ;
;------------------------------------------------------------;

CrtIn:	Ld	Hl,RngCnt		;; POINT TO THE RING BUFFER COUNTER.
	Xor	A			;;        ZERO 
	Ei				;;
CrtIn1:	Or	(Hl)			;; GET IT.
	Jr	Z,CrtIn1		;; LOOP FOR CHAR.
	Di				;;
	Ld	A,(QFlag)
	Bit	6,A
	Jr	Nz,CrtIn3
	Dec	(Hl)			;; COUNT DOWN
	Ld	De,(RngOut)		;; GET THE OUTPUT-POINTER
	Ld	A,(De)			;; A=OUTPUT CHAR (PARITY RESET).
	And	A			;;
	Ld	Hl,RngEnd		;; INC RING BUFFER-OUTPUT-POINTER
	Sbc	Hl,De			;; IS THE BUFFEREND?
	Inc	De			;;        (INC)
	Jr	Nz,CrtIn2		;; NO...JUMP
	Ld	De,RngBeg		;; SET BUFFER START
CrtIn2:	Ld	(RngOut),De		;; SAVE THE POINTER.
	Ei				;;
	Cp	80h			;;
	Jr	Z,CrtIn			;;
	And	7Fh			;; Clear parity bit.
	Ret				;;

CrtIn3:	Ld	Hl,(LastPoint)		;;
	Ld	(Hl),80h		;; Mark 'Taken'
	Ld	Hl,QFlag		;;
	Ld	(Hl),0			;;
	Ld	Hl,Last			;;
	Ld	A,(Hl)			;;
	Ld	(Hl),0			;;
	Ei				;;
	Ret				;;

CiDev1:
	Djnz	CiDev2			;; JUMP IF NOT DEVICE 1

;------------------------------------------------------------;
; Lpt0In -- Input from device LPT.                           ;
;------------------------------------------------------------;

Lpt0In:
	Call	Lpt0InSt		;; CHAR IN SIO BUFFER?
	Jr	Z,Lpt0In		;; NO...WAIT

	Di				;;
	Ld	Hl,(LpRngCnt)		;; DECREMENT LPT INPUT COUNTER
	Dec	Hl			;;
	Ld	(LpRngCnt),Hl		;;

	Ld	A,(LptWr3)		;;
	Bit	5,A			;;
	Jr	Z,Lpt010		;; IF NOT USING HANDSHAKE

	Ld	De,(LpRngBfZ)		;; CHECK IF TIME TO RISE DTR
	And	A			;;
	Sbc	Hl,De			;;
	Ld	De,8			;;
	And	A			;;
	Adc	Hl,De			;;
	Jr	Nz,Lpt010		;; IF NOT TIME TO RISE DTR

	Ld	A,5			;;
	Out	(Sio1AC),A		;; RISE DTR
	Ld	A,(LptWr5)		;;
	Set	Dtr,A			;;
	Out	(Sio1AC),A		;;
	Ld	(LptWr5),A		;;
Lpt010:
	Ld	Hl,(LpRngBeg)		;; COMPUTE LPT RING BUFFER END
	Ld	De,(LpRngBfZ)		;;
	Add	Hl,De			;;
	Ex	De,Hl			;; SAVE IN De

	Ld	Hl,(LpRngOut)		;;
	Ld	A,(Hl)			;; GET NEXT BYTE
	Ei				;;
	Inc	Hl			;;
	Ex	De,Hl			;;
	And	A			;;
	Sbc	Hl,De			;; CHECK IF AT BUFFER END
	Jr	Nz,NOTATLpEnd		;;

	Ld	De,(LpRngBeg)		;;
NOTATLpEnd:
	Ld	(LpRngOut),De		;; SET NEW OUTPUT POINTER
	Ret				;;

CiDev2:
	If	Not WrkStn
	Djnz	CiDev3			;; JUMP IF NOT DEVICE 2

;------------------------------------------------------------;
; CenIn -- Input from device CEN.                            ;
;------------------------------------------------------------;

CenIn:	Ld	A,Eof
	Ret

CiDev3:	Djnz	CiDev4			;; JUMP IF NOT DEVICE 3

;------------------------------------------------------------;
; GraphIn -- Graphic keyboard input.                         ;
;------------------------------------------------------------;

GraphIn:
	Ld	Hl,GrCnt		;; POINT TO THE RING BUFFER COUNTER.
	Xor	A			;;        ZERO 
	Ei				;;
GraphIn1:
	Or	(Hl)			;; GET IT.
	Jr	Z,GraphIn1		;; LOOP FOR CHAR.
	Di				;;

	Ld	A,10000011B		;;
	Out	(PioGBC),A		;; RESTART PIO INTERUPT
	Ld	A,(QFlag)
	Bit	6,A
	Jp	Nz,CrtIn3

	Dec	(Hl)			;; COUNT DOWN
	Ld	De,(GrnOut)		;; GET THE OUTPUT-POINTER
	Ld	A,(De)			;; A=OUTPUT CHAR (PARITY RESET).
	And	A			;; Get rid of carry
	Ld	Hl,GrnEnd		;;
	Sbc	Hl,De			;; IS THE BUFFEREND?
	Inc	De			;; INC RING BUFFER-OUTPUT-POINTER
	Jr	Nz,GraphIn2		;; NO...JUMP
	Ld	De,GrnBeg		;; SET BUFFER START
GraphIn2:
	Ld	(GrnOut),De		;; SAVE THE POINTER.
	Ei				;;
	Cp	80h			;;
	Jr	Z,GraphIn		;;
	And	7Fh			;; Clear parity
	Ret				;;

CiDev4:
	Endif
	If	NetWork
	Djnz	CiDev5			;; Jump if not Dev4

;------------------------------------------------------------;
; SpoolIn -- Input from device SPOOL.                        ;
;------------------------------------------------------------;

SpoolIn:				;;
	Ld	A,Eof			;;
	Ret				;;

CiDev5:
	Endif
	If	Not WrkStn
	Djnz	CiDev6			;; Jump if not Dev5

;------------------------------------------------------------;
; Lpt1In -- Input from device LPT1.                          ;
;------------------------------------------------------------;

Lpt1In:					;;
	Ld	A,Eof			;;
	Ret				;;

CiDev6:	Djnz	CiDev7			;; Jump if not Dev6

;------------------------------------------------------------;
; Lpt2In -- Input from device LPT2.                          ;
;------------------------------------------------------------;

Lpt2In:					;;
	Ld	A,Eof			;;
	Ret				;;

CiDev7:					;;
	Endif
	Ld	A,Eof			;;
	Ret				;;
	Page
;------------------------------------------------------------;
; ?Co -- Character output.                                   ;
;                                                            ;
; At entry:	B = Device number (0...)                     ;
;		C = Character.                               ;
; At exit:	A = Written character.                       ;
;------------------------------------------------------------;

?Co:
	Inc	B			;; Make device # (relative 1)
	Djnz	CoDev1			;; Jump if not device 0

;------------------------------------------------------------;
; CrtOut -- Output to device CRT.                            ;
;------------------------------------------------------------;

CrtOut:
	Call	CrtOSt			;; Test CRT output status
	Jr	Z,CrtOut		;; Wait for ready
	Ld	A,C			;;
	Out	(Sio1BD),A		;;
	Ret				;;

CoDev1:	Djnz	CoDev2			;; Jump if not device 1

;------------------------------------------------------------;
; Lpt0Out --  Output to device LPT.                          ;
;------------------------------------------------------------;

Lpt0Out:
	Call	Lpt0OSt			;; Test LPT output status
	Jr	Z,Lpt0Out		;; Wait for ready
	Ld	A,C			;;
	Out	(Sio1AD),A		;;
	Ret				;;

CoDev2:
	If	Not WrkStn
	Djnz	CoDev3			;; Jump if not device 2

;------------------------------------------------------------;
; CenOut -- Output to device CEN.                            ;
;------------------------------------------------------------;

CenOut:	Call	CenOSt			;; Test CEN output status
	Jr	Z,CenOut		;; Wait for ready.
	Ld	A,C			;;
	Out	(PioAD),A		;;
	Ld	A,01000000B		;; Strobe
	Out	(PioBD),A		;;
	Ld	A,01010000B		;; Strobe high
	Out	(PioBD),A		;;
	Ret				;;

CoDev3:	Djnz	CoDev4			;; Jump if not device 3

;------------------------------------------------------------;
; GraphOut -- Output to device GRAPH.                        ;
;------------------------------------------------------------;

GraphOut:
	Ld	Hl,GrOutCnt		;; Get output byte counter
GrOutX:	Xor	A			;;
	Di				;;
	Cp	(Hl)			;; CHECK IF ANYTHING IN OUTPUT BUFFER
	Jr	Nz,GrOutW		;; YES

	Ld	A,C			;;
	Out	(PioGAD),A		;; ELSE JUST SEND IT
	Inc	(Hl)			;; INC BUFFER COUNTER
	Ei				;;
	Ret				;;
GrOutW:	Ei				;;
	Ld	A,GrOBufZ		;;
	Di				;;
	Cp	(Hl)			;;
	Jr	C,GrOutW		;; IF BUFFER FULL..WAIT
	Jr	Nz,GrOutX		;; CHECK FOR 

	Ift	GrOBufZ NE 1		;; IF OUTPUT BUFFER SIZE > 1
	Inc	(Hl)			;; INC BUFFER COUNTER
	Ld	Hl,(GrInPnt)		;;
	Ld	(Hl),C			;; SAVE OUTPUT BYTE IN OUTPUT RING BUFFER
	Ei				;;
	Inc	Hl			;;
	Ld	De,GrOutBufEnd		;;
	Ld	A,E			;;
	Cp	L			;;
	Jr	Nz,GrOut20		;;

	Ld	Hl,GrOutBuf		;; SET POINTER TO START OF BUFFER
GrOut20:
	Ld	(GrInPnt),Hl		;; SET NEW BUFFER IN POINTER

	Else				;; IF JUST A ONE BYTE BUFFER
	Ld	A,C			;;
	Ld	(GrOutBuf),A		;;
	Inc	(Hl)			;;
	Ei				;;
	Endif

	Ret				;;

CoDev4:
	Endif
	If	NetWork
	Djnz	CoDev5			;; Jump if not device 4

;------------------------------------------------------------;
; SpoolOut -- Output to device SPOOL.                        ;
;------------------------------------------------------------;

SpoolOut:
	Call	$Spool##		;;
	Ret				;;

CoDev5:
	Endif
	If	Not WrkStn
	Djnz	CoDev6			;; Jump if not device 5

;------------------------------------------------------------;
; Lpt1Out -- Output to device LPT1.                          ;
;------------------------------------------------------------;

Lpt1Out:
	Call	Lpt1OSt			;; Test LPT1 output status
	Jr	Z,Lpt1Out		;; Wait for ready
	Ld	A,C			;;
	Out	(Sio3AD),A		;;
	Ret				;;

CoDev6:	Djnz	CoDev7			;; Jump if not device 6

;------------------------------------------------------------;
; Lpt2Out -- Output to device LPT2.                          ;
;------------------------------------------------------------;

Lpt2Out:
	Call	Lpt2OSt			;; Test LPT2 output status
	Jr	Z,Lpt2Out		;; Wait for ready
	Ld	A,C			;;
	Out	(Sio3BD),A		;;
	Ret				;;

CoDev7:
	Endif
	Ret
	Page
;------------------------------------------------------------;
; ?CiSt -- Character input status.                           ;
;                                                            ;
; At entry:	B = Device number (0...)                     ;
; At exit:	A =-1 & Nz-Flag if at least 1 char. available;
;		A = 0 & Z-Flag if no char. available.        ;
;------------------------------------------------------------;

?CiSt:
	Call	ConInPatch		;; Check if patch in ConsoleInput
CiStB0X:
	Inc	B			;; Make device # (relative 1)
	Djnz	CiSDev1			;; Jump if not device 0

;------------------------------------------------------------;
; CrtInSt -- Input status from CRT.                          ;
;------------------------------------------------------------;

CrtInSt:
	Ld	A,(RngCnt)		;; ANY CHAR IN THE BUFFER?
	Or	A			;;
	Ret	Z			;; NO...RETURN

CrtInSt0:
	Ld	A,(@QueFl)		;; Bit7 & Bit6 set in Bdos on Func11 and Func2 resp.
	And	A
	Jr	Z,CrtInSt5
	Bit	7,A			;; Test Func11 or Func2
	Ld	A,(Last)
	Jr	Z,CrtInSt4
	Cp	'C'-'@'			;; Here on Func11
	Jr	Z,CrtInSt5
CrtInSt1:
	Xor	A
	Jr	CrtInSt3
CrtInSt2:
	Or	-1
CrtInSt3:
	Ld	(QFlag),A
	Ret
CrtInSt4:				;; Here on Func2
	Cp	'S'-'@'
	Jr	Z,CrtInSt2
	Cp	'Q'-'@'
	Jr	Z,CrtInSt2
	Cp	'C'-'@'
	Jr	Z,CrtInSt2
	Jr	CrtInSt1

CrtInSt5:
	Or	-1			;; YES...SET FLAG
	Ret 				;;

CiSDev1:
	Djnz	CiSDev2			;; Jump if not device 1

;------------------------------------------------------------;
; Lpt0InSt -- Input status from device LPT.                  ;
;------------------------------------------------------------;

Lpt0InSt:
	Ld	Hl,(LpRngCnt)		;; ANYTHING IN LPT BUFFER
	Ld	A,H			;;
	Or	L			;;
	Ret	Z			;; If empty
	Or	-1			;; 
	Ret				;;

CiSDev2:
	If	Not WrkStn
	Djnz	CiSDev3			;; Jump if not device 2

;------------------------------------------------------------;
; CenInSt -- Input status from device CEN.                   ;
;------------------------------------------------------------;

CenInSt:				;;
	Xor	A			;; Not ready
	Ret

CiSDev3:
	Djnz	CiSDev4			;; Jump if not device 3

;------------------------------------------------------------;
; GraphInSt -- Input status from device GRAPH.               ;
;------------------------------------------------------------;

GraphInSt:
	Ld	A,(GrCnt)		;; TEST GR. CHAR. COUNTER
	Or	A			;;
	Ret	Z			;; RETURN NO CHAR

	Jp	CrtInSt0


CiSDev4:
	Endif
	If	NetWork
	Djnz	CiSDev5			;; Jump if not device 4

;------------------------------------------------------------;
; SpoolInSt -- Input status from device SPOOL.               ;
;------------------------------------------------------------;

SpoolInSt:
	Xor	A			;; No char
	Ret

CiSDev5:
	Endif
	If	Not WrkStn
	Djnz	CiSDev6			;; Jump if not device 5

;------------------------------------------------------------;
; Lpt1InSt -- Input status from device LPT1.                 ;
;------------------------------------------------------------,

Lpt1InSt:
	Xor	A			;; No char
	Ret				;;

CiSDev6:
	Djnz	CiSDev7			;; Jump if not device 6

;------------------------------------------------------------;
; Lpt2InSt -- Input status from device LPT2.                 ;
;------------------------------------------------------------;

Lpt2InSt:
	Xor	A			;;
	Ret				;;

CiSDev7:
	Endif
	Xor	A			;;
	Ret
	Page
;------------------------------------------------------------;
; ?CoSt -- Character output status.                          ;
;                                                            ;
; At entry:	B = Device number (0...)                     ;
; At exit:	A =-1 & Nz-Flag if ready.                    ;
;		A = 0 & Z-Flag if not ready.                 ;
;------------------------------------------------------------;

?CoSt:
	Inc	B			;; Make device # (relative 1)
	Djnz	CoSDev1			;; Jump if not device 0

;------------------------------------------------------------;
; CrtOSt -- Output status from device CRT.                   ;
;------------------------------------------------------------;

CrtOSt:
	In	A,(Sio1BC)		;; Read status
	And	00000100B		;; Mask Tx buffer empty
	Ret	Z			;; Not ready...return
	Or	-1			;; Set ready flag
	Ret				;;

CoSDev1:
	Djnz	CoSDev2			;; Jump if not device 1

;------------------------------------------------------------;
; Lpt0OSt -- Output status from device LPT.                  ;
;------------------------------------------------------------;

Lpt0OSt:
	In	A,(Sio1AC)		;; Read status
	And	00000100b		;; Mask Tx buffer empty
	Ret	Z			;; Not ready...return
	Or	-1			;; Set ready flag.
	Ret				;;

CoSDev2:
	If	Not WrkStn
	Djnz	CoSDev3			;; Jump if not device 2

;------------------------------------------------------------;
; CenOSt -- Output status from device CEN.                   ;
;------------------------------------------------------------;

CenOSt:
	In	A,(PioBD)		;; READ ACK AND BUSY.
	And	00100001B		;;
	Cp	00100000B		;; READY AND NOT BUSY
	Ld	A,0FFH			;;
	Jr	Z,CenOSt1		;; YES...JUMP
	Ld	A,0			;; SET NOT READY
CenOSt1:
	And	A			;;
	Ret				;;

CoSDev3:
	Djnz	CoSDev4			;; Jump if not device 3

;------------------------------------------------------------;
; GraphOSt -- Output status from device GRAPH.               ;
;------------------------------------------------------------;

GraphOSt:
	Ld	Hl,GrOutCnt		;; GET OUTPUT BYTE COUNTER
	Ld	A,GrOBufZ+1		;;
	Cp	(Hl)			;;
	Ld	A,0			;; MAYBE NOT READY
	Jr	Z,GrOST2		;; IF BUFFER FULL (NOT RDY)
	Ld	A,-1			;; ELSE READY
GrOST2:					;;
	Or	A			;; SET FLAG BITS
	Ret				;;

CoSDev4:
	Endif
	If	NetWork
	Djnz	CoSDev5			;; Jump if not device 4

;------------------------------------------------------------;
; SpoolOSt -- Output status from device SPOOL.               ;
;------------------------------------------------------------;

SpoolOSt:
	Ld	A,-1			;;
	Or	A
	Ret

CoSDev5:
	Endif
	If	Not WrkStn
	Djnz	CoSDev6			;; Jump if not device 5

;------------------------------------------------------------;
; Lpt1OSt -- Output status from device LPT1.                 ;
;------------------------------------------------------------;

Lpt1OSt:
	In	A,(Sio3AC)		;; Read status
	And	00000100b		;; Mask Tx buffer empty
	Ret	Z			;; Not ready...return
	Or	-1			;; Set ready flag
	Ret				;;

CoSDev6:
	Djnz	CoSDev7			;; Jump if not device 6

;------------------------------------------------------------;
; Lpt2OSt -- Output status from device LPT2.                 ;
;------------------------------------------------------------;

Lpt2OSt:
	In	A,(Sio3BC)		;; Read status
	And	00000100b		;; Mask Tx buffer empty
	Ret	Z			;; Not ready...return
	Or	-1			;; Set ready flag
	Ret				;;

CoSDev7:
	Endif
	Xor	A			;; Not ready. Cause no
	Ret				;; more devices.
	Page
;------------------------------------------------------------;
;                Interrupt Driven Routines                   ;
;------------------------------------------------------------;

;------------------------------------------------------------;
; KbdIrq -- Console keyboard interrupt service routine.      ;
;           Uses local stack in order not to interfere with  ;
;           the user program stack.                          ;
;------------------------------------------------------------;

	Cseg
KbdIrq:	Call	BIOSINTENT		;
	Jp	KbdGBIB0		;

	Dseg

KbdGBIB0:				;;
	Ld	Hl,RngCnt		;; Hl --> NO OF CHAR IN BUFFER
	Ld	A,RngEnd-RngBeg-2	;; A = BUFF SIZE - 2
	Cp	(Hl)			;;
	Jr	Nz,NOTSFULL		;;

	Ld	A,(KbdWr3)		;; IF BUFFER SOON FULL
	Bit	5,A			;;
	Jr	Z,NOTSFULL		;; IGNORE IF NOT DTR/RTS HANDSHAKE

	Ld	A,5			;;
	Out	(Sio1BC),A		;; RESET DTR IF JUST 2 BYTES LEFT IN BUFFER
	Ld	A,(KbdWr5)		;;
	Res	Dtr,A			;;
	Out	(Sio1BC),A		;;
	Ld	(KbdWr5),A		;;
NOTSFULL:
	Ld	A,RngEnd-RngBeg		;;
	Cp	(Hl)			;; IS BUFFER FULL?
	In	A,(Sio1BD)		;; A = CHAR (CLR INTERRUPT)
	Ld	D,A			;; SAVE PARITY BIT
	Jr	Z,KbdIr3		;; YES...JUST JUMP AND QUIT
	Inc	(Hl)			;; INC CHAR-COUNTER 
	And	07FH			;; MASK PARITY
	Ld	(Last),A		;; Save last char
KbdIr1:	Ld	Hl,(RngIn)		;; Hl --> INPUT
	Ld	(LastPoint),Hl
	Ld	(Hl),D			;; SAVE INPUT CHAR IN BUFFER INCLUDING PARITY
	And	A			;; CLEAR CARRY BIT
	Ex	De,Hl			;; SAVE INPUT POINTER IN De.
	Ld	Hl,RngEnd		;; Hl=BUFFEREND FOR TEST
	Sbc	Hl,De			;; POINTER AT END?
	Inc	De			;;            INC
	Jp	Nz,KbdIr2		;; NO...JUMP
	Ld	De,RngBeg		;; SET POINTER TO BUFFERSTART
KbdIr2:	Ld	(RngIn),De		;; SAVE THE POINTER.
KbdIr3:	
	Jp	BIOSINTEXIT		;;

	Cseg
;------------------------------------------------------------;
; BiosIntEnt -- Save registers and Bank. Set Bank0.          ;
;               Using user's stack to save time.             ;
;------------------------------------------------------------;

BiosIntEnt:
	Ld	(HlSave),Hl		;
	Ld	(DeSave),De		;
	Pop	Hl			; GET RETURN ADRESS
	Push	Af			; SAVE REGISTERS.
	
; SINCE THIS IS AN INTERUPT ROUTINE CAN WE IGNORE TO UPPDATE
; @CBnk AND BnkMux 

	Ld	A,(MuxByte)		; GET CURRENT BANK MUX
	Ld	(MuxSave),A		; AND SAVE
	If	Not WrkStn
	Set	5,A			; Force Bank0
	Else
	Set	0,A			; Force Bank0
	Endif
	Out	(BnkMux),A		;
	Jp	(Hl)			;

;RESTOR BANK AND REGISTER  RETURN FROM INTERUPT
BiosIntExit:
	Ld	A,(MuxSave)		; GET OLd BANK MUX SETTINGS
	Out	(BnkMux),A		;
	Ld	De,(DeSave)		;
	Ld	Hl,(HlSave)		;
	Pop	Af			;
UnkInt:
	Ei				; BACK FROM INTERRUPT.
	Reti				;

;------------------------------------------------------------;
; LptIrq -- LPT PORT INTERRUPT SERVICE ROUTIN.
; USES LOCAL STACK IN ORDER NOT TO INTERFERE WITH THE
; USER PROGRAM STACK.

LptIrq:
	Call	BIOSINTENT		;

	Jp	LptIrqB0		;

	Dseg
LptIrqB0:
	Ld	Hl,(LpRngBfZ)		;; BUFFER SIZE
	Ld	De,(LpRngCnt)		;; De = NR OF CHAR IN BUFFER
	And	A			;;
	Sbc	Hl,De			;; CHECK IF BUFFER FULL
	Jr	Z,LpFULL		;;

	Ld	De,5			;; CHECK IF < 5 BYTES LEFT
	Sbc	Hl,De			;;
	Jr	Nc,NOLpHSH		;; IF NO TIME FOR DTR RESET

	Ld	A,(LptWr3)		;; CHECK IF DTR/CTS HANSHAKE
	Bit	5,A			;;
	Jr	Z,NOLpHSH		;; IGNORE IF NOT DTR/RTS HANDSHAKE

	Ld	A,5			;;
	Out	(Sio1AC),A		;; RESET DTR IF < 5 BYTES LEFT IN BUFFER
	Ld	A,(LptWr5)		;;
	Res	Dtr,A			;;
	Out	(Sio1AC),A		;;
	Ld	(LptWr5),A		;;
NOLpHSH:
	Ld	Hl,(LpRngIn)		;; GET STORE POINTER
	In	A,(Sio1AD)		;;         A = CHAR (CLR INTERRUPT)
	Ld	(Hl),A			;; STORE CHAR IN BUFFER
	Inc	Hl			;; INC CHAR-POINTER
	Ld	(LpRngIn),Hl		;;

	Ld	De,(LpRngBeg)		;; COMPUTE IF AT BUFFER END
	And	A			;;
	Sbc	Hl,De			;;
	Ld	De,(LpRngBfZ)		;;
	And	A			;;
	Sbc	Hl,De			;; CHECK IF AT BUFFER END
	Jr	Nz,NOTLptEnd		;;

	Ld	Hl,(LpRngBeg)		;; RESET POINTER TO BUFFER START
	Ld	(LpRngIn),Hl		;; SET NEW RING POINTER

NOTLptEnd:

	Ld	Hl,(LpRngCnt)		;;
	Inc	Hl			;; Inc RING BUFFER COUNTER
	Ld	(LpRngCnt),Hl		;;
LptXIT:
	Jp	BIOSINTEXIT		;;
LpFULL:
	In	A,(Sio1AD)		;;
	Jr	LptXIT			;;

	Cseg
	If	Not WrkStn
;------------------------------------------------------------;
; PioGAI -- INTERRUPT FROM GRAPHIC TERMINAL.
;  GRAPHIC TERMINAL OUTPUT INTERRUPT SERVICE ROUTIN.

PioGAI:	
	Call	BIOSINTENT		;

	Jp	PioGAIB0		;

	Dseg
PioGAIB0:

	Ld	Hl,GrOutCnt		;;
	Ld	A,1			;;
	Cp	(Hl)			;; CHECK IF ANYTHING TO SEND
	Jr	Nc,GrOutI100		;; IF NO

	Dec	(Hl)			;; DEC BYTE COUNTER
	Ift	GrOBufZ GT 1		;;
	Ld	Hl,(GrOutPnt)		;;
	Ld	A,(Hl)			;; GET BYTE TO SEND
	Out	(PioGAD),A		;; SEND THE BYTE
	Inc	Hl			;; INC OUT POINTER
	Ld 	De,GrOutBufEnd		;;
	Ld	A,L			;;
	Cp	E			;; CHECK IF AT BUFFER END
	Jr	Nz,GrOutI10 		;; IF NOT

	Ld	Hl,GrOutBuf		;;
GrOutI10:
	Ld	(GrOutPnt),Hl		;; SET NEW BUFFER OUT POINTER
	
	Else
	Ld	A,(GrOutBuf)		;; GET BYTE TO SEND
	Out	(PioGAD),A		;;
	Endif
	Jp	BIOSINTEXIT		;;

GrOutI100:
	Jp	Nz,BIOSINTEXIT		;; IF JUST A DUMMY INTERUPT
	Dec	(Hl)			;;
	Jp	BIOSINTEXIT		;;

; PioGBI -- GRAPHIC KEYBOARD INPUT INTERRUPT SERVICE ROUTIN.

	Cseg
PioGBI:	
	Call	BIOSINTENT		;

	Jp	PioGBIB0		;

	Dseg
PioGBIB0:
	Ld	Hl,GrCnt		;; Hl --> NO OF CHAR IN BUFFER
	Inc	(Hl)			;; INC CHAR-COUNTER 
	Ld	A,(Hl)			;; A = NO OF CHAR IN BUFFERT
	Cp	GrnEnd-GrnBeg-2		;; IS BUFFER FULL?
	Jr	Nz,PioGB9		;;

	Ld	A,00000011B		;;
	Out	(PioGBC),A		;; YES STOP PIO INTERUPT
PioGB9:
	In	A,(PioGBD)		;;  A = CHAR (CLR INTERRUPT)
	Ld	D,A			;; 
	And	7Fh			;; Mask parity bit
	Ld	(Last),A		;;
	Ld	Hl,(GrnIn)		;; Hl --> INPUT
	Ld	(LastPoint),Hl		;;
	Ld	(Hl),D			;; Save input char in buffer.
	And	A			;; Clear carry flag.
	Ex	De,Hl			;; SAVE INPUT POINTER IN De.
	Ld	Hl,GrnEnd		;; Hl=BUFFEREND FOR TEST
	Sbc	Hl,De			;; POINTER AT END?
	Inc	De			;;            INC
	Jp	Nz,PioGB2		;; NO...JUMP
	Ld	De,GrnBeg		;; SET POINTER TO BUFFERSTART
PioGB2:	Ld	(GrnIn),De		;; SAVE THE POINTER.
PioGB3:	
	Jp	BIOSINTEXIT		;;
	Endif
	Cseg

; TAKE CARE OF SPECIAL RECIVE CONDITION Kbd AND Lpt

KbdErRq:
	Push	Af			;
	In	A,(Sio1BD)		;
	Ld	A,30H			; ERROR RESET
	Out	(Sio1BC),A		;
	Jr	INTXIT			;
LptErRq:
	Push	Af			;
	In	A,(Sio1AD)		;
	Ld	A,30H			; ERROR RESET
	Out	(Sio1AC),A		;
INTXIT:	Pop	Af			;
	Ei				;
	Reti				;

;------------------------------------------------------------;
;                   Ctc Interrupt 10 Hz.                     ;
;------------------------------------------------------------;

ClkIrq:
	Ld	(StSav1),SP		; SPAR STACKPEKAREN
	Ld	SP,Stack1		; SÆTT LOKAL STACK
	Push	Af			; SPAR ANVÆNDARREGISTER▶8a◀	Push	Hl			;

	If	Not NetWork

	Ld	Hl,Cnt10		; LADDA 10-DELS-RÆKNAREN
	Dec	(Hl)			; RÆKNA NED 1.
	Jr	Nz,Clk2			; HOPPA OM EJ HEL SEKUND
	Ld	(Hl),10			; SÆTT 10 TIONDELAR.

	Ld	Hl,@Sec			; RÆKNA UPP REALTIDSKLOCKAN
	Ld	A,(Hl)			;
	Add	A,1			; ØKA MED 1.
	Daa				; JUSTERA BCD.
	Cp	60H			; 60 SEKUNDER ?
	Jr	C,Clk1			; NEJ...HOPPA

	Xor	A			; NOLLA SEKUND
	Ld	(Hl),A			; SPAR.
	Dec	Hl			; PEKA PÅ MINUT.
	Ld	A,(Hl)			;
	Inc	A			; ØKA MED 1.
	Daa				; JUSTERA BCD.
	Cp	60H			; 60 MINUTER ?
	Jr	C,Clk1			; NEJ...HOPPA

	Xor	A			; NOLLA MINUT.
	Ld	(Hl),A			;
	Dec	Hl			; PEKA PÅ TIMME
	Ld	A,(Hl)			;
	Inc	A			; ØKA MED 1.
	Daa				; JUSTERA BCD
	Cp	24H			; 24 TIMMAR ?
	Jr	C,Clk1			; NEJ...HOPPA

	Xor	A			; NOLLA TIMME
	Ld	(Hl),A			;
	Dec	Hl			; PEKA PÅ ANTAL DAGAR
	Dec	Hl			; F.O.M 1/1-78. (LÅG-BYTE)
	Inc	(Hl)			; ØKA MED 1.
	Jr	Nz,Clk2			; EJ 256 ...HOPPA
	Inc	Hl			; PEKA PÅ HØG-BYTE.
	Ld	A,(Hl)			;
	Inc	A			; ØKA MED 1.
Clk1:	Ld	(Hl),A			; SPAR A.

	Endif

Clk2:	Jp	ExtMcl			; CHECK FOR BUFFER TIME OUTS IN EXTMEM

Cnt10:	Db	10

	Page
;------------------------------------------------------------;
;               Port Initzialisation Tables                  ;
;------------------------------------------------------------;
	Dseg

VecSi1B:				;; CRT
		Db	3,Ctc1		;; 2 BYTES TO CTC CHAN 1
		Db	01000101B	;; CTC1: INT. DIS, COUNTER MODE,
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
CtcBaud		Equ	$-VecSi1B	;; Ix-index
BaudB:		Db	4		;; GIVES 307200 Hz TO SIO1B.
CTC1Vec: 	Db	0		;; CTCINTERRUPTVECTOR.

		Db	11,Sio1BC	;; 11 BYTES TO SIO1 B/TERMINAL
		Db	18H		;; RESET CHANNEL
		Db	12H		;; Wr 2:
SIOVec:		Db	0		;; INTERRUPTVECTOR
		Db	14H		;; Wr 4:
SioWr4		Equ	$-VecSi1B	;; Ix-index
		Db	00000000b	;; xx00xxxxb
		Db	13H		;; Wr 3:
SioWr3		Equ	$-VecSi1B	;; Ix-index
KbdWr3:		Db	00000001b	;; Rx enable. xxx00001b
		Db	15H		;; Wr 5:
SioWr5		Equ	$-VecSi1B	;; Ix-index
KbdWr5:		Db	10001010b	;; DTR, Tx enable, RTS, 1xx01010b
		Db	01		;; Wr 1:
		Db	00011100B	;; INT ON ALL Rx CHAR (PARITY DOES NOT
					;; AFFECT VECTOR), STATUS AFFECTS VECTOR.
		Db	0		;; END TABLE.
SioLen		Equ	$-VecSi1B	;; Table length


VecSi1A:				;; LPT
		Db	3,Ctc0		;; 3 BYTES TO CTC CHAN 0
		Db	01000101B	;; CTC0: INT. DIS, COUNTER MODE,
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
BaudA:		Db	4		;; GIVES 307200 Hz TO SIO1A
CTC0Vec: 	Db	0		;; CTCINTERRUPTVECTOR.

		Db	11,Sio1AC	;; 11 BYTES TO SIO1 A/MODEM
		Db	18H		;; RESET CHANNEL.
		Db	2,0		;; DUMMY INTERUPT VECTOR
		Db	14H		;; Wr 4:
		Db	00000000b	;; xx00xxxxb
		Db	13H		;; Wr 3:
LptWr3:		Db	00000001B	;; Rx enable. xxx00001b
		Db	15H		;; Wr 5:
LptWr5:		Db	10001011b	;; DTR,Tx enable,RTS,Tx CRC, 1xx01011b
		Db	01		;; Wr 1:
		Db	00011000B	;;  INTERRUPTS, 
		Db	0		;; END TABLE.

	If	Not WrkStn
					;; INIT EXTRA SERIE PORTS
VecSi3A:				;; LPT1
		Db	3,Ctc4		;; 3 BYTES TO CTC CHAN 0
		Db	01000101B	;; CTC0: INT. DIS, COUNTER MODE,
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
BaudC:		Db	4		;; GIVES 307200 Hz TO SIO3A
		Db	0		;; CTCINTERRUPTVECTOR. NOT USED

		Db	11,Sio3AC	;; 9 BYTES TO SIO3 A
		Db	18H		;; RESET CHANNEL.
		Db	2,0		;; DUMMY INTERUPT VECTOR
		Db	14H		;; Wr 4:
		Db	00000000b	;; xx00xxxxb
		Db	13H		;; Wr 3:
Lp1Wr3:		Db	00000000b	;; Rx disable. xxx00000b 
		Db	15H		;; Wr 5:
Lp1Wr5:		Db	10001011b	;; DTR,Tx enable,RTS,Tx CRC 1xx01011b
		Db	01		;; Wr 1:
		Db	00000000B	;;  NO INTERRUPTS, 
		Db	0		;; END TABLE.

VecSi3B:				;; LPT2
		Db	3,Ctc5		;; 3 BYTES TO CTC CHAN 0
		Db	01000101B	;; CTC5: INT. DIS, COUNTER MODE,
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
BaudD:		Db	4		;; GIVES 307200 Hz TO SIO3B
		Db	0		;; CTCINTERRUPTVECTOR. NOT USED

		Db	11,Sio3BC	;; 11 BYTES TO SIO3 B
		Db	18H		;; RESET CHANNEL.
		Db	2,0		;; DUMMY INTERUPT VECTOR
		Db	14H		;; Wr 4:
		Db	00000000b	;; xx00xxxxb
		Db	13H		;; Wr 3:
Lp2Wr3:		Db	00000000b	;; Rx disable. xxx00000b
		Db	15H		;; Wr 5:
Lp2Wr5:		Db	10001011b	;; DTR,Tx enable,RTS,Tx CRC 1xx01011b
		Db	01		;; Wr 1:
		Db	00000000B	;;  NO INTERRUPTS, 
		Db	0		;; END TABLE.

VecPio:					;; CEN
		Db	2,PioAC		;; 2 BYTES TO PIO A CTLR-REG.
		Db	00001111B	;; SELECT MODE 0 OPERATION
		Db	00000011B	;; INTERUPT DISABLE.
		Db	4,PioBC		;; 4 BYTES TO PIO B CTRL-REG.
		Db	11001111B	;; SELECT MODE 3 OPERATION
		Db	00101111B	;; BIT 7,6,4=OUTPUT ALL OTHERS INPUTS
		Db	00110111B	;; INTERRUPT CONTROL WORD = DISABLED
		Db	00000001B	;; MASK WORD, ONLY MONITOR BIT 0.
		Db	1,PioBD		;; 1 BYTE TO PIO B  DATA
		Db	01010000B	;;
		Db	0		;; End table

VecPioG:				;; GRAPH
		Db	3,PioGAC	;; BYTES TO PIOGA CONTROL
PIAVec:		Db	0		;; VECTOR FOR A
		Db	00001111B	;; OUTPUT ONLY. MODE 0
		Db	10000111B	;; ENABLE INTERRUPT.
		Db	3,PioGBC	;; BYTES TO PIOGB CONTROL
PIBVec:		Ds	1		;; VECTOR FOR B
		Db	01001111B	;; INPUT ONLY. MODE 1
		Db	10000111B	;; ENABLE INTERRUPT
		Db	0		;; End table
	Endif

					;; REAL TIME CLOCK INITIALIZATION TABLE
RestTbl:
		Db	2,Ctc2		;; 2 BYTES TO CTC CHAN 2
		Db	01000101B	;; CTC2: INT. DIS, COUNTER MODE,
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
		Db	0		;; GIVES 4800 Hz TO CTC3.


		Db	2,Ctc3		;; 2 BYTES TO CTC CHAN 3.
		Db	11000101B	;; INT. ENABLED, COUNTER MODE
					;; NEG. EDGE, TIME CONST. FOLLOWS,
					;; COUNTING CONT.
		Db	240		;; GIVES 20 Hz, WHICH IS DIVIDED
					;; BY 2 (HARDWARE).
					;; INERRUPT 10 times/second.
		Db	0		;; End table

	Page
;------------------------------------------------------------;
;              Variables, Buffers and Stacks.                ;
;------------------------------------------------------------;

	Cseg

MuxSave:	Ds	1		;
HlSave:		Ds	2		;
DeSave:		Ds	2		;

	Dseg

LpRngCnt:	Dw	0		;; NO OF CHAR IN BUFFER
LpRngIn:	Dw	LpBuff		;; POINTS TO INPUT PLACE
LpRngOut:	Dw	LpBuff		;; POINTS TO OUTPUT PLACE

LpRngBeg:	Dw	LpBuff		;; MAKE IT POSSIBLE TO SET BUFFER IN TPA
LpBuff:		Ds	20		;;
LpRngBfZ:	Dw	$-LpBuff	;;

QFlag:		Db	0		;; Set on status call Func2
Last:		Db	0		;; Last char
LastPoint:	Dw	0		;; Pointer to last char
RngCnt:		Db	0		;; NO OF CHAR IN BUFFER
RngIn:		Dw	RngBeg		;; POINTS TO INPUT PLACE
RngOut:		Dw	RngBeg		;; POINTS TO OUTPUT PLACE
					;; IF EQU BUFFER IS EMPTY.
RngBeg:		Ds	22		;; KEYBOARD RING BUFFER.
RngEnd		Equ	$-1		;;
	If	Not WrkStn
					;; GRAPHIC INPUT 
GrCnt:		Db	0		;; NO OF CHAR IN GRAPHIC RING BUFFER
GrnIn:		Dw	GrnBeg		;; POINTER TO GRAPHIC INPUT PLACE
GrnOut:		Dw	GrnBeg		;; POINTER TO GRAPHIC OUTPUT PLACE
GrnBeg:		Ds	22		;; GRAPHIC RING BUFFER
GrnEnd		Equ	$-1		;;


					; GRAPHIC OUTPUT
GrOutCnt:	Db	0		;; BYTE COUNTER
	Ift	GrOBufZ GT 1
GrInPnt:	Dw	GrOutBuf	;; BUFFER IN POINTER
GrOutPnt:	Dw	GrOutBuf	;; BUFFER OUT POINTER
	Endif
GrOutBuf:	Ds	GrOBufZ		;;
GrOutBufEnd	Equ	$		;;
	Endif

	End
«eof»