; LAST DATE CHANGED:			16:35	AUG 9, 1983
; USER.ASM					09-Aug-80
; CBIOS.ASM					28-DEC-82
;
TRUE	EQU	0FFFFH
FALSE	EQU	NOT TRUE
;
HDISK	EQU	FALSE	;DO BIOS FOR FLOPPY
FLOPPY	EQU	NOT HDISK
;
;
OVHD	EQU	0A00H		; DIFF TO MDS
;
;
MSIZE	EQU	48		; SYSTEM SIZE
IOBYTE	EQU	3
;
;
BIAS	EQU	(MSIZE-20)*1024-OVHD
;
CPMB	EQU	3400H+BIAS	; CCP
BDOS	EQU	3C00H+BIAS	; BDOS
BIOS	EQU	4A00H+BIAS	; START OF BIOS
	IF	HDISK
OFFSET	EQU	0A00H-CPMB	; TO SYSGEN IMAGE
USER	EQU	BIOS+0600H	; START OF USER AREA
	ENDIF
	IF	FLOPPY
OFFSET	EQU	0980H-CPMB	; TO SYSGEN IMAGE
USER	EQU	BIOS+0400H	; START OF USER AREA IN FLOPPY 2.2
	ENDIF
;
CUSER	EQU	4
JBDOS	EQU	5
TBUFF	EQU	80H
TPA	EQU	100H
MCOPYRT	EQU	BDOS+311H	;LOCATION OF COPYRIGHT MSG
SIGNON	EQU	BIOS-40H	;LOCATION OF 'ICOM' SIGNON MSG
;
CNTRL	EQU	0C0H	;FLOPPY CONTROL OUT PORT
DATAO	EQU	0C1H	;FLOPPY DATA OUT PORT
DATAI	EQU	0C0H	;FLOPPY STATUS/DATA IN PORT
FSKRD	EQU	0F282H	;ROUTINE TO SEEK, READ FROM FLOPPY
FRDBF	EQU	0F29DH	;ROUTINE TO READ FLOPPY BUFFER
FSKWR	EQU	0F2CFH	;ROUTINE TO SEEK, WRITE BUFFER TO FLOPPY
FWRTBF	EQU	0F2F7H	;ROUTINE TO WRITE TO FLOPPY BUFFER (128 BYTES)
FINIT	EQU	0F3A4H	;ROUTINE TO INITIALIZE THE FLOPPY CONTROLLER
FHOME1	EQU	0F3B6H	;ROUTINE TO HOME THE FLOPPY
XMITW	EQU	0F3CAH	;OUTPUT FLOPPY COMAND, WAIT FOR COMPLETION
XMIT	EQU	0F3D9H	;OUTPUT FLOPPY COMMAND
DENFLG	EQU	0F428H	;DENSITY FLAG FOR FLOPPY - 0=S.D., 2=D.D.
FRQDSK	EQU	0F430H	;FLOPPY REQUEST DRIVE
FRQTRK	EQU	0F431H	;FLOPPY REQUEST TRACK
RDBFFL	EQU	0F438H	;FLAG TELLING WHICH HALF OF BUFFER TO READ
FSEEKDR	EQU	0F43DH	;FLOPPY SEEK DRIVE NUMBER
FSEEKTK	EQU	0F43EH	;FLOPPY SEEK TRACK NUMBER
;
CR	EQU	0DH
LF	EQU	0AH
;
	ORG	BIOS
CBOOTE: 
	JMP	CBOOT
WBOOTE: 
	JMP	WBOOT
CONST: 
	JMP	VCONST
CONIN: 
	JMP	VCONIN
CONOUT: 
	JMP	BCONOUT
LIST: 
	JMP	VLIST
PUNCH: 
	JMP	VPUNCH
READER: 
	JMP	VREADER
BHOME: 
	JMP	HOME
BSELDSK: 
	JMP	SELDSK
BSETTRK: 
	JMP	SETTRK
BSETSEC: 
	JMP	SETSEC
BSETDMA: 
	JMP	SETDMA
BREAD: 
	JMP	READ
BWRITE: 
	JMP	WRITE
	JMP	VLISTST
BSECTRAN: 
	JMP	SECTRAN
	IF	HDISK
;.DSK A: DEFS
DPBASE: 
	DW	XLTHD	;HARD DISK TRANSLATION TABLE
	DW	0
	DW	0
	DW	0
;DIRBUF - ADDR OF 128 BYTE SCRATCPAD FOR DIR USE
	DW	DIRBUF
;DPBAC - DISK PARAMETER BLOCK FOR DRIVE A
	DW	DPBAC
;CSVA - SCRATCHPAD FOR DISK CHANGE CHECK DIFF FOR EACH DPH
	DW	CSVA
;ALVA - SCRATCHPAD FOR ALLOCATION INFO - DIFF FOR EACH DPH
	DW	ALVA
;.DSK B: DEFS
	DW	XLTHD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBDEF
	DW	CSVB
	DW	ALVB
;.DSK C: DEFS
	DW	XLTHD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBAC
	DW	CSVC
	DW	ALVC
;.DSK D: DEFS
	DW	XLTHD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBDEF
	DW	CSVD
	DW	ALVD
;.DSK E: DEFS
	DW	XLTHD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBDEF
	DW	CSVE
	DW	ALVE
;.DSK F: DEFS
	DW	XLTHD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBDEF
	DW	CSVF
	DW	ALVF
;.DSK G: DEFS
	DW	XLTSD	;SINGLE DENSITY TRANSLATION TABLE
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBGH	;DPB FOR S.D. FLOPPIES
	DW	CSVG	;EQU CSVI
	DW	ALVG	;EQU ALVI
;.DSK H: DEFS
	DW	XLTSD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBGH
	DW	CSVH	;EQU CSVJ
	DW	ALVH	;EQU ALVJ
;.DSK I: DEFS
	DW	XLTDD	;DOUBLE DENSITY TRANSLATION TABLE
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBIJ	;DPB FOR D.D. FLOPPIES
	DW	CSVI
	DW	ALVI
;.DSK J: DEFS
	DW	XLTDD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBIJ
	DW	CSVJ
	DW	ALVJ
;DPB FOR DISKS A,C; 1ST WORD IS TOTAL # OF SECTORS/TRACK
DPBAC: 
	DW	48
;BSH - DATA ALLOCATION BLOCK SHIFT FACTOR, FROM BLOCK SIZE
	DB	4
;BLM - BLOCK SHIFT MASK
	DB	15
;EXM - EXTENT MASK
	DB	0
;DSM - MAXIMUM STORAGE IN BLS UNITS(BSH=4,BLM=15=>BLS=2048)
	DW	2430-1
;DRM - TOTAL # OF DIRECTORY ENTRIES-1
	DW	512-1
;AL0,AL1 - RESERVES BLOCKS OF DATA FOR DIRECTORY ENTRIES
	DB	0FFH,0
;CKS - IF DISK MEDIA IS REMOVABLE, CKS=(DRM+1)/4; IF FIXED,=0
	DW	128
;OFF - NUMBER OF TRACKS TO SKIP ON PHYSICAL DISK-2 IS SKIP CPM
	DW	2
;DISK DEFINITIONS FOR ALL FIXED PLATTERS (NO DIR CHECK)
DPBDEF: 
	DW	48
	DB	4
	DB	15
	DB	0
	DW	2430-1
	DW	512-1
	DB	0FFH,0
	DW	0
	DW	2
DPBGH:
	DW	26
	DB	3
	DB	7
	DB	0
	DW	243-1
	DW	64-1
	DB	192,0
	DW	16
	DW	2
