ווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווdifications by Mike Goetz and Hank Kee - 9/2/81
;
;	corrected PIP A:=B:filename.ext on Persci 277/299
;		Persci's must be configured as A: and B:
;		and/or C: and D: since they have but one
;		arm to access two drives
;	modified sign-on message to properly generate size
;		from MEMSIZE definition during assembly
;	corrected current drive assignment on warm boot
;	inclusion of LIST serial driver for CCS 8250 (30 CPS)
;		option to support LA34/LA36
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
; This version modified for 4 drives, A, B, C, D, 2-8" and 2-5"
; In this first version, the boot drive is "A:" only, the 1st 8"
;
; MISC EQUATES
;
PERSCI:	EQU	1		;ONE IF PERSCI DRIVE
ADDLIO:	EQU	0		;ZERO IF NO LIST, NO PUNCH
VERS:	EQU	22		;VERSION 2.2
MEMSIZ	EQU	48		;48K SYSTEM
MEMT	EQU	MEMSIZ*1024
;
; THE FOLLOWING VARIABLE IS THE NUMBER OF SECTORS PER TRACK ON
; THE BOOT DRIVE.  IT ALSO TELLS IF THE BOOT DRIVE IS 8" OR 5"
; AND IF IT IS DRIVE A: OR C:
;
BOOTSPT	EQU	26		;BOOT DRIVE SECT/TRK
;
; THE FOLLOWING PARAMETER VALUES FOR VERSION 2.0
;
CCPSIZ	EQU	16*128
BDOSIZ	EQU	28*128
BIOSIZ	EQU	12*128		;7 ON DISK, EXCESS UNINITIALIZED RAM
STACK	EQU	MEMT
;
BIOS	EQU	MEMT-BIOSIZ
BDOS	EQU	BIOS-BDOSIZ
CCP	EQU	BDOS-CCPSIZ
BASE	EQU	0		;BASE OF USABLE RAM
IOBYTE	EQU	BASE+3		;I/O DEVICE ASSIGNMENT BYTE
LOGDSK	EQU	BASE+4		;WHERE CPM STORES DEFAULT DRIVE
FCB	EQU	BASE+5CH	;DEFAULT FILE CONTROL BLOCK
BUFF	EQU	BASE+80H	;DEFAULT DISK BUFFER
TPA	EQU	BASE+100H	;BASE OF TRANSIENT PGM AREA
;
; MISC CPM EQUATES
;
RTCNT	EQU	10		;NO RETRIES ON DISK ERROR
SERIAL:	EQU	0		;SERIAL PRINTER OPTION W/8250
MEMONES:EQU	MEMSIZ-(MEMSIZ/10*10)
MEMTENS:EQU	MEMSIZ/10
;
;	CROMEMCO 4FDC I/O ASSIGNMENTS
;
STAT:EQU	00H		;3P + S, 4FDC, TU-UART, OR SCC
CONDATA:EQU	01H
CONIMOD:EQU	02H		;(3P + S DOESNT HAVE THESE)
CONIMSK:EQU	03H
PARPORT:EQU	04H		;NOT USED
;
FDCSTAT:EQU	30H		;4FDC OR CCS 2422 BOARD
FDCTRK:	EQU	31H
FDCSECT:EQU	32H
FDCDATA:EQU	33H
FDCFLAG:EQU	34H
;
BANKSEL:EQU	40H		;MEMORY BANKING PORT
;
;	1771/179X EQUATES
;
HEADLD:	EQU	08H
VERIFY:	EQU	04H
;
		IF	ADDLIO = 1
;
;	OTHER DEFINITIONS (OPTIONAL)
;
BAUDRATE:	EQU	01H		;110 BAUD FOR READER ?
RFDCSTAT:	EQU	10H
RBAUDPORT:	EQU	RFDCSTAT	;TU-UART BOARD FOR PAPER TAPE
RFDCDATA:	EQU	RFDCSTAT+1
PFDCSTAT:	EQU	10H
PBAUDPORT:	EQU	PFDCSTAT	;PAPER TAPE PUNCH ALSO
PFDCDATA:	EQU	PFDCSTAT+1
LFDCSTAT:	EQU	54H		;PARALLEL PRINTER POARD
LFDCDATA:	EQU	LFDCSTAT
		ENDIF

