;********************************;
;   LOGICAL I/O SYSTEM FOR CP/M  ;
;********************************;
 
;********************************;
;   MISCELLANEOUS EQUATES        ;
;********************************;
 
BOOT	EQU	0000H	;REBOOT ENTRY POINT
CPM	EQU	0005H	;CPM ENTRY POINT

TBUF	EQU	0080H	;TRANS. BUFFER
TFCB	EQU	005CH	;TRANS. FCB

SDISK	EQU	14	;SET DISK FUNCT. CODE
OPEN	EQU	15	;OPEN FUNCTION CODE
CLOSE	EQU	16	;CLOSE FUNCTION CODE
DELET	EQU	19	;DELETE FUNCTION CODE
READ	EQU	20	;READ FUNCTION CODE
WRITE	EQU	21	;WRITE FUNCTION CODE
CREAT	EQU	22	;CREATE FUNCTION CODE
RENAM	EQU	23	;RENAME FUNCTION CODE

;********************************;
;          JUMP VECTORS          ;
;********************************;

	ORG	1000H
	JMP	FFCB	;FILL FCB
	JMP	FMAKE	;FILE CREATE
	JMP	FOPEN	;FILE OPEN
	JMP	FCLOS	;FILE CLOSE
	JMP	FDELE	;DELETE FILE
	JMP	OUTBT	;BYTE OUTPUT
	JMP	GETBT	;BYTE INPUT

;********************************;
;           F F C B              ;
; ROUTINE TO FILL IN ID FIELDS   ;
;            OF FCB              ;
;                                ;
; INPUTS:    HL = A(FCB)         ;
;            DE = A(ID STRING)   ;
; OUTPUTS:   CARRY = ERROR       ;
;********************************;

FFCB:	MVI	M,00	;CLEAR FIRST BYTE OF FCB
	INX	H	;SKIP BYTE
	PUSH	H	;SAVE FCB NAME ADDRESS
	MVI	C,8+3	;SIZE OF ID FIELD
	MVI	A,' '	;SPACE
FFCB0:	MOV	M,A	;CLEAR ID FIELD TO SPACES
	INX	H
	DCR	C
	JNZ	FFCB0
	POP	H	;GET ID FIELD ADDR.
	MVI	C,8	;MAZ SIZE OF NAME
FFCB1:	LDAX	D	;GET ID BYTES
	CPI	' '	;LEADING SPACES?
	JNZ	FFCB2	;NO, CONTINUE
	INX	D	;SKIP LEADING SPACES
	JMP	FFCB1
FFCB2:	LDAX	D	;GET ID BYTE
	CPI	0DH	;CR?
	RZ		;YES, DONE
	CPI	' '	;IMBEDDED SPACE?
	RZ		;YES, DONE
	CPI	'.'	;NAME.TYP SEPARATOR?
	JZ	FFCB3	;YES, PROCESS TYPE
	MOV	M,A	;STORE NAME BYTE
	INX	D
	INX	H	;BUMP POINTERS
	DCR	C	;DECREMENT MAX COUNT
	JNZ	FFCB2	;LOOP
	JMP	FFCBE	;ERROR, NAME TOO BIG

FFCB3:	INX	D	;SKIP OVER '.'
FFCB4:	INX	H	;SKIP TO TYPE FIELD
	DCR	C
	JNZ	FFCB4
	MVI	C,3	;SIZE OF TYPE FIELD
FFCB5:	LDAX	D	;GET ID BYTE
	CPI	0DH	;CR?
	RZ		;YES, DONE
	CPI	' '	;SPACE?
	RZ		;YES, DONE
	MOV	M,A	;STORE TYPE BYTE
	INX	D	;BUMP POINTER
	INX	H
	DCR	C	;DECREMENT MAX COUNT
	JNZ	FFCB5	;LOOP
	RET		;DONE

FFCBE:	STC		;SET CARRY
	RET

;********************************;
;           F M A K E            ;
;  ROUTINE TO CREATE A DISK FILE ;
;                                ;
;  INPUT:    DE=A(FCB)           ;
; OUTPUT:    CARRY=ERROR         ;
;********************************;

FMAKE:	MVI	C,CREAT	;CREATE CODE
	CALL	CPM	;ISSUE CREATE
	CPI	0FFH	;ERROR?
	JZ	FMERR	;YES
	XRA	A	;CLEAR CARRY
	RET
FMERR:	STC		;SET CARRY
	RET		;EXIT

;********************************;
;           F O P E N            ;
;  ROUTINE TO OPEN A DISK FILE   ;
;                                ;
;  INPUT:     DE=A(FCB)          ;
; OUTPUT:     CARRY=ERROR        ;
;********************************;

FOPEN:	MVI	C,OPEN	;OPNE CODE
	CALL	CPM	;ISSUE OPEN
	CPI	0FFH	;ERROR?
	JZ	FOERR	;YES
	XRA	A	;CLEAR CARRY
	RET
