;-----------------------------------------------;
;						;
;	    CP/M 8080 UTILITY PACKAGE		;
;						;
;-----------------------------------------------;
;
;REV 0	12-JULY-77	MGL
;
;REV 1	12-SEPT-80	Keith Petersen, W8SDZ
;	(to clean up format of file)
;
;JUMP TABLE
;
	ORG	103H	;FOR CP/M LOAD VIA DDT
	JMP	WLINE	;WRITE LINE ON LIST DEVICE
	JMP	WMSG	;WRITE LINE ON CONSOLE DEVICE
	JMP	DSKSEL	;SELECT DISK
	JMP	OPNFIL	;OPEN FILE
	JMP	CLSFIL	;CLOSE FILE
	JMP	DELFIL	;DELETE FILE
	JMP	DREAD	;DISK READ (USING CP/M)
	JMP	DWRITE	;DISK WRITE(USING CP/M)
	JMP	CREFIL	;CREATE FILE
	JMP	DMASET	;SET DMA ADDRESS
	JMP	MOVE	;MOVE BYTES
	JMP	CMPCHR	;COMPARE BYTES  
	JMP	CMPHD	;COMPARE HL : DE
	JMP	MUL16	;HL <= HL * DE (16 BITS ONLY)
	JMP	GNB	;GET NEXT BYTE (1K BUFFERING) (USING FCB1)
	JMP	WNB	;WRITE NEXT BYTE (USING FCB1)
	JMP	GNB2	;GET NEXT BYTE (USING FCB2)
	JMP	WNB2	;WRITE NEXT BYTE (USING FCB2)
	JMP	CNV2HX	;CONVERT A REG TO HEX IN BUFFER (HL)
;-----------------------------------------------;
;						;
;	     COMMUNICATIONS AREA		;
;						;
;-----------------------------------------------;
;
FCB1	DB	0	;FILE CONTROL BLOCK #1
	DS	32	;REMAINING AREA
FCB2	DB	0	;FILE CONTROL BLOCK #2
	DS	32
IBP	DS	2	;INPUT BUFFER POINTER (FCB1)
IBP2	DS	1	;INPUT BUFFER POINTER (FCB2)
OBP	DS	1	;OUTPUT BUFFER POINTER (FCB1)
OBP2	DS	1	;OUTPUT BUFFER POINTER (FCB2)
IBUF	DW	INBUF	;INPUT BUFFER ADDRESS
OBUF	DW	OUTBUF	;OUTPUT BUFFER ADDRESS
IBUF2	DW	INBUF2	;INPUT BUFFER ADDRESS (FCB2)
OBUF2	DW	OUTBF2	;OUTPUT BUFFER ADDRESS (FCB2)
INBUF	DS	1024	;1K BUFFER FOR GNB (TO SPEED UP INPUT STREAM)
OUTBUF	DS	128	;I/O BUFFERS
INBUF2	DS	128
OUTBF2	DS	128
;
;CP/M EQUATES
;
BDOS	EQU	5
BOOT	EQU	0
;
;
;ENTRY - USED TO CALL	BDOS - SAVES AND RESTORES REGISTERS
;
ENTRY	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
;WLINE - WRITE LINE TO LIST DEVICE
;HL -> BUFFER, TERM = 0AH
;
WLINE	MOV	A,M
	MOV	E,A
	MVI	C,5
	CALL	ENTRY
	MOV	A,M
	CPI	0AH
	RZ
	INX	H
	JMP	WLINE
;
;WMSG - WRITE MESSAGE TO CONSOLE
;
;DE -> MSG, TERM-'$'
;
WMSG	MVI	C,9
	CALL	ENTRY
	RET
;
;DSKSEL - SELECT DISK
;DRIVE NUMBER IN A REG
;
DSKSEL	MOV	E,A
	MVI	C,14
	CALL	ENTRY
	RET
;
;OPNFIL - OPEN FILE CONTROL BLOCK
;REEL # AND NR ARE SET TO 00H
;DE -> FCB
;Z=0 SUCCESS, Z=1 FAILURE
;
OPNFIL	PUSH	H
	LXI	H,12
	DAD	D
	MVI	M,0	;ZERO REEL #
	MVI	C,15
	PUSH	D
	CALL	ENTRY
	POP	D
	CPI	255
	POP	H
	RZ
	PUSH	H
	LXI	H,32
	DAD	D
	MVI	M,0	; ZERO NR
	POP	H
	RET
;
;CLSFIL - CLOSE FILE CONTROL BLOCK
;DE -> FCB
;Z=1 ERROR, Z=0 SUCCESS
;
CLSFIL	MVI	C,16
	CALL	ENTRY 
	CPI	255
	RET
;
;DELFIL - DELETE FILE
;DE -> FCB
;Z=1 ERROR, Z=0 SUCCESS
;
DELFIL	MVI	C,19
	CALL	ENTRY
	CPI	255
	RET
;
;DREAD - READ DISK SECTOR
;DE -> FCB
;Z=0 ERROR OR EOF, Z=1 NORMAL
;
DREAD	MVI	C,20
	CALL	ENTRY
	CPI	0
	RET
;
;DWRITE - WRITE DISK SECTOR
;DE -> FCB
;Z=0 ERROR, Z=1 NORMAL
;
DWRITE	MVI	C,21
	CALL	ENTRY
	CPI	0
	RET
;
;CREFIL - CREATE FILE
;
;REEL # ASSUMMED TO BE SET
;
;DE -> FCB
;Z=0 NORMAL, Z=1 ERROR
;
CREFIL	MVI	C,22
	CALL	ENTRY
	CPI	255
	RET
;
;DMASET - SET DMA ADDRESS
;
;BUFFER ADDRESS IN DE
;
DMASET	MVI	C,26
	CALL	ENTRY
	RET