TRUE:	EQU	-1
FALSE:	EQU	0
;
SDATA:	EQU	20H		;DATA PORT
SINTEN:	EQU	21H		;INTERRUPT REGISTER
SIDENT:	EQU	22H		;INTERRUPT IDENTIFICATION
SLCTRL:	EQU	23H		;LINE CONTROL REGISTER
SMDMCT:	EQU	24H		;MODEM CONTROL REGISTER
SLSTAT:	EQU	25H		;LINE STATUS REGISTER
SMDMST:	EQU	26H		;MODEM STATUS REGISTER
SSTATP:	EQU	25H		;SERIAL PRINTER STATUS PORT (INPUT)
STBE:	EQU	20H		;SERIAL PRINTER TBE BIT
;
	ORG	BIOS
;
;	JUMP VECTOR
;
	JMP	CBOOT
	JMP	WBOOT
	JMP	CONSTAT
	JMP	CONIN
	JMP	CONOUT
	JMP	LIST
	JMP	PUNCH
	JMP	READER
	JMP	HOME	
	JMP	SELDSK		
	JMP	SETTRK
	JMP	SETSEC
	JMP	SETDMA
	JMP	READ
	JMP	WRITE
	JMP	LISTAT
	JMP	SECTRAN
;
BOOTDRV:DB	BOOTSPT		;BOOT DRIVE INDICATOR
STEPRAT:DB	03H		;STEP RATE, 0 = FASTEST, 03H = SLOWEST
;
;	CP/M 2.2 DISK CONTROL BLOCKS
;
DPH0:	DW	SD8TRAN		;ADDR OF SECTOR TRANSLATE TABLE
	DW	0		;SCRATCHPAD VALUE
	DW	0
	DW	0
	DW	DIRBUF		;DIRECTORY OPERATION BUFFER
	DW	SD8PBLK		;DISK PARAMETER BLOCK ADDRESS
	DW	CKSMBK0		;DIRECTORY CHECKSUM VECTOR
	DW	ALOC0		;FREE SPACE MAP
;
DPH1:	DW	SD8TRAN		;ADDR OF SECTOR TRANSLATE TABLE
	DW	0		;SCRATCHPAD VALUE
	DW	0
	DW	0
	DW	DIRBUF		;DIRECTORY OPERATION BUFFER
	DW	SD8PBLK		;DISK PARAMETER BLOCK ADDRESS
	DW	CKSMBK1		;DIRECTORY CHECKSUM VECTOR
	DW	ALOC1		;FREE SPACE MAP
;
DPH2:	DW	SD5TRAN		;ADDR OF SECTOR TRANSLATE TABLE
	DW	0		;SCRATCHPAD VALUE
	DW	0
	DW	0
	DW	DIRBUF		;DIRECTORY OPERATION BUFFER
	DW	SD5PBLK		;DISK PARAMETER BLOCK ADDRESS
	DW	CKSMBK2		;DIRECTORY CHECKSUM VECTOR
	DW	ALOC2		;FREE SPACE MAP
;
DPH3:	DW	SD5TRAN		;ADDR OF SECTOR TRANSLATE TABLE
	DW	0		;SCRATCHPAD VALUE
	DW	0
	DW	0
	DW	DIRBUF		;DIRECTORY OPERATION BUFFER
	DW	SD5PBLK		;DISK PARAMETER BLOCK ADDRESS
	DW	CKSMBK3		;DIRECTORY CHECKSUM VECTOR
	DW	ALOC3		;FREE SPACE MAP