;DPB FOR 1.4 COMPATIBLE DOUBLE DENSITY DRIVES
DPBIJ:
	DW	52
	DB	4
	DB	15
	DB	0
	DW	243-1
	DW	128-1	;NOTE - 128 DIRECTORY ENTRIES, NOT 64
	DB	192,0	;
	DW	32	;
	DW	2
	ENDIF
	IF	FLOPPY
;.DSK A: DEFS
DPBASE: 
	DW	XLTDD	;DOUBLE DENSITY TRANSLATION TABLE
	DW	0
	DW	0
	DW	0
;DIRBUF - ADDR OF 128 BYTE SCRATCPAD FOR DIR USE
	DW	DIRBUF
;DPBAB - DISK PARAMETER BLOCK FOR DRIVE A
	DW	DPBAB
;CSVA - SCRATCHPAD FOR DISK CHANGE CHECK DIFF FOR EACH DPH
	DW	CSVA
;ALVA - SCRATCHPAD FOR ALLOCATION INFO - DIFF FOR EACH DPH
	DW	ALVA
;.DSK B: DEFS
	DW	XLTDD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBAB
	DW	CSVB
	DW	ALVB
;.DSK C: DEFS
	DW	XLTSD	;SINGLE DENSITY TRANSLATION TABLE
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBCD
	DW	CSVC
	DW	ALVC
;.DSK D: DEFS
	DW	XLTSD
	DW	0
	DW	0
	DW	0
	DW	DIRBUF
	DW	DPBCD
	DW	CSVD
	DW	ALVD
;DPB FOR 1.4 COMPATIBLE DOUBLE DENSITY DRIVES
DPBAB:
	DW	52
	DB	4
	DB	15
	DB	0
	DW	243-1
	DW	128-1	;NOTE - 128 DIRECTORY ENTRIES, NOT 64
	DB	192,0	;
	DW	32	;
	DW	2
DPBCD:
	DW	26
	DB	3
	DB	7
	DB	0
	DW	243-1
	DW	64-1
	DB	192,0
	DW	16
	DW	2
	ENDIF
	IF	HDISK
;SECTOR TRANSLATION TABLE FOR HARD DISK 48 SECT/TRACK
XLTHD: 
;UNSHIFTED TABLE SO SECTOR NUMBERS CORRESPOND TO FLOPPY 1-26
	DB	1,2,27,28,5,6,31,32,9,10,35,36,13,14,39,40,17,18
	DB	43,44,21,22,47,48,25,26,3,4,29,30,7,8,33,34
	DB	11,12,37,38,15,16,41,42,19,20,45,46,23,24
;ORIGIONAL TABLE (H.D. CONTROLLER TAKES SECTORS 0-23)
;	DB	0,1,26,27,4,5,30,31,8,9,34,35,12,13,38,39,16,17
;	DB	42,43,20,21,46,47,24,25,2,3,28,29,6,7,32,33
;	DB	10,11,36,37,14,15,40,41,18,19,44,45,22,23
	ENDIF
;SECTOR TRANSLATION TABLE FOR DOUBLE DENSITY DRIVES
XLTDD:
;STANDARD TABLE FOR D.D.
	DB	2,1,20,19,38,37,4,3,22,21,40,39,6,5,24,23
	DB	42,41,8,7,26,25,44,43,10,9,28,27,46,45,12,11
	DB	30,29,48,47,14,13,32,31,50,49,16,15,34,33
	DB	52,51,18,17,36,35
;	DB	1,2,19,20,37,38,3,4,21,22,39,40,5,6,23,24
;	DB	41,42,7,8,25,26,43,44,9,10,27,28,45,46,11,12
;	DB	29,30,47,48,13,14,31,32,49,50,15,16,33,34
;	DB	51,52,17,18,35,36
;SHIFTED TABLE TO MATCH H.D.
;	DB	0,1,18,19,36,37,2,3,20,21,38,39,4,5,22,23
;	DB	40,41,6,7,24,25,42,43,8,9,26,27,44,45,10,11
;	DB	28,29,46,47,12,13,30,31,48,49,14,15,32,33
;	DB	50,51,16,17,34,35
;SECTOR TRANSLATION TABLE FOR SINGLE DENSITY DRIVES
XLTSD:
;STANDARD TABLE FOR S.D.
	DB	1,7,13,19,25,5,11,17,23,3,9,15,21,2,8,14,20
	DB	26,6,12,18,24,4,10,16,22
;SHIFTED TABLE TO MATCH H.D. ROUTINES
;	DB	0,6,12,18,24,4,10,16,22,2,8,14,20,1,7,13,19
;	DB	25,5,11,17,23,3,9,15,21
;
;VCINIT INITIALIZES IOBYTE, PRINTER PORTS, SIO PORTS
CBOOT: 
	IF	FLOPPY
	CALL	READCPM	;USE BIOS TO READ CCP,BDOS ON COLD BOOT
	ENDIF
	CALL	VCINIT
	CALL	INIT1
	LXI	D,SIGNON
	CALL	MSGOUT
	LXI	D,MCOPYRT
	CALL	MSGOUT
	XRA	A
	STA	CUSER
	JMP	GOCPM
;WHEN FLOPPY PROM CHANGED,CAN ELIMINATE THIS
MWRPT: 
	DB	0DH,0AH,'DISK WRITE PROTECTED.$'
PRMWPT:
	LXI	D,MWRPT
	CALL	MSGOUT
	CALL	VCONIN
	CPI	3
	RNZ		;NO CONTROL-C, GO TRY AGAIN
WBOOT: 
	LXI	SP,TPA
	CALL	VWINIT
	CALL	INIT1
	IF	HDISK
	XRA	A
	STA	BOOTHD
	MVI	A,0DH
	LXI	H,BDOS+400H
	CALL	READCPM
	MVI	A,20H
	STA	BOOTHD
	XRA	A
	LXI	H,BIOS+100H
	CALL	READCPM
	ENDIF
;
	IF	FLOPPY
	CALL	READCPM	;RELOAD CCP,BDOS ON WARM BOOT
	ENDIF
	MVI	A,0FFH
GOCPM: 
	STA	BOOTFL
	MVI	A,0C3H
	STA	0
	STA	JBDOS
	LXI	H,WBOOTE
	SHLD	1
	LXI	H,BDOS+6
	SHLD	6
;INIT LOCS 50-53H
;	CALL	INIT2
	LXI	B,TBUFF
	CALL	SETDMA
	LDA	CUSER
	MOV	C,A
;SEE IF THERE IS AN AUTO-RUN FOR EITHER COLD OR WARM BOOT
	LDA	BOOTFL
	ORA	A
	LDA	MODE1
	RRC
	JZ	CBAUTO
	RRC
CBAUTO: 
	JNC	CPMB+3
	JMP	CPMB
	IF	FLOPPY
READCPM:
	MVI	A,10H	;SET D.D. CONFIGURATION
	OUT	DATAO
	MVI	A,15H
	CALL	XMIT
;
	MVI	A,1	;SEEK TO TRACK 1 TO READ CCP,BDOS
	OUT	DATAO
	MVI	A,11H
	CALL	XMIT
	MVI	A,9
	CALL	XMITW
	JNZ	RCPMERR
	MVI	C,1	;STARTING SECTOR ON TRACK 1 FOR CCP
	MVI	B,22	;NUMBER OF SECTORS TO READ
	LXI	H,CPMB	;STARTING ADDR OF CCP