;
;MOVE (HL) <= (DE) LEN IN BC
;
MOVE	XCHG
;
MOVLOP	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVLOP
	XCHG		;PUT REGS BACK FOR CALLING ROUTINES SAKE
	RET
;
;CMPCHR - COMPARE STRINGS (HL) : (DE) LEN IN B
;
CMPCHR	PUSH	H
	PUSH	D
	PUSH	B	;SAVE REGS
	LDAX	D
	CMP	M
	JNZ	CMPCH1
	INX	H
	INX	D
	DCR	B
	JNZ	CMPCHR+3
;
CMPCH1	POP	B
	POP	D
	POP	H	;RESTORE REGS
	RET
;
;MUL16 - HL <= HL * DE (16 BITS ONLY)
;
MUL16	PUSH	B
	PUSH	D
	POP	B
	PUSH	D
	XCHG
	LXI	H,0
;
MUL16A	MOV	A,C
	ORA	B
	JNZ	MUL16B
	POP	D
	POP	B
	RET
;
MUL16B	DAD	D
	DCX	B
	JMP	MUL16A
;
;CMPHD - COMPARE HL:DE
;
CMPHD	MOV	A,H
	CMP	D
	RNZ
	MOV	A,L
	CMP	E
	RET
;
;GNB - GET NEXT BYTE (FCB1)
;
GNB	PUSH	H
	PUSH	D
	LHLD	IBP
	LXI	D,INBUF+1024
	CALL	CMPHD	;SEE IF END OF BUFFER
	POP	D
	POP	H
	JNZ	GNB0	;BRANCH IF NOT AT END OF BUFFER
	PUSH	H
	PUSH	D
	PUSH	B	;GET 1K BLOCK FROM DISK
	LXI	H,INBUF
	SHLD	GNBPTR	;SET UP POINTER FOR DMASET
	MVI	B,8	;NUMBER OF 128 BYTE SECTORS IN 1K BUFFER
;
GNB0A	PUSH	B
	LHLD	GNBPTR
	XCHG
	CALL	DMASET	;SET UP DMA ADDRESS
	LXI	D,FCB1
	CALL	DREAD	;GO READ A SECTOR
	LHLD	GNBPTR
	LXI	D,128
	DAD	D
	SHLD	GNBPTR	;UPDATE POINTER
	POP	B
	DCR	B
	JNZ	GNB0A	;BRANCH BACK IF MORE TO DO
	POP	B
	POP	D	;RESTORE REGS
	LXI	H,INBUF
	SHLD	IBP
	POP	H	;SET UP NEXT DATA POINTER
;
GNB0	PUSH	H
	LHLD	IBP
	MOV	A,M
	INX	H
	SHLD	IBP
	POP	H	;GET BYTE
	RET
;
GNBPTR	DS	2	;TEMP POINTER FOR BUFFERING
;
;GNB2 - GET NEXT BYTE (FCB2)
;
GNB2	PUSH	D 
	LDA	IBP2
	CPI	80H
	JNZ	GNB20
	PUSH	H
	PUSH	B
	LXI	D,INBUF2
	CALL	DMASET
	LXI	D,FCB2
	CALL	DREAD
	POP	B
	POP	H
	XRA	A
;
GNB20	MOV	E,A
	MVI	D,0
	INR	A
	STA	IBP2
	PUSH	H
	LXI	H,INBUF
	DAD	D
	MOV	A,M
	POP	H
	POP	D
	RET
;
;WNB - WRITE NEXT BYTE (FCB1)
;BYTE IN A REG
;
WNB	PUSH	H
	PUSH	D
	PUSH	PSW
	LDA	OBP
	CPI	80H
	JNZ	WNB0
	LXI	D,OUTBUF
	CALL	DMASET
	LXI	D,FCB1
	CALL	DWRITE
	JZ	WNB00	;BRANCH IF OK
	LXI	D,WNBERR
	CALL	WMSG
	JMP	BOOT
;
WNB00	XRA	A
;
WNB0	MOV	E,A
	MVI	D,0
	INR	A
	STA	OBP  
	LXI	H,OUTBUF
	DAD	D
	POP	PSW
	MOV	M,A
	POP	D
	POP	H
	RET
;
WNBERR	DB	13,10,'OUTPUT FILE WRITE ERROR '
	DB	'(DISK MAY BE FULL)',13,10,'$'
;
;WNB2 - WRITE NEXT BYTE (FCB2)
;
WNB2	PUSH	H
	PUSH	D
	PUSH	PSW
	LDA	OBP2
	CPI	80H
	JNZ	WNB20
	LXI	D,OUTBF2
	CALL	DMASET
	LXI	D,FCB2
	CALL	DWRITE
	JZ	WNB200	;BRANCH IF ALL OK
	LXI	D,WNBERR
	CALL	WMSG
	JMP	BOOT
;
WNB200	XRA	A
;
WNB20	MOV	E,A
	MVI	D,0
	INR	A
	STA	OBP2
	LXI	H,OUTBF2
	DAD	D
	POP	PSW
	MOV	M,A 
	POP	D
	POP	H
	RET
;
;CNV2HX - CONVERT CONTENTS OF A REG TO HEX CHARACTERS
;AND PLACE IN BUFFER POINTED TO BY HL
;
CNV2HX	PUSH	B
	MOV	B,A 
	RRC
	RRC
	RRC
	RRC
	ANI	0FH
	CALL	CNV2H
	MOV	A,B
	POP	B
	ANI	0FH
;
CNV2H	CPI	0AH
	JC	CNV2H1
	ADI	7
;
CNV2H1	ADI	'0'
	MOV	M,A
	INX	H
	RET
;
;END OF FILE CPMUTIL.ASM
;