;
;	disk parameter block, common to all disks
;	this implements a "standard" CP/M directory
;	with 64 entries, and 1K blocks.
;
;	The 5" format appears to be 18 sectors of 128 bytes each
;	40 tracks single sided total, 3 reserved, net 37 tracks, 83k per disk,
;
SD8PBLK:DW	26		;SECTORS PER TRACK
BSH:	DB	3		;BLOCK SHIFT FACTOR (2**3 = 8 RCDS PER CLUSTER)
BLM:	DB	7		;BLOCK MASK (RIGHTMOST BSH BITS SET)
EXM:	DB	0		;EXTENT MASK
DSM:	DW	242		;243 1K CLUSTERS PER DISK
DRM:	DW	63		;64 DIRECTORY ENTRIES PER DISK
AL0:	DW	00C0H		;INITIAL FREE SPACE MAP, 2 (DIR) BLKS IN USE
CKS:	DW	16		;CHECK 16 (ALL) DIRECTORY SECTORS
OFF:	DW	2		;RESERVE TWO TRACKS FOR THE SYSTEM
;
SD5PBLK:DW	18		;SECTORS PER TRACK
	DB	3		;BLOCK SHIFT FACTOR (2**3 = 8 RCDS PER CLUSTER)
	DB	7		;BLOCK MASK (RIGHTMOST BSH BITS SET)
	DB	0		;EXTENT MASK
	DW	82		;243 1K CLUSTERS PER DISK
	DW	63		;64 DIRECTORY ENTRIES PER DISK
	DW	00C0H		;INITIAL FREE SPACE MAP, 2 (DIR) BLKS IN USE
	DW	16		;CHECK 16 (ALL) DIRECTORY SECTORS
	DW	3		;RESERVE TWO TRACKS FOR THE SYSTEM
;
; SECTOR SKEW TABLES
;
SD8TRAN:DB	1,7,13,19,25,5,11,17,23,3,9,15,21
	DB	2,8,14,20,26,6,12,18,24,4,10,16,22
;
SD5TRAN:DB	1,6,11,16,3,8,13,18,5
	DB	10,15,2,7,12,17,4,9,14
;
SIGNON:DB	0DH,0AH,0AH
	DB	MEMTENS+30H
	DB	MEMONES+30H
	DB	'k CP/M version 2.2'
	DB	0DH,0AH,0
;
SELDSK:	LXI	H,0
	MOV	A,C		;C CONTAINS REQUESTED DRIVE NO.
	CPI	4		;THIS BIOS ONLY SUPPORTS 4 DRIVES
	RNC			;IGNORE IF TOO HIGH
	STA	NEWDSK
	MOV	L,C		;L=disk number 0,1,2,3
	DAD	H		;*2
	DAD	H		;*4
	DAD	H		;*8
	DAD	H		;*16 (size of each header)
	LXI	D,DPH0
	DAD	D		;HL=.dpbase(diskno*16)
	RET	
;
;TRANSLATE SECTOR IN C USING TABLE AT DE
;
SECTRAN:MVI	B,0
	XCHG			;TABLE ADDR TO HL
	DAD	B		;GET ADDRESS
	MOV	L,M		;GET BYTE
	MVI	H,0		;ANSWER IN HL
	RET
;
SETSEC:	MOV	A,C		;JUST SAVE SECTOR NUMBER
	STA	SECT
	RET
;
SETDMA:	PUSH	H
	MOV	L,C
	MOV	H,B
	SHLD	DMAADD
	POP	H
	RET
;
;	ERROR CHECKING READ AND WRITE ROUTINES FOR
;	CROMEMCO CBIOS
;
READ:	XRA	A
	STA	ERCNT
RDRETRY:CALL	RD4FDC		;READ SECTOR
	RZ			;SUCCESSFUL READ, DONE
	CALL	ERROR		;INCREMENT RTRYCNT
	JNZ	RDRETRY		;RETRY 10 TIMES
	ORI	01H		;CP/M CONVENTION FOR PERMANENT ERROR
	RET	
;
WRITE:	XRA	A
	STA	ERCNT