;
RCPMLP:
	MOV	A,C	;SET SECTOR TO READ
	OUT	DATAO
	MVI	A,21H
	CALL	XMIT
	MVI	A,3	;READ SECTOR TO BUFFER
	CALL	XMITW
	ANI	8	;CHECK FOR CRC ERROR
	JNZ	RCPMERR
	MVI	A,40H	;READ BUFFER TO MEMORY
	OUT	CNTRL
	MVI	D,0	;READ 256 BYTES AT A TIME
RDLOOP:
	IN	DATAI
	MOV	M,A	;STORE BYTE AT DMA ADDR
	INX	H	;INCR DMA ADDR
	DCR	D	;DECR BYTE COUNT
	JNZ	RDLOOP
	XRA	A
	OUT	CNTRL
;
	MVI	A,9	;D.D. SKEW FACTOR
	ADD	C	;ADD TO SECTOR NUMBER
	CPI	27	;TEST FOR NUMBER >26
	JC	RSVSEC
	SUI	26	;SECTOR NUMBER MODULO 26
RSVSEC:
	MOV	C,A
	DCR	B	;DECR SECTOR COUNT
	JNZ	RCPMLP
	RET
RCPMERR:
	MVI	A,0BH	;CLEAR ERRORS
	CALL	XMIT
	JMP	READCPM
	ENDIF
	IF	HDISK
READCPM: 
	MOV	C,A
	MVI	A,(BIOS-100H)/256
	CMP	H
	JC	BUMPHL
	PUSH	B
	PUSH	H
	LDA	BOOTHD
	ORA	C
;OUTPUT HEAD,SECTOR
	OUT	0A7H
	MVI	A,30H
;READ SECTOR FROM DRIVE 0, INTO BUFFER 0
	CALL	OUTCMD
;	CALL	DKWAIT
	CALL	EXECUT
	ANI	7FH
;GOT AN ERROR TRYING TO READ, GOTO WBOOT
	JNZ	WBOOT
;PUT BUFFER INTO MEMORY
	CALL	RD256B
	POP	H
	POP	B
BUMPHL: 
	LXI	D,0D00H
	DAD	D
	MVI	A,13
	ADD	C
	CPI	24
	JC	READCPM
	SUI	24
	LXI	D,-1800H
	DAD	D
	JNZ	READCPM
	RET
;.READ BUFFER FROM DISK CONTROLLER
RD256B: 
	XRA	A
	MOV	B,A
	OUT	0A7H
;READ BUFFER 0 COMMAND
	MVI	A,50H
	CALL	OUTCMD
RDRDYL: 
	IN	0A4H
	RAL
	JNC	RDRDYL
RDBFLP: 
	IN	0A5H
	MOV	M,A
	INX	H
	DCR	B
	JNZ	RDBFLP
	RET
;OUTPUT A COMMAND TO THE DISK CONTROLLER - A7 ALREADY OUT
OUTCMD: 
	OUT	0A3H
OUTCLP1: 
	IN	0A2H
	RAL
	JNC	OUTCLP1
	IN	0A3H
	RET
	ENDIF
;WAIT FOR CONTROLLER TO EXECUTE COMMAND, GET STATUS, MASK OFF WPT BIT
;DKWAIT: 
;	IN	0A0H
;	RLC
;	JNC	DKWAIT
;	IN	0A1H
;	IN	0A3H
;	IN	0A5H
;	IN	0A1H
;	ANI	7FH
;	RET
	IF	HDISK
BOOTHD: 
	DB	0
	ENDIF
;THE RESULTS OF THIS ARE: 50H=B1H; 51H=B1H; 52H=2; 53H=64H
;INIT2: 
;	LXI	H,50H
;	LXI	D,0B1B1H
;	XRA	A
;	MOV	M,E
;	ADD	E
;	INX	H
;	MOV	M,D
;	ADD	D
;	INX	H
;	MVI	B,2
;	MOV	M,B
;	ADD	B
;	INX	H
;	MOV	M,A
;	RET
;	DW	0C000H
MSGOUT: 
	LDAX	D
	CPI	'$'	;24H
	RZ
	MOV	C,A
	CALL	VCONOUT
	INX	D
	JMP	MSGOUT
BCONOUT: 
	PUSH	B
	CALL	CLOSE
	POP	B
	JMP	VCONOUT
SELDSK: 
	MOV	A,C
	IF	HDISK
;CHANGE THIS TO 10 FOR 10 DRIVE SYSTEM
	CPI	10
	ENDIF
	IF	FLOPPY
	CPI	4	;FLOPPY SYSTEM IS FOUR DRIVES FOR NOW
	ENDIF
	LXI	H,0
	RNC
	IF	HDISK
;CHANGE THIS TO 0FH FOR A 10 DRIVE SYSTEM
	ANI	0FH
	ENDIF
	IF	FLOPPY
	ANI	07H	;FOR 4-6 DRIVES
	ENDIF
	STA	RQDRIVE
	DCX	H
	SHLD	CURTRK
	MOV	L,C
	MVI	H,0
	LXI	B,DPBASE
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	B
	RET
SETTRK: 
	MOV	L,C
	MOV	H,B
	SHLD	RQTRACK
	RET
SETSEC: 
	MOV	A,C
	STA	RQSECTOR
	RET
SETDMA: 
	MOV	L,C
	MOV	H,B
	SHLD	DMAADR
	RET
SECTRAN: 
	MOV	A,D
	ORA	E
;DE<>0, SECTOR TRANSLATION REQUESTED
	JNZ	SECTRN1
	MOV	L,C
	MOV	H,B
	RET
SECTRN1: 
	XCHG
	MVI	B,0
	DAD	B
	MOV	L,M
	MVI	H,0
	RET
HOME: 
	CALL	CLOSE
	LDA	RQDRIVE
	STA	SEEKDR
	JMP	HOME1
READ: 
	CALL	CHKSTK0	;CHECK FOR S.D. IF IT IS A FLOPPY
	JZ	RDDSEK	;S.D. FLOPPY, SKIP DEBLOCKING
	LXI	H,RQDRIVE
	LXI	D,DIRDRV
	CALL	CPARAM
;SKIP WRTDIR IF NO DIRECTORY BUFFER ACTIVE
	JNZ	RNDIRAC
	CALL	WRTDIR
;IF THERE WAS AN ERROR, RETURN
	RNZ
RNDIRAC: 
	LXI	H,RQDRIVE
	LXI	D,READDR
	CALL	CPARAM
;IF THE PHYSICAL SECTOR IN READDR = RQDRIVE, SECTOR ALREADY READ
	JZ	RALLOC
RDDSEK:
	LXI	H,RQDRIVE
	CALL	MOVE2SK
	CALL	SEEKRQ
	RNZ
RALLOC: 
	CALL	CHKSTK0	;IF S.D., ONLY NEED TO READ SECTOR FROM BUFFER
	JZ	RDSINGL
	LDA	RQSECTOR
	RRC
	ANI	80H
RDSINGL:
	LHLD	DMAADR
	XCHG
	IF	HDISK
	JMP	READBFR
	ENDIF
	IF	FLOPPY
	JMP	FRDBF	;GO READ FLOPPY BUFFER
	ENDIF