FOERR:	STC
	RET

;********************************;
;           F C L O S            ;
;  ROUTINE TO CLOSE A DISK FILE  ;
;                                ;
;  INPUT:     DE=A(FCB)          ;
; OUTPUT:     CARRY=ERROR        ;
;********************************;

FCLOS:	MVI	C,CLOSE	;CLOSE CODE
	CALL	CPM
	CPI	0FFH	;ERROR?
	JZ	FCERR	;YES
	XRA	A	;CLEAR CARRY
	RET
FCERR:	STC
	RET

;********************************;
;            F D E L E           ;
;  ROUTINE TO DELETE A DISK FILE ;
;                                ;
;  INPUT:     DE=A(FCB)          ;
;********************************;

FDELE:	MVI	C,DELET
	CALL	CPM	;ISSUE DELETE
	XRA	A	;RESET CARRY
	RET

;********************************;
;            O U T B T           ;
;   ROUTINE TO OUTPUT A BYTE     ;
;                                ;
;  INPUT:     A=BYTE)            ;
; OUTPUT:     CARRY=ERROR        ;
;********************************;

OUTBT:	STA	TEMP	;SAVE BYTE
OUT1:	LXI	H,OBUF+128
	XCHG		;BUFFER END ADDR IN DE
	LHLD	OUTPT	;CURRENT ADDR IN HL
	CALL	CPHL	;TEST FOR END OF BUFFER
	JZ	OUT2	;YES, WRITE
	LDA	TEMP
	MOV	M,A	;STORE DATA BYTE IN BUFFER
	INX	H	;BUMP BUFFER POINTER
	SHLD	OUTPT	;SAVE BUFFER POINTER
	ORA	A
	RET		;EXIT
OUT2:	LXI	D,OBUF	;POINT TO OUTPUT BUFFER
	LXI	H,TBUF	;TEMP BUFFER
	MVI	B,128
	CALL	MOVE	;COPY BUFFERS
	MVI	C,WRITE	;WRITE CODE
	LXI	D,OFCB	;OUTPUT FCB
	CALL	CPM	;ISSUE WRITE
	CPI	00	;OK?
	JNZ	OERR	;NO
OUT2A:	LXI	H,OBUF	;RESET POINTER
	SHLD	OUTPT
	JMP	OUT1	;CONTINUE
OERR:	STC
	RET

;********************************;
;            G E T B T           ;
;   ROUTINE TO READ A BYTE       ;
;                                ;
;  OUTPUTS:     A=BYTE           ;
;               CARRY=ERROR      ;
;********************************;

GETBT:	LXI	H,IBUF+128
	XCHG		;BUFFER END ADDR. IN DE
	LHLD	INPTR	;CURRENT POINTER IN HL
	CALL	CPHL	;TEST FOR END OF BUFFER
	JZ	GETB2	;YES, READ
GETB1:	MOV	A,M	;GET BYTE
	INX	H	;BUMP POINTER
	SHLD	INPTR	;SAVE POINTER
	ORA	A	;RESET CARRY
	RET
GETB2:	MVI	C,READ	;READ CODE
	LXI	D,IFCB	;FCB ADDRESS
	CALL	CPM	;ISSUE READ
	CPI	00	;ERROR?
	JNZ	IERR	;YES
	LXI	D,TBUF	;POINT TO TEMP BUFFER
	LXI	H,IBUF	;INPUT BUFFER
	MVI	B,128
	CALL	MOVE	;COPY BUFFER
	LXI	H,IBUF	;RESET BUFFER POINTER
	SHLD	INPTR
	JMP	GETB1	;CONTINUE
IERR:	STC
	RET

;********************************;
;   MISCELLANEOUS SUBROUTINES    ;
;********************************;

;********************************;
;            M O V E             ;
;  ROUTINE TO MOVE BLOCKS OF DATA;
;********************************;
MOVE:	LDAX	D	;GET BYTE
	MOV	M,A	;STORE BYTE
	INX	H
	INX	D	;BUMPP POINTERS
	DCR	B	;DECREMENT COUNT
	JNZ	MOVE	;LOOP
	RET

;********************************;
;             C P H L            ;
;  ROUTINE TO COMPARE HL VS DE   ;
;********************************;

CPHL:	MOV	A,H
	CMP	D
	RNZ
	MOV	A,L
	CMP	E
	RET

;********************************;
;             D A T A            ;
;********************************;

TEMP:	DS	2	;TEMP SAVE WORD

IFCB:	DS	33	;INPUT FCB
OFCB:	DS	33	;OUTPUT FCB

OUTPT:	DW	OBUF	;OUTPUT POINTER
INPTR:	DW	IBUF+128;INPUT POINTER

OBUF:	DS	128	;INPUT BUFFER
IBUF:	DS	128	;OUTPUT BUFFER
	END