WRRETRY:CALL	WR4FDC		;WRITE SECTOR
	RZ			;SUCCESSFUL WRITE, DONE
	CALL	ERROR		;INCREMENT RTRYCNT
	JNZ	WRRETRY		;RETRY 10 TIMES
	ORI	01H		;CP/M CONVENTION FOR PERMANENT ERROR
	RET	
;
ERROR:	PUSH	H
	ANI	10H		;CHECK FOR RNF
	JNZ	TRKERR	
	LXI	H,ERCNT
	INR	M		;INCREMENT RTRYCNT
	MOV	A,M
	POP	H
	SUI	RTCNT		;REACHED RETRY LIMIT ?
	RET	
;
TRKERR:	LXI	H,ERCNT
	INR	M		;INCREMENT NO OF TRACK ERRORS
	MOV	A,M
	SUI	RTCNT		;ALLOW ONLY 10 TRACK ERRORS
	POP	H
	RZ			;IF >RTCNT, RETURN A FAILURE
	PUSH	B
	LDA	TRK
	PUSH	PSW
	CALL	HOME		;HOME THE HEAD
	POP	PSW
	STA	TRK
	MOV	C,A		;GET TRACK IN C
	CALL	SEEK		;RESEEK TO CORRECT TRACK
	POP	B
	ORI	0FFH		;RETRY
	RET	
;
;	RESTORE THE DISK TO TRACK ZERO
;
HOME:	SUB	A		;ZERO OUT TRACK COUNTER
	STA	TRK
	CALL	DSKSEL		;NOW SELECT THE DISK
	OUT	FDCFLAG
	LDA	STEPRAT		;GET STEPPING RATE
	ORI	HEADLD+VERIFY	;ADD IN HEAD LOAD & VERIFY FLAG
	OUT	FDCSTAT
RSTI:	IN	FDCFLAG		;NOW CHECK STATUS
	RAR
	JNC	RSTI		;LOOP BACK UNTIL DONE
	JMP	SEEKTST
;
;	HERE, ACTUALLY DO THE READ OPERATION
;
RD4FDC:	PUSH	B
	PUSH	H		;FIRST, SAVE REGS
	PUSH	D
	CALL	SEEK
	MVI	E,88H		;READ COMMAND (VALID FOR 1771, 179X)
	CALL	INIT4FDC
RDI1:	IN	FDCDATA		;AUTO WAIT INPUT COMMAND
 	MOV	M,A
	INX	H
	DCR	B
	JNZ	RDI1		;READ ANOTHER BYTE INTO CORE UNTIL DONE
RDI2:	IN	FDCFLAG		;CHECK FLAGS
	RAR
	JNC	RDI2		;LOOP UNTIL READY
RDI3:	IN	FDCSTAT		;NOW CHECK STATUS
	ANI	9CH
RDWREND:EI
	POP	D		;RESTORE REGS
	POP	H
	POP	B
	RET
;
;	ACTUALLY DO WRITE OPERATION
;
WR4FDC:	PUSH	B
	PUSH	H		;SAVE REGS
	PUSH	D
	CALL	SEEK
	MVI	E,0A8H		;WRITE COMMAND (VALID FOR 1771, 179X)
	CALL	INIT4FDC
WRI1:	IN	FDCFLAG		;CHECK FLAGS
	RAR
	JC	WRI3		;IF PREMATURELY DONE, STOP
WRI1A:	MOV	A,M
	OUT	FDCDATA
	INX	H
	DCR	B
	JNZ	WRI1A		;WRITE DATA FROM MEMORY TIL DONE
WRI2:	IN	FDCFLAG		;CHECK FLAGS
	RAR
	JNC	WRI2		;LOOP TIL DONE WITH WHOLE OPERATION
WRI3:	IN	FDCSTAT		;NOW CHECK ERROR STATUS
	ANI	0FCH
	JMP	RDWREND
;
;	SET THE TRACK, AND MOVE DISK ARM THERE
;
SETTRK:	MOV	A,C
	STA	TRK		;STORE THE TRACK NUMBER
	RET