;	CALL	READBFR
;	RET
;
;ROUTINE TO CHECK FOR 1)FLOPPY DRIVE; 2)S.D. FLOPPY; 3)TRACK 0
;
CHKSTK0:
	LHLD	RQDRIVE	;GET DRIVE IN L, LSB OF TRACK IN H
	MOV	A,L
	IF	HDISK
	CPI	6
	JC	NFLOPPY	;NOT A FLOPPY, CLEAR Z FLAG
	ANI	8	;CHECK FOR D.D. DRIVE (8,9)
	RZ		;DRIVE IS 6,7 , IS S.D.
	ENDIF
	IF	FLOPPY
	CMA		;INVERT TO CHECK BIT 1 FOR 2,3 (C:,D:)
	ANI	2	;IF 0,1 THEN BIT 1=1, Z=0, D.D. DRIVE
	RZ		;DRIVE IS 2,3 IS SINGLE DENSITY DRIVE,RET Z=1
	ENDIF
	MOV	A,H
	ORA	A	;CHECK FOR TRACK 0, WHICH IS S.D.
	IF	HDISK
	RZ
NFLOPPY:
	XRA	A
	DCR	A
	ENDIF
	RET
;
;WRITE CPM SECTOR TO DISK, DOING DEBLOCKING IF NEEDED
;
WRITE: 
	MOV	A,C
	STA	WRFUNC
	CALL	CHKSTK0	;CHECK FOR S.D. FLOPPY
	JNZ	WRITE1	;NOT SINGLE DENSITY, DO DE-BLOCKING
	LHLD	DMAADR
	CALL	FWRTBF	;=0F2F7H; WRITE 128 BYTES TO CNTRLR BUFFER
	JMP	WRITE2	;FINISH UP WRITE
WRITE1:
	LXI	H,RQDRIVE
	LXI	D,DIRDRV
;IS DSKSEL,TRACK,SECTOR = DSKSEL1,TRACK1,SECTOR1?
	CALL	CPARAM
;NO
	JNZ	WNDIRAC
;COMPARE LOGICAL SECTOR,SECTOR1
	LDAX	D
	CMP	M
;LOGICAL SECTORS ARE THE SAME, GO MOVE DATA INTO WRBUFF
	JZ	WLSM
	MVI	A,0FFH
	STA	DIRDRV
	LHLD	DMAADR
	LXI	D,WRBUFF
;CHECK TO SEE WHICH LOGICAL SECTOR IN THE PHYSICAL SECTOR IS REQUESTED
	LDA	DIRSEC
	RRC
	JC	W2NDSC
	XCHG
W2NDSC: 
	IF	HDISK
	CALL	WRITBFR	;WRITE 256 BYTES TO CONTROLLER
	ENDIF
	IF	FLOPPY
	CALL	FWRTBFR
	ENDIF
WRITE2:
	LXI	H,RQDRIVE
	CALL	MOVE2SK
FINWRT: 
	MVI	A,0FFH
	STA	READDR
;SEEKWR SETS (A)=1,CLEARS Z FLAG IF THERE IS AN ERROR, SO JMP IS SUFFICIENT
	IF	HDISK
	JMP	SEEKWR	;GO SEEK, WRITE SECTOR TO DISK
	ENDIF
	IF	FLOPPY
	LDA	SEEKDR
	JMP	FSEEKWR
	ENDIF
;	CALL	SEEKWR
;	RZ
;	MVI	A,1
;	RET
WNDIRAC: 
	CALL	WRTDIR
	RNZ
WLSM: 
	LXI	H,RQDRIVE
	LXI	D,DIRDRV
	CALL	MOVEPAR
	LXI	D,WRBUFF
	LHLD	DMAADR
;MOVE THE USER WRITE BUFFER TO BIOS WRITE BUFFER
	CALL	LDIR80
	LDA	WRFUNC
	CPI	1
;IF WRFUNC=1, WRITE TO DIRECTORY
	JZ	WRTDIR
;CLEAR A TO SIGNAL GOOD WRITE, RETURN TO USER
	XRA	A
	RET
CLOSE: 
	LDA	DIRDRV
	INR	A
;IF DIRDRV=0FFH, NO DIRECTORY IN USE
	RZ
	PUSH	B
	CALL	WRTDIR
	POP	B
	RET
WRTDIR: 
	LXI	H,DIRDRV
	MOV	A,M
	INR	A
	RZ
	CALL	MOVE2SK
	MVI	A,0FFH
	STA	DIRDRV
	CALL	SEEKRQ
	RNZ
	LDA	DIRSEC
	INR	A
	RRC
	ANI	80H
	LXI	D,RDBUFF
	IF	HDISK
	CALL	READBFR
	ENDIF
	IF	FLOPPY
	CALL	FRDBF
	ENDIF
	LDA	DIRSEC
	RRC
	LXI	H,WRBUFF
	LXI	D,RDBUFF
	JNC	WDIR2ND
	XCHG
WDIR2ND: 
	LDA	SEEKDR	;MUST LOOK AT SEEK DRV (OLD WRITE DRIVE) IF NEW DIRDRV
	IF	HDISK
	CALL	WRITBFR+3	;WRITE TO BFR OF OLD DIRDRV, IN CASE NEW DIRDRV
	ENDIF
	IF	FLOPPY
	CALL	FWRTBFR
	ENDIF
	JMP	FINWRT
CPARAM: 
	LDAX	D
	ORA	A
	RM
;COMPARE DRIVE NUMBERS
	CMP	M
	RNZ
	INX	H
	INX	D
;COMPARE LSB OF TRACK NUMBERS
	LDAX	D
	CMP	M
	RNZ
	INX	H
	INX	D
;COMPARE MSB OF TRACK NUMBERS
	LDAX	D
	CMP	M
	RNZ
	INX	H
	INX	D
;COMPARE PHYSICAL SECTOR NUMBERS
	MOV	A,M
	INR	A	;COMPENSATE FOR RRC
	RRC
	ANI	7FH
	MOV	C,A
	LDAX	D
	INR	A	;COMPENSATE FOR RRC
	RRC
	ANI	7FH
	CMP	C
	RET
SEEKRQ: 
	MVI	A,0FFH
	STA	READDR
	IF	HDISK
	CALL	SEEKRD	;GO SEEK, READ SECTOR FROM DRIVE. (A)=1 IF ERROR
	ENDIF
	IF	FLOPPY
	LDA	SEEKDR
	CALL	FSEEKRD
	ENDIF
;	MVI	A,1
	RNZ
;MOVE THE SEEK PARAMETERS TO THE READ PARAMETERS
	LXI	H,SEEKDR
	LXI	D,READDR
	CALL	MOVEPAR
	RET
INIT1: 
	MVI	A,0FFH
	STA	DIRDRV
	STA	READDR
	XRA	A
	STA	SEEKDR
	STA	SEEKSC
	STA	FSEEKTK	;=0F43EH; SET TRK FOR FLOPPY INIT
	CALL	FINIT	;=0F3A4H; INIT FLOPPY CONTROLLER
	IF	HDISK
;0E0H= INITIALIZE DISK CONTROLLER
	MVI	A,0E0H
	CALL	OUTCMD
;GO WAIT FOR COMMAND
	CALL	EXECUT
	ENDIF
HOME1: 
	IF	HDISK
	LDA	SEEKDR	;CHECK FOR HOME OF FLOPPY
	CPI	6
	JNC	FHOME1A	; DO RESTORE ON FLOPPY DRIVE
	ENDIF
	LXI	H,0
	SHLD	SEEKTK
	DCX	H
	SHLD	CURTRK
	MOV	A,H
	STA	READDR
	IF	FLOPPY
	JMP	FHOME1A
	ENDIF
	IF	HDISK
SEEK: 
	LHLD	SEEKTK
;FORM PHYSICAL TRACK FROM LOGICAL TRACK (SHIFT OFF HEAD BIT)
	CALL	SHFT16R
	XCHG