;
; PHYSICAL SEEK ROUTINE
;
SEEK:	SUB	A		;NO AUTO WAIT
	CALL	DSKSEL		;NOW SELECT THE DISK
	OUT	FDCFLAG		;SELECT THE DRIVE
	LDA	TRK
	MOV	C,A
	OUT	FDCDATA		;TELL 1771 ABOUT TRACK WANTED
	LDA	SECT
	OUT	FDCSECT		;TELL IT ABOUT SECTOR WANTED
	PUSH	H
	PUSH	D
	LXI	H,TRKTBL	;NOW, SEE WHERE DISK ARM IS NOW
	LDA	NEWDSK
	MOV	E,A		;LOOK UP IN TABLE
	MVI	D,0
	DAD	D		;GET BYTE
	MOV	A,M
	OUT	FDCTRK		;TELL 1771 WHERE ARM IS NOW
	SUB	C
	POP	D		;NOW CAN RESTORE THE REGS
	POP	H
	RZ			;IF ALREADY AT THAT TRACK, QUIT
	LDA	STEPRAT		;GETT
	MOV	B,A		;SAVE THE NEW VALUE
	LDA	NEWDSK		;GET DISK
	CMA			;COMPLIMENT
	ANI	02H		;ACC = 02H IF 8"
	RLC
	RLC
	RLC			;"MAXI" BIT IS SET
	ORI	20H		;SET MOTOR ON BIT
	ORA	B		;ADD IN DRIVE SELECT
	ORA	C		;OR IN AUTO WAIT
	POP	B
	RET
;
;	GETS CONTROL ON A WARM START
;
WBOOT:	MVI	A,01H		;FIRST, RESTORE DEFAULT BANKING
	OUT	BANKSEL
;
	LXI	SP,STACK
	LDA	NEWDSK
	STA	CURRDRIVE	;STORE SELECTED DRIVE
;
STARTBOOT:
	MVI	C,0		;ASSUME DRIVE A:
	LDA	BOOTDRV		;SEE IF 8"
	CPI	26
	JZ	SB1
	MVI	C,2		;BOOT DRIVE IS DRIVE C:, 5"
SB1:	CALL	SELDSK		;ASSUME DRIVE A TO REBOOT
	CALL	HOME
	LXI	H,CCP-128	;WILL INCREMENT BY 128 LATER
	SHLD	DMAADD
	LXI	B,44*256+1	;SECTOR COUNT, FIRST SECTOR-1
RDSEC:	LDA	BOOTDRV		;GET SECTORS/TRACK
	CMP	C		;SAME AS SECTOR NUMBER
	MOV	A,C		;C IS SECTOR NUMBER
	JZ	NXTTRK		;TIME TO BUMP TRACK
	LXI	D,128		;INCREMENT DMA ADDRESS
	LHLD	DMAADD
	DAD	D
	SHLD	DMAADD		;STORE DMA ADDRESS
	INR	C		;INCREMENT SECTOR NUMBER
	CALL	SETSEC
	CALL	READ		;READ THE DATA
	JNZ	WBOOT		;ONT
	MOV	B,A		;SAVE THE NEW VALUE
	LDA	NEWDSK		;GET DISK
	CMA			;COMPLIMENT
	ANI	02H		;ACC = 02H IF 8"
	RLC
	RLC
	RLC			;"MAXI" BIT IS SET
	ORI	20H		;SET MOTOR ON BIT
	ORA	B		;ADD IN DRIVE SELECT
	ORA	C		;OR IN AUTO WAIT
	POP	B
	RET
;
;	GETS CONTROL ON A WARM START
;
WBOOT:	MVI	A,01H		;FIRST, RESTORE DEFAULT BANKING
	OUT	BANKSEL
;
	LXI	SP,STACK
	LDA	NEWDSK
	STA	CURRDRIVE	;STORE SELECTED DRIVE
;
STARTBOOT:
	MVI	C,0		;ASSUME DRIVE A:
	LDA	BOOTDRV		;SEE IF 8"
	CPI	26
	JZ	SB1
	MVI	C,2		;BOOT DRIVE IS DRIVE C:, 5"
SB1:	CALL	SELDSK		;ASSUME DRIVE A TO REBOOT
	CALL	HOME
	LXI	H,CCP-128	;WILL INCREMENT BY 128 LATER
	SHLD	DMAADD
	LXI	B,44*256+1	;SECTOR COUNT, FIRST SECTOR-1
RDSEC:	LDA	BOOTDRV		;GET SECTORS/TRACK
	CMP	C		;SAME AS SECTOR NUMBER
	MOV	A,C		;C IS SECTOR NUMBER
	JZ	NXTTRK		;TIME TO BUMP TRACK
	LXI	D,128		;INCREMENT DMA ADDRESS
	LHLD	DMAADD
	DAD	D
	SHLD	DMAADD		;STORE DMA ADDRESS
	INR	C		;INCREMENT SECTOR NUMBER
	CALL	SETSEC
	CALL	READ		;READ THE DATA
	JNZ	WBOOT		;ONT
	MOV	B,A		;SAVE THE NEW VALUE
	LDA	NEWDSK		;GET DISK
	CMA			;COMPLIMENT
	ANI	02H		;ACC = 02H IF 8"
	RLC
	RLC
	RLC			;"MAXI" BIT IS SET
	ORI	20H		;SET MOTOR ON BIT
	ORA	B		;ADD IN DRIVE SELECT
	ORA	C		;OR IN AUTO WAIT
	POP	B
	RET
;
;	GETS CONTROL ON A WARM START
;
WBOOT:	MVI	A,01H		;FIRST, RESTORE DEFAULT BANKING
	OUT	BANKSEL
;
	LXI	SP,STACK
	LDA	NEWDSK
	STA	CURRDRIVE	;STORE SELECTED DRIVE
;
STARTBOOT:
	MVI	C,0		;ASSUME DRIVE A:
	LDA	BOOTDRV		;SEE IF 8"
	CPI	26
	JZ	SB1
	MVI	C,2		;BOOT DRIVE IS DRIVE C:, 5"
SB1:	CALL	SELDSK		;ASSUME DRIVE A TO REBOOT
	CALL	HOME
	LXI	H,CCP-128	;WILL INCREMENT BY 128 LATER
	SHLD	DMAADD
	LXI	B,44*256+1	;SECTOR COUNT, FIRST SECTOR-1
RDSEC:	LDA	BOOTDRV		;GET SECTORS/TRACK
	CMP	C		;SAME AS SECTOR NUMBER
	MOV	A,C		;C IS SECTOR NUMBER
	JZ	NXTTRK		;TIME TO BUMP TRACK
	LXI	D,128		;INCREMENT DMA ADDRESS
	LHLD	DMAADD
	DAD	D
	SHLD	DMAADD		;STORE DMA ADDRESS
	INR	C		;INCREMENT SECTOR NUMBER
	CALL	SETSEC
	CALL	READ		;READ THE DATA
	JNZ	WBOOT		;ON READ FAILURE TRY AGAIN
	DCR	B
	JNZ	RDSEC
	JMP	BOOT		;READ CCP AND BDOS;