;COMPARE REQUESTED TRACK TO CURRENT TRACK, RETURN IF THE SAME
	LHLD	CURTRK
	MOV	A,L
	CMP	E
	JNZ	NEEDSK
	MOV	A,H
	CMP	D
	MVI	A,0
	RZ
NEEDSK: 
	XCHG
;UPDATE CURRENT TRACK
	SHLD	CURTRK
	MOV	A,L
;OUTPUT LSB TRACK BITS TO CONTROLLER
	OUT	0A7H
;ADD DRIVE BITS TO SEEK COMMAND (0), AND MSB TRACK BIT
	LDA	SEEKDR
	ADD	A
	ANI	0CH
	MOV	B,A
	MOV	A,H
	ANI	1
	ORA	B
;GO ISSUE SEEK COMMAND
	CALL	OUTCMD
;WAIT FOR PREVIOSLY GIVEN COMMAND TO FINNISH - EXIT IF NOT DONE IN 65K TR
EXECUT: 
	PUSH	B
	LXI	B,65535	;0FFFFH
EXECLP: 
	IN	0A0H
	RLC
	JNC	EXECNR
	IN	0A3H
	IN	0A5H
	IN	0A7H
	IN	0A1H
	ORA	A
	POP	B
	RET
;CHECK TO SEE HOW MANY TIMES TRIED TO GET AN ANSWER FROM CONTROLLER
EXECNR: 
	DCX	B
	MOV	A,B
	ORA	C
;NOT TRIED 65K TIMES YET!
	JNZ	EXECLP
	CMA
	ORA	A
	POP	B
	RET
;SHIFT HL REGISTER 1 BIT TO THE RIGHT
SHFT16R: 
	ORA	A
	MOV	A,H
	RAR
	MOV	H,A
	MOV	A,L
	RAR
	MOV	L,A
	RET
	ENDIF
	IF	HDISK
SEEKWR: 
	LDA	SEEKDR	;CHECK FOR FLOPPY
	CPI	6
	JNC	FSEEKWR	;GO SEEK, WRITE ON FLOPPY
	CALL	SEEK
;MASK OFF WPT BIT, CHECK TO SEE IF ALL OTHERS ARE 0 - IF NOT, ERROR
	ANI	7FH
	JNZ	SEEKERR
;5 RETRIES
	MVI	D,5
RETRYWR: 
	CALL	GHDSEC
;OUTPUT THE HEAD, SECTOR TO THE CONTROLLER
	OUT	0A7H
	MVI	B,20H
	MVI	C,1
;FORM A WRITE BUFFER 1 TO SECTOR COMMAND
	CALL	GBFD2CM
	CALL	OUTCMD
	CALL	EXECUT
	JNZ	WRTERR
;CHECK FOR READ AFTER WRITE
	LDA	MODE1
	ANI	40H
	RZ
	CALL	GHDSEC
;OUTPUT THE HEAD, SECTOR TO THE CONTROLLER
	OUT	0A7H
	MVI	B,30H
	MVI	C,0
;FORM A READ SECTOR TO BUFFER 0 COMMAND
	CALL	GBFD2CM
	CALL	OUTCMD
	CALL	EXECUT
	RZ
ERROR: 
	DCR	D
	JNZ	RETRYWR
	JMP	SEEKERR
WRTERR: 
	RLC
	JNC	ERROR
	CALL	PRMWPT	;TELL USER DISK IS WRITE PROTECTED, LOOK FOR CNTRL C
	JMP	RETRYWR
	ENDIF
	IF	HDISK
;
;SEEK TO DESIRED TRACK AND READ A SECTOR INTO THE CONTROLLER
;
SEEKRD: 
	LDA	SEEKDR	;CHECK FOR FLOPPY
	CPI	6
	JNC	FSEEKRD	;GO SEEK, READ FLOPPY
	CALL	SEEK
;MASK OFF WPT BIT, CHECK OTHERS FOR 0
	ANI	7FH
	JNZ	SEEKERR
;5 RETRIES
	MVI	D,5
RETRYRD: 
	CALL	GHDSEC
;OUTPUT HEAD, SECTOR TO CONTROLLER
	OUT	0A7H
	MVI	B,30H
	MVI	C,0
;FORM A READ SECTOR TO BUFFER 0 COMMAND
	CALL	GBFD2CM
	CALL	OUTCMD
	CALL	EXECUT
	ANI	7FH
;IF NO ERRORS, RETURN
	RZ
	DCR	D
	JNZ	RETRYRD
SEEKERR: 
	MVI	A,1
	ORA	A
	RET
GHDSEC: 
	LDA	SEEKTK
;MASK OFF ALL BUT HEAD BIT
	ANI	1
	MOV	B,A
	LDA	SEEKDR
;MASK OFF ALL BUT PLATTER BIT
	ANI	1
	ADD	A
	ORA	B
	RRC
	RRC
	RRC
;FULL HEAD NUMBER IS IN 3 MSB
	ANI	0E0H
	MOV	B,A
	LDA	SEEKSC
;NOW MUST DECREMENT SECTOR NUMBER FROM TABLE TO MATCH CONTROLLER'S 0-23
	DCR	A
;NOW DIVIDE 0-47 NUMBER FOR 0-23 PHYSICAL SECTOR
	RRC
;MASK OFF ALL BUT PHYSICAL SECTOR BITS
	ANI	1FH
;ADD IN HEAD BITS
	ORA	B
	RET
GBFD2CM: 
	LDA	SEEKDR
;MASK OFF ALL BUT DRIVE BIT(S) - CHANGE TO 6 FOR 6 DRIVE SYSTEM
	ANI	6
	ADD	A
	ORA	C
;ADD IN BUFFER BITS
	MOV	C,A
	MOV	A,B
;IS THIS REALLY NEEDED?
	ANI	0F0H
;ADD IN COMMAND BITS
	ORA	C
	RET
	ENDIF
MOVE2SK: 
	LXI	D,SEEKDR
MOVEPAR: 
	MVI	B,4
	JMP	LDIR
LDIR80: 
	MVI	B,80H
LDIR: 
	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	LDIR
	RET
;	MVI	B,0
;	JMP	LDIR
	IF	HDISK
READBFR: 
	MOV	B,A	;SAVE (A)
	LDA	SEEKDR	;CHECK FOR FLOPPY (SHOULD THIS BE READDR?)
	CPI	6
	MOV	A,B	;RESTORE (A)
	JNC	FRDBF	;=0F29DH; GO READ FLOPPY BUFFER - NOTHING ELSE NEEDED
	ADI	80H
;OUTPUT NUMBER OF BYTES TO READ FROM BUFFER-0(256) OR 80H (128)
	OUT	0A7H
;READ BUFFER 0 INTO MEMORY
	MVI	A,50H
	CALL	OUTCMD
;IF (A) WAS 0 THEN A=80H, GO READ 1ST HALF OF BUFFER
	JNZ	READ1ST
;THE ABOVE JNZ SHOULD BE AFTER THIS INSTR, AND SHOULD GOTO JB47E
	MVI	B,80H
;IF (A) WAS 80H, A=0, SKIP OVER 1ST 128 BYTES
RBRDYL1: 
	IN	0A4H
	RAL
	JNC	RBRDYL1
RBFLP1: 
	IN	0A5H
	DCR	B
	JNZ	RBFLP1
;THER SHOULD BE NO LABEL HERE, AND JB47E S/B READ1ST
READ1ST: 
	MVI	B,80H
	JMP	READNXT
JB47E: 
	IN	0A4H
	RAL
	JNC	JB47E
READNXT: 
	IN	0A5H
	STAX	D
	INX	D
	DCR	B
	JNZ	READNXT
	JMP	EXECUT
	ENDIF
	IF	HDISK
WRITBFR: 
	LDA	RQDRIVE	;CHECK FOR FLOPPY
	CPI	6
	JNC	FWRTBFR	;GO WRITE TO FLOPPY BUFFER (256 BYTES)
	XRA	A
;WRITE 256 BYTES
	OUT	0A7H
;WRITE MEMORY TO BUFFER #1
	MVI	A,41H
	CALL	OUTCMD
	MVI	B,128
	CALL	WBMEM1
	MVI	B,128
	XCHG
	CALL	WBMEML
	JMP	EXECUT
WBMEM1: 
	IN	0A6H
	RAL
	JNC	WBMEM1
WBMEML: 
	MOV	A,M
	OUT	0A7H
	INX	H
	DCR	B
	JNZ	WBMEML
	RET
	ENDIF
;OUTCMD: 
;	OUT	0A3H
;OUTCLP2: 
;	IN	0A2H
;	RAL
;	JNC	OUTCLP2
;	IN	0A3H
;	RET
;
FHOME1A:
;	CALL	FSKSET	;SET PARAMETERS FOR GDRSEC IN FHOME1
	LDA	SEEKDR
	RRC
	RRC
	ANI	040H	;ONLY HAVE DRIVES 0,1
	INR	A
	JMP	FHOME1+3	;=0F3B6H; HOME SELECTED FLOPPY DRIVE
;
FRDBFR	EQU	FRDBF	;NO OTHER CODE NEEDED, GO TO FRDBF
;
FWRTBFR:
	CALL	FWRTBF	;=0F2F7H; WRITE 128 BYTES TO CONTROLLER
	XCHG
	JMP	FWRTBF	;WRITE LAST 128 BYTES TO BUFFER
FSEEKRD:
	CALL	FSKSET	;GO MOVE PARAMETERS TP FLOPPY RAM @ F400
	XRA	A
	STA	RDBFFL	;=0F438H; THIS IS A BYTE COUNT USED IN FRDBFR
	JMP	FSKRD	;=0F282H; GO SEEK, READ THE FLOPPY
;
FSEEKWR:
	CALL	FSKSET
FSEKRTY:
	CALL	FSKWR	;GO SEEK, WRITE SECTOR TO FLOPPY
	IN	DATAI	;=0C0H; CHECK FOR FLOPPY WRITE PROTECTED
	ANI	10H	;MASK ALL BUT WPT BIT
	RZ
	CALL	PRMWPT	;"DISK WRITE PROTECTED", CHECK FOR CONTROL-C
	JMP	FSEKRTY	;TRY AGAIN (HOPEFULLY, WPT HAS BEEN REMOVED)
;
FSKSET:
	MOV	D,A	;SAVE DRIVE NUMBER
	IF	HDISK
	ANI	8	;SET UP BIT TO TELL FLOPPY PROM SD OR DD
	RRC
	RRC
	ENDIF
	IF	FLOPPY
	CMA		;INVERT, SINCE 0,1 ARE D.D. DRIVES IN FLOPPY 2.2
	ANI	2	;MASK OUT ALL BUT MSB OF DRIVE - 1= DRIVE 0,1(A,B)
	ENDIF
	MOV 	E,A	;A=0, S.D.; A=2, D.D. FLOPPY
	LXI	H,DENFLG	;=0F428H; DENSITY FLAG
	MOV	A,D
	ANI	1	;FIND IF DRIVE 'A' OR 'B'
	MOV	D,A	;SAVE FOR SETTING FSEEKDR
	ADD	L	;HL=0F429H IF 'B'
	MOV	L,A
	MOV	M,E	;SET DENSITY FLAG
	MOV	A,D	;RECOVER FSEEKDR
	LXI	H,SEEKDR+1
	LXI	D,FSEEKDR	;=0F43DH; FLOPPY PARAMETERS IN RAM
	STAX	D	;MOVE SEEK DRIVE NUMBER
	STA	FRQDSK	;MOVE TO FLOPPY REQUEST DISK ALSO
	INX	D
	MOV	A,M
	STAX	D	;MOVE TRACK # (LSB CPM 2.0 TRACK)
	STA	FRQTRK	;MOVE TO FLOPPY REQUEST TRACK ALSO
	INX	H
	INX	D
	INX	H	;SKIP CPM2.0 MSB TRACK
	MOV	A,M
;THE INSTRUCTION BELOW IS NO LONGER NEEDED - H.D. ROUTINE MODIFIED
;	INR	A	;SHIFT SECTOR NUMBER FOR 3812 (SECTORS 1-26)
	STAX	D	;MOVE SECTOR NUMBER
;	LHLD	RQDRIVE
;	SHLD	FRQDSK	;=0F430H; FLOPPY REQUEST DRIVE
	RET
;
EBIOS	EQU	$	;END OF BIOS. MUST BE < MAREA
BIOSSP	EQU	(USER-10H)-EBIOS	;SPACE REMAINING
;
	ORG	USER-10H	; START OF MODE AREA
;
;
;****************************************************************
;*								*
;*			MODE AREA				*
;*								*
;****************************************************************
;
;
;
MAREA	EQU	$		; MODE AREA
;
IOCONF:	DB	81H	;CON:=SERIAL PORT A(16/17);LST:=CENTRONICS (PORTS 2,3)
;
PINTABL:			; PRINTER INITIALIZATION DATA
LSTLEN:	DB	132		; CHARACTERS PER LINE
	DB	0	
	DB	0
	DB	0
;
;
	DB	0,0,0,0,0,0,0,0,0
;
;
MODE2:	DB	0		; RESERVED
MODE1:	DB	0		; SET MODE HERE
;
WAUTO	EQU	2
CAUTO	EQU	1
RAW	EQU	40H		; READ AFTER WRITE
;
;
;
;****************************************************************
;*								*
;*			USER AREA				*
;*								*
;****************************************************************
;
SUSER	EQU	$		; START OF USER AREA
;
; MISC. PRINTER ROUTINES
; PICK ONE
;
CENT	EQU	TRUE
QUME	EQU	FALSE
LPTSIO	EQU	FALSE
;
VCINIT:	JMP	UCINIT
VWINIT:	JMP	UWINIT
VCONST:	JMP	UCONST
VCONIN:	JMP	UCONIN
VCONOUT	JMP	UCONOUT
VLIST:	JMP	ULIST
VPUNCH:	JMP	UPUNCH
VREADER	JMP	UREADER
VLISTST	JMP	ULISTST
;
;
UCINIT:	LDA	IOCONF
	STA	IOBYTE
	IF	QUME
	CALL	PLSTINIT	; INITIALIZE QUME PRINTER
	ENDIF
	JMP	SIOINIT
;
;
UWINIT:	RET
;
;
UCONST:
	LDA	IOBYTE
	CALL	DSPACH
	DW	SPAIST
	DW	SPAIST
	DW	SPAIST
	DW	SPBIST
;
;
UCONIN:
	LDA	IOBYTE
	CALL	DSPACH
	DW	SPAIN
	DW	SPAIN
	DW	SPAIN
	DW	SPBIN
;
;
UCONOUT:
	LDA	IOBYTE
	CALL	DSPACH
	DW	PLIST 
	DW	SPAOUT
	DW	SPAOUT
	DW	SPBOUT