;
NXTTRK:	MVI	C,1		;ASSUME MAX TRACK READ IS 1 (8")
	LDA	BOOTDRV		;GET BOOT DRIVE SECT/TRK
	CPI	26		;IS IT 26 (8") ?
	JZ	NXTK1		;IS 8"
	INR	C		;MAX TRACK TO READ IS 2 (0, 1, 2)
NXTK1:	LDA	TRK
	CMP	C
	JZ	BOOT		;HAVE READ ALL BOOT TRACKS
	MOV	C,A
	INR	C		;SEEK NEXT TRACK IF NOT
	CALL	SETTRK
	MVI	C,0
	JMP	RDSEC
;
;AFTER COLD BOOT
;
CBOOT:	LXI	SP,STACK	;INITIALIZE STACK FOR ROUTINE
	LXI	H,SIGNON
	CALL	PRMSG		;PRINT MESSAGE
	LDA	BOOTDRV		;SEE IF BOOTING FROM 8" OR 5"
	CPI	26		;8" ?
	MVI	A,0		;ASSUME 8"
	JZ	BOOT		;WAS DRIVE 0, 8"
	MVI	A,2		;WAS 5" DRIVE
	STA	CURRDRIVE
;
;GETS CONTROL AFTER COLD OR WARM BOOT
;
BOOT:	DI	
	MVI	A,0C3H		;SET UP PARAMETERS ON PAGE 0
	STA	0
	LXI	H,BIOS+3
	SHLD	1
	STA	5
	LXI	H,BDOS+6
	SHLD	6
;
;		CROMEMCO INITIALIZATION HERE (READER, LIST NOT NEEDED)
;		NOTE .. THE CONSOLE TUART IS INITIALIZED BY RDOS
;
	IF	ADDLIO = 1
	MVI	A,BAUDRATE
	OUT	PBAUDPORT
	ENDIF
;
	IF	SERIAL  DATA REGISTER ACCESS
	OUT	SLCTRL	
	MVI	A,0H		;DISABLE INTERRUPT
	OUT	SINTEN	
	OUT	SLSTAT		;RESET ERROR FLAGS
	RET
;
; Get Serial Printer Output Status
; Upon Exit:	A = -1 (FFH) and Z-flag is reset if ready for char.
;		A = 0 and Z-flag is set if not ready for character
;
L2RDY:	IN	SSTATP		;GET LIST-OUT STATUS
	ANI	STBE		;CHECK PRINTER TBE FLAG
	RZ			;PRINTER NOT READY FOR CHARACTER
	MVI	A,-1		;PRINTER READY FOR CHARACTER
	RET
;
; Serial Printer Output Routine
; Upon Entry:	A contains the character to be output
;
L2OUT:	PUSH	PSW		;SAVE CHARACTER FOR A MOMENT
L2OT30:	CALL	L2RDY		;GET LIST-OUT STATUS
	JZ	L2OT30		;ZERO MEANS PRINTER BUSY
	POP	PSW		;RESTORE CHARACTER
	OUT	SDATA		;OUTPUT THE CHARACTER
	RET
;
; ROUTINE TO ADD NULLS AFTER LF
;
;
;	CPI	0AH		;CHECK FOR END OF LINE
;	RNZ			;RETURN IF NOT LINE FEED CHARACTER
;	MVI	A,NULLS+1	;IF LF, GET NUMBER OF NULLS
;L2RTN:	DCR	A		;CHECK FOR 0 NULLS AT TOP OF LOOP
;	RZ			;RETURN IF ALL NULLS OUTPUT
;	PUSH	PSW		;SAVE NULLS COUNTER
;	 DATA REGISTER ACCESS
	OUT	SLCTRL	
	MVI	A,0H		;DISABLE INTERRUPT
	OUT	SINTEN	
	OUT	SLSTAT		;RESET ERROR FLAGS
	RET
;
; Get Serial Printer Output Status
; Upon Exit:	A = -1 (FFH) and Z-flag is reset if ready for char.
;		A = 0 and Z-flag is set if not ready for character
;
L2RDY:	IN	SSTATP		;GET LIST-OUT STATUS
	ANI	STBE		;CHECK PRINTER TBE FLAG
	RZ			;PRINTER NOT READY FOR CHARACTER
	MVI	A,-1		;PRINTER READY FOR CHARACTER
	RET
;
; Serial Printer Output Routine
; Upon Entry:	A contains the character to be output
;
L2OUT:	PUSH	PSW		;SAVE CHARACTER FOR A MOMENT
L2OT30:	CALL	L2RDY		;GET LIST-OUT STATUS
	JZ	L2OT30		;ZERO MEANS PRINTER BUSY
	POP	PSW		;RESTORE CHARACTER
	OUT	SDATA		;OUTPUT THE CHARACTER
	RET
;
; ROUTINE TO ADD NULLS AFTER LF
;
;
;	CPI	0AH		;CHECK FOR END OF LINE
;	RNZ			;RETURN IF NOT LINE FEED CHARACTER
;	MVI	A,NULLS+1	;IF LF, GET NUMBER OF NULLS
;L2RTN:	DCR	A		;CHECK FOR 0 NULLS AT TOP OF LOOP
;	RZ			;RETURN IF ALL NULLS OUTPUT
;	PUSH	PSW		;SAVE NULLS COUNTER
;	 DATA REGISTER ACCESS
	OUT	SLCTRL	
	MVI	A,0H		;DISABLE INTERRUPT
	OUT	SINTEN	
	OUT	SLSTAT		;RESET ERROR FLAGS
	RET
;
; Get Serial Printer Output Status
; Upon Exit:	A = -1 (FFH) and Z-flag is reset if ready for char.
;		A = 0 and Z-flag is set if not ready for character
;
L2RDY:	IN	SSTATP		;GET LIST-OUT STATUS
	ANI	STBE		;CHECK PRINTER TBE FLAG
	RZ			;PRINTER NOT READY FOR CHARACTER
	MVI	A,-1		;PRINTER READY FOR CHARACTER
	RET
;
; Serial Printer Output Routine
; Upon Entry:	A contains the character to be output
;
L2OUT:	PUSH	PSW		;SAVE CHARACTER FOR A MOMENT
L2OT30:	CALL	L2RDY		;GET LIST-OUT STATUS
	JZ	L2OT30		;ZERO MEANS PRINTER BUSY
	POP	PSW		;RESTORE CHARACTER
	OUT	SDATA		;OUTPUT THE CHARACTER
	RET
;
; ROUTINE TO ADD NULLS AFTER LF
;
;
;	CPI	0AH		;CHECK FOR END OF LINE
;	RNZ			;RETURN IF NOT LINE FEED CHARACTER
;	MVI	A,NULLS+1	;IF LF, GET NUMBER OF NULLS
;L2RTN:	DCR	A		;CHECK FOR 0 NULLS AT TOP OF LOOP
;	RZ			;RETURN IF ALL NULLS OUTPUT
;	PUSH	PSW		;SAVE NULLS COUNTER
;	SUB	A		;PRINT A SINGLE NULL
;	CALL	L2OUT		;	CHARACTER (RECURSIVE)
;	POP	PSW		;RESTORE NULLS COUNTER
;	JMP	L2RTN		;LOOP TO PRINT NEXT NULL
;
CURRDRIVE:
	DB	0		;THE SAVE AREA FOR THE DEFAULT DRIVE
NEWDSK:	DB	0		;DISK DRIVE FOR NEXT I/O
;
; TRACK TABLE FOR 4 DRIVES
;
TRKTBL:	DB	0		;FOUR DRIVES
	DB	0
	DB	0
	DB	0
;
SECT:	DB	0		;SECTOR NUMBER
TRK:	DB	0		;TRACK NUMBER FROM SETTRK
DMAADD:	DW	0		;DMA ADDRESS
ERCNT:	DB	0		;NUMBER OF ERRORS
;
;	FROM HERE ON, THE AREAS ARE INITIALIZED BY CP/M AS NEEDED
;
DIRBUF:	DS	128		;SAVE AREA FOR DISK DIRECTORY OPERATIONS
;
;
ALOC0:	DS	32
ALOC1:	DS	32
ALOC2:	DS	32
ALOC3:	DS	32
;
CKSMBK0:DS	16
CKSMBK1:DS	16
CKSMBK2:DS	16
CKSMBK3:DS	16
;
; Note:  The last assembled byte of this module MUST NOT be a Define
; Storage (DS or DEFS) pseudo-op to assure proper operation with CDOSGEN
;
	END