;
;
ULIST:
	LDA	IOBYTE
	RLC ! RLC
	CALL	DSPACH
	IF	LPTSIO AND NOT(CENT OR QUME)
	DW	PLIST
	DW	PLIST
	DW	SPBOUT 
	DW	PLIST 
	ENDIF
	IF	CENT OR QUME
	DW	SPBOUT
	DW	PLIST
	DW	PLIST
	DW	PLIST
	ENDIF
;
;
UPUNCH:
	LDA	IOBYTE
	RAR ! RAR ! RAR ! RAR
	CALL	DSPACH
	DW	SPAOUT
	DW	SPBOUT
	DW	SPAOUT
	DW	SPBOUT
;
UREADER:
	LDA	IOBYTE
	RAR ! RAR
	CALL	DSPACH
	DW	SPAIN
	DW	SPBIN
	DW	SPAIN
	DW	SPBIN
;
ULISTST:
	LDA	IOBYTE
	RLC ! RLC
	CALL	DSPACH
	IF	LPTSIO AND NOT(CENT OR QUME)
	DW	PLISTST
	DW	PLISTST
	DW	SPBIST
	DW	PLISTST
	ENDIF
	IF	CENT OR QUME
	DW	SPBIST
	DW	PLISTST
	DW	PLISTST
	DW	PLISTST
	ENDIF
;
;
DSPACH:	SHLD	USERHL	;SAVE USER'S HL
	POP	H	; GET TABLE ADDRESS
	ANI	3	; ONLY 4 ENTRIES
	ADD	A	; 2 BYTE TABLE
	ADD	L	; ADD OFFSET
	MOV	L,A	; TO HL
	JNC	DSPCH1
	INR	H
DSPCH1:	MOV	A,M	; LO BYTE TO [A]
	INX	H	; BUMP POINTER
	MOV	H,M	; HI BYTE TO [H]
	MOV	L,A	; LO BYTE TO [L]
	PUSH	H	;PUSH JMP ADDRESS ON STACK
	LHLD	USERHL	;RECOVER USER'S HL
	RET		; BLAST OFF.....
;
USERHL:	DW	0
;
BS	EQU	8
TAB	EQU	9
FF	EQU	12
;
SPASTAT	EQU	16
SPBSTAT	EQU	20
;
SPADATA	EQU	17
SPBDATA	EQU	21
;
;
SIOINIT:			;COLD BOOT INIT
	MVI	A,3
	OUT	SPASTAT
	OUT	SPBSTAT
	MVI	A,11H
	OUT	SPASTAT
	OUT	SPBSTAT
	RET
;
;
;
;
SPAOST:				;CONSOLE STATUS ROUTINE
	IN	SPASTAT
	RRC ! RRC
	SBB	A
	RET
;
SPBOST:
	IN	SPBSTAT
	RRC ! RRC
	SBB	A
	RET
;
SPAIST:
	IN	SPASTAT
	RRC
	SBB	A
	RET
;
SPBIST:
	IN	SPBSTAT
	RRC
	SBB	A
	RET
;
;
;
SPAIN:	
	CALL	SPAIST
	JZ	SPAIN
	IN	SPADATA
	ANI	7FH
	RET
;
SPBIN:	CALL	SPBIST
	JZ	SPBIN
	IN	SPBDATA
	ANI	7FH
	RET
;
;
;
SPAOUT:	CALL	SPAOST
	JZ	SPAOUT
	MOV	A,C
	OUT	SPADATA
	RET
;
SPBOUT:	CALL	SPBOST
	JZ	SPBOUT
	MOV	A,C
	OUT	SPBDATA
	RET
;
;
	IF	LPTSIO AND NOT(CENT OR QUME)
PLIST:
	RET
PLISTST:
	XRA	A
	CMA		;FOR ALWAYS READY
	RET
	ENDIF
;
;
	IF	CENT OR LPTSIO
PLSTINIT:
	RET		;NO SPECIAL INIT FOR CENTRONICS OR SIO PRINTERS
	ENDIF
;
;
	IF	CENT
;
;*** CENTRONIX PRINTER ***
;CENTRONICS PRINTER OUTPUT ROUTINE
CENTC	EQU	18		;CENTRONICS CONTROL PORT
CENTD	EQU	19		;CENTRONICS DATA PORT
CENTBE	EQU	2		;   "       BUFFER EMPTY BIT
PLIST:
CLIST:				;CENTRONIX OUTPUT ROUTINE
	LDA	LPTLEN
	ORA	A		;INIT?
	JNZ	LPTOT1		;ALREADY INIT
INITCP:				;INIT FOR CENTRONICS
	MVI	A,3
	OUT 	CENTC
	MVI	A,11H
	OUT	CENTC
	MVI	A,255
	STA	LPTLEN		;SET MAX LINE LENGTH
LPTOT1:				;THIS DOES THE ACTUAL OUTPUT
;	MOV	A,C		;GET CHAR
;	CPI	LF
;	JNZ	LPTOT2		;IGNORE LF
;	STA	LPTLST
;	LDA	LPTPOS		;IF FIRST
;	ORA	A
;	RZ			;CHAR ON LINE
;LPTOT2:
	MOV	A,C
	CPI	FF
	JZ	LPTWAT
	CPI	BS
	JZ	LPTWAT
	CPI	TAB
	JZ	MORSPC
	CPI	CR
	JZ	CRTRIK
	RC			;IGNORE OTHER CONTROL CHARS
				;MAKE SURE FORM FEEDS IGNORED
	LDA	LPTPOS
	INR	A
	PUSH	H
	LXI	H,LPTLEN
	CMP	M
	POP	H
	JNZ	NOTENL
CRTRIK:				;SPECIAL HANDLING FOR CR
;	LDA	LPTPOS
;	ORA	A		;POSITION 0?
;	JNZ	ATENL		;PRINT CR IF NOT ENL
;	LDA	LPTLST
;	CPI	CR		;IGNORE 2 CR IN A ROW
;	RZ
	MVI	C,LF		;CHANGE POS0 CR TO LF
ATENL:	XRA	A
NOTENL:				;SAVE POSITION OF CHAR
	STA	LPTPOS
	MOV	A,C
	STA	LPTLST		;STORE LAST CHAR
LPTWAT:				;PHYSICAL DRIVER
	IN	CENTC
	ANI	CENTBE
	JZ	LPTWAT		;NOT READY TO OUTPUT
	MOV	A,C
	OUT	CENTD		;SEND CHAR TO PRINTER
	RET			;DONE
MORSPC:				;TAB ROUTINE
	MVI	C,' '
	CALL	LPTOT1
	LDA	LPTPOS
	ANI	7
	JNZ	MORSPC
	RET		;DONE
PLISTST:
CSTAT:
	IN	CENTC
	ANI	CENTBE
	RZ		;IF A=0, NOT READY TO SEND CHARACTER
	MVI	A,0FFH
	ORA	A
	RET		;IF A=0FFH, READY TO SEND CHARACTER
;
LPTPOS:	DB	0		;POSITION
LPTLEN:	DB	0		;DOUBLES AS INIT FLAG
LPTLST:	DB	0		;LAST CHAR
	ENDIF
;
	IF	QUME
;
;
;
;
;****************************************************************
;*								*
;*		QUME PRINT DRIVER				*
;*								*
;*								*
;****************************************************************
;
;
QBASE	EQU	60Q
QUME1	EQU	QBASE+1
QUME2	EQU	QBASE+3
QINC	EQU	10	; CHARACTER INCREMENT IN 1/120 PER INCH
QLINCM	EQU	8	; LINE FEED INCREMENTS IN 1/48 OF AN INCH
;
;
;
PLSTINIT:
QINIT:	XRA	A
	STA	LPTPOS
	OUT	QBASE
	OUT	QBASE+2
	OUT	QBASE+4
	OUT	QBASE+5
	OUT	QBASE+6
	CMA
	OUT	QBASE+1
	OUT	QBASE+3
	OUT	QBASE+7
	MVI	A,54Q
	OUT	QBASE
	OUT	QBASE+2
	OUT	QBASE+4
	OUT	QBASE+6
 	MVI	A,374Q
	OUT	QBASE+7
	MVI	A,372Q
	OUT	QBASE+7
	LXI	H,0
	SHLD	QMOV
	SHLD	QPOS
	RET
;
;
;
;
PLIST:
;
;
;
; QUME PRINTER ROUTINES FROM MITS SHIT
;
;
QLIST:
	IN	QBASE+5
	INR	A
	RZ		; RETURN IF NOTHING THERE
	MOV	A,C	; GET CH TO PRINT
	ANI	07FH
	MOV	C,A
	CPI	' '
	LDA	LPTPOS
	JM	CRCHK	; CHECK FOR CR OR LINE FEED
	JZ	QSPACE	; SPECIAL HANDLING FOR SPACE
LIST1:	CALL	QMOVE	; PRINTABLE CHARACTER,MOVE CURSOR
	MOV	A,C
	ADD	A
	CMA		; FOR THE JERKS AT MITS
	OUT	QUME1	; SEND CHARACTER
	CALL	QWAIT	; READY TO PRINT
	MVI	A,337Q
	OUT	QUME2	; SEND CHAR. STROBE
	ORI	40Q	;
	OUT	QUME2	; RESET CHAR. STROBE
	LDA	LPTPOS	; GET CURRENT POSITION
	LXI	H,LPTLEN; GET ADD. OF LENGTH
	CMP	M	; END OF CARRIAGE?
	RNZ
QELN:	MVI	C,15Q	; SEND FAKE CR
	CALL	QLIST
; FALL THROUGH TO QLF;LINE FEED ROUTINE
;
QLF:	LXI	H,QLINCM*2	; LOAD LINE INCREMENT(ACTIVE LOW)
	CALL	QWAIT
	MOV	A,L
	CMA
	OUT	QUME1
	MOV	A,H
	CMA
	ANI	127	; TAKE PAPER FEED LOW
	OUT	QUME2
	ORI	080H
	OUT	QUME2
; FALL THROUGH TO RETURN ROUTINE
;
ENQME:	RET
;
;
QSPACE:	INR	A
	LXI	H,LSTLEN
	CMP	M	; END OF LINE
	JZ	QELN
	STA	LPTPOS
	LXI	D,QINC	; GET CHARACTER INCREMENT
	LHLD	QMOV	; GET MOVE VALUE
	DAD	D	; ADD INCREMENT TO MOVE
	SHLD	QMOV	; SAVE NEW MOVE VALUE
 	RET
;
QMOVE:	INR	A	; BUMP CH. POSITION
	STA	LPTPOS	; 
	LXI	D,QINC
	LHLD	QMOV
	DAD	D
	XCHG
	LHLD	QPOS
	DAD	D
	SHLD	QPOS
QBAK:	CALL	QWAIT
	MOV	A,E
	CMA
	OUT	QUME1
	MOV	A,D
	CMA
	ANI	(NOT 100Q) AND 0FFH
	OUT	QUME2
	ORI	100Q
	OUT	QUME2
	LXI	H,0
	SHLD	QMOV
	RET
;
CRCHK:	MOV	A,C
	CPI	10
	JZ	QLF
	CPI	13	; IS IT CARRIAGE RET
	JZ	SENCR
	CPI	12	; IS IT A FORM FEED
	JZ	SENFOR	;
	RET		; OTHERWISE DONT SEND ANYTHING
;
SENCR:	XRA	A
	STA	LPTPOS
	LHLD	QPOS	; GET # TO BACK CARRIAGE
	XCHG		; INTO [D,E]
	MOV	A,D	; GET D
	ORI	8	; LEFT MOVEMENT OF CARRIAGE
	MOV	D,A
	LXI	H,0
	SHLD	QPOS
	JMP	QBAK
;
;
SENFOR:	CALL	QWAIT
	MVI	A,322Q	; PULL TOF LOW
	OUT	QBASE+7
	ORI	32	; BACK UP
	OUT	QBASE+7
	RET
;
;
;
QPOS:	DW	$-$	; CURRENT INCREMENTAL POSITION
QMOV:	DW	$-$	; DISTANCE TO MOVE CARRIAGE
LPTPOS:	DB	$-$	; CURRENT CARRIAG POSITION
LPTLEN:	DB	$-$	; MAX LINE LENGTH
;
;
QWAIT:
	IN	QBASE+5
	RLC		; ROTATE BUFFER READY INTO CARRY
	JC	QWAIT
	RET
;
PLISTST:
QSTAT:	IN	QBASE+5
	RLC		; BUFFER NOT READY TO CARRY
	SBB	A	; [A] NON ZERO IF PRINTER NOT READY
	CMA
	ORA	A
	RET
;
	ENDIF
;
;
ENUSER	EQU	$		; END OF USER AREA
	DS	200H-(ENUSER-SUSER)
;
;
;****************************************************************
;*								*
;*		DATA AREA STARTS HERE				*
;*								*
;****************************************************************
;
SDATA	EQU	$		; START OF DATA AREA

RQDRIVE: 
	DB	0
RQTRACK: 
	DW	0
RQSECTOR: 
	DB	0
DMAADR: 
	DW	80H
READDR: 
	DB	0FFH
READTK: 
	DW	0
READSC: 
	DB	0
DIRDRV: 
	DB	0FFH
DIRTRK: 
	DW	0
DIRSEC: 
	DB	0
SEEKDR: 
	DB	0FFH
SEEKTK: 
	DW	0
SEEKSC: 
	DB	0
BOOTFL: 
	DB	0
WRFUNC: 
	DB	0
;CURTRK IS PHYSICAL TRACK,=SEEKTK/2
CURTRK: 
	DW	0
DIRBUF: 
	DS	128
	IF	HDISK
ALVA: 
	DS	304
CSVA: 
	DS	128
ALVB: 
	DS	304
CSVB:
	DS	0
ALVC: 
	DS	304
CSVC:
	DS	128
ALVD: 
	DS	304
CSVD: 
	DS	0
RDBUFF:
	DS	128
	DS	64
BDSTK:
	DS	0
	ORG	0F800H
ALVE:
	DS	304
CSVE:
	DS	0
ALVF:
	DS	304
CSVF:
	DS	0
ALVG:
	DS	31
CSVG:
	DS	16
ALVH:
	DS	31
CSVH:
	DS	16
ALVI:
	DS	31
CSVI:
	DS	32
ALVJ:
	DS	31
CSVJ:
	DS	32
WRBUFF: 
	DS	128
;STACK GROWS DOWNWARD (ROOM FOR 32 CALLS,PUSHES)
BDSTACK	EQU	0FC00H
	ENDIF
	IF FLOPPY
ALVA:
	DS	31
CSVA:
	DS	32
ALVB:
	DS	31
CSVB:
	DS	32
ALVC:
	DS	31
CSVC:
	DS	16
ALVD:
	DS	31
CSVD:
	DS	16
RDBUFF:
	DS	128
WRBUFF:
	DS	128
	ENDIF
ECPM	EQU	$		;END OF CPM DATA AREA
	END
