;****************************************
;
;               ISIS II TO CPM
;             FILE COPY UTILITY
;
;                VERSION 1.1
;  MODIFIED VERSION
;		ORIGINAL WOULD NOT COPY A FILE LONGER THAN 16K
;		BECAUSE OF IMPROPERLY SETTING THE LINKS
;		THIS VERSION HAS BEEN TESTED ON LARGER THAN 16K
;		FILES AND SHOULD WORK WITH ANY SIZE FILE BUT HAS
;		NOT BEEN TESTED ON FILES > 48K.
;
;****************************************

	ORG	100H
ICOPY:	LXI	SP,STACK	;SET STACK
	MVI	C,1		;SELECT DISK 1
	CALL	SDSK
	CALL	HOME		;HOME DISK 1
	LXI	D,DIRLNK	;POINT TO DIR LINK BLOCK LINK
	LXI	H,DBCA		;DIR BCA
	CALL	GLB		;GET LINK BLOCK
ICL0:	LXI	H,DBCA		;DIR BCA
	CALL	GDB		;GET DIR BLOCK
	JC	NOTF		;NO MORE DIR BLOCKS, ERR
	LXI	H,DBUF		;DIR BUFFER
	SHLD	DENT		;SAVE IN POINTER
	MVI	A,8		;NUMBER OF  ENTRIES/BLOCK
	STA	DCNT		;SAVE
ICL1:	LHLD	DENT		;GET DIR ENTRY PTR
	MOV	A,M		;GET STATUS BYTE
	CPI	00		;ACTIVE?
	JNZ	ILN1		;NO, GET NEXT ENTRY
	INX	H		;POINT TO FN
	LXI	D,TFCB+1	;POINT TO ENTERED FN
	MVI	B,6		;FN SIZE
	CALL	FCHK		;TEST FN
	JNZ	ILN1		;NO, GET NEXT ENTRY
	LHLD	DENT		;GET DIR ENTRY ADDR
	LXI	D,7		;OFFSET TO EXT.
	DAD	D		;ADDR OF EXT.
	LXI	D,TFCB+1+8	;EXT
	MVI	B,3		;SIZE OF EXT.
	CALL	FCHK		;TEST EXT
	JZ	ICL2		;OK, FOUND FILE
ILN1:	LHLD	DENT		;POINTER TO ENTRY
	LXI	D,16		;SIZE OF ENTRY
	DAD	D		;POINT TO NEXT ENTRY
	SHLD	DENT
	LDA	DCNT		;ENTRY COUNTER
	DCR	A		;DECREMENT
	STA	DCNT
	JNZ	ICL1		;LOOP
	JMP	ICL0

NOTF:	LXI	D,MSG1
	MVI	C,09
	CALL	CPM
	JMP	EXIT

IOERR:	LXI	D,MSG2
	MVI	C,09
	CALL	CPM
	JMP	EXIT

EXIT:	MVI	C,0
	CALL	SDSK		;SET DISK 0
	JMP	BOOT

ICL2:	LHLD	DENT		;GET DIR ENTRY ADDRESS
	LXI	D,12		;OFFSET TO COUNT
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M		;BLOCK COUNT IN DE
	XCHG
	SHLD	BCNT		;SAVE BLOCK COUNT
	INX	D		;POINT TO LINK BLOCK LINK
	LXI	H,FBCA		;FILE BCA
	CALL	GLB		;GET LINK BLOCK
	MVI	C,0
	CALL	SDSK		;SET DISK A
	LXI	D,TFCB		;POINT TO FCB
	MVI	C,CREATE
	CALL	CPM		;CREATE FILE
	CPI	0FFH		;ERROR?
	JZ	IOERR
ICL3:	LXI	H,FBCA		;POINT TO BCA
	CALL	GDB		;GET DATA BLOCK
	JC	DONE		;FINS
	LXI	D,FBUF		;COPY FBUF TO TBUF
	LXI	H,TBUF
	MVI	B,128
	CALL	MOVE
	MVI	C,0
	CALL	SDSK		;SET DISK A
	LXI	D,TFCB
	MVI	C,WRITE
	CALL	CPM		;WRITE THE BLOCK ON CPM
	ORA	A
	JNZ	IOERR
	LHLD	BCNT		;GET BLOCK COUNT
	DCX	H		;DECREMENT
	SHLD	BCNT
	MOV	A,H
	ORA	L		;TEST FOR DONE
	JNZ	ICL3		;NO, LOOP
DONE:	MVI	C,0
	CALL	SDSK		;SET DISK A
	LXI	D,TFCB		;FCB
	MVI	C,CLOSE
	CALL	CPM
	JMP	BOOT		;FINISHED

;***************************************;
;
;           GLB - GET LINK BLOCK
;
;         DE= A(LINK TO LINK BLOCK)
;         HL= A(BLOCK CONTROL AREA)
;
;***************************************;
GLB:	SHLD	BCAP		;SAVE BCA ADDR
	CALL	SEEKR		;READ LINK BLOCK
	LHLD	BCAP		;GET BCA ADDR
	LXI	D,BCBL		;OFFSET TO LINK BUFFER
	DAD	D
	LXI	D,TBUF
	MVI	B,128
	CALL	MOVE		;COPY TO LINK BUFFER
	LHLD	BCAP		;GET BCA ADDR
	LXI	D,BCBL+4	;OFFSET TO FIRST DATA LINK
	XCHG
	DAD	D		;DE=A(FIRST DATA LINK)
	XCHG
	LXI	B,BCAL		;OFFSET TO LINK PTR
	DAD	B
	MOV	M,E
	INX	H
	MOV	M,D		;SET LINK PTR
	LHLD	BCAP		;BCA ADDR
	LXI	D,BCALC		;LINK COUNT
	DAD	D
	MVI	M,62		;NO OF LINKS
	RET

;****************************************:
;
;            GDB:   GET DATA BLOCK
;
;            HL= A(BLOCK CONTROL AREA)
;
;****************************************;

GDB:	SHLD	BCAP		;SAVE BCA ADDR
	LXI	D,BCAL		;OFFSET TO LINK BUF
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M		;GET LINK ADDR
	PUSH	D		;SAVE LINK ADDR
	LDAX	D		;GET LINK BYTE
	INX	D
	MOV	C,A
	LDAX	D		;GET ANOTHER LINK BYTE
	ORA	C		;TEST FOR ZERO LINK
	POP	D
	JZ	GDBE		;END, EXIT
	PUSH	D		;SAVE D AGAIN
	PUSH	H
	CALL	SEEKR		;GET DATA BLOCK
	POP	H
	POP	D
	INX	D
	INX	D
	MOV	M,D
	DCX	H
	MOV	M,E		;UPDATE LINK PRT
	LHLD	BCAP		;GET BCA ADDR
	LXI	D,BCBD		;OFFSET TO DATA BUF
	DAD	D
	LXI	D,TBUF
	MVI	B,128
	CALL	MOVE		;COPY DATA TO BUF
	LHLD	BCAP		;GET BCA ADDR
	LXI	D,BCALC		;LINK COUNT
	DAD	D
	DCR	M		;DECREMENT
	RNZ			;OK, CONTINUE
	LHLD	BCAP		;GET BCA ADDR
	LXI	D,BCBL+2	;POINT TO LINK BUF
	DAD	D
	MOV	E,M		;GET LINK
	INX	H
	MOV	D,M
	DCX	H
        MOV A,E
	ORA	D		;TEST FOR ZERO LINK
	JZ	GDBE2		;END, EXIT
	XCHG			;DE = A(NEXT LINK)
	LHLD	BCAP		;BCA ADDR
	CALL	GLB		;GET LINK BLOCK
	RET

GDBE:	STC			;INDICATE EOF
	RET

GDBE2:  LXI D,FBUF      ;COPY FBUF TO TBUF
        LXI H,TBUF
        MVI B,128
        CALL MOVE
        MVI C,0
        CALL SDSK       ;SET DISK A
        LXI D,TFCB
        MVI C,WRITE
        CALL CPM
        ORA A
        JNZ IOERR
        JMP GDBE
;
;**************************************;
;       FCHK:   FILE ID CHECK
;
;       DE = A(ISIS FILE ID)
;	HL = A(CPM FILE ID)
;	B = SIZE OF FIELD
;
;*************************************;

FCHK:	XCHG
FCK1:	LDAX	D		;GET BYTE
	CPI	00		;SEE IF END OF ID
	JNZ	FCK2		;YES, SEE IF END OK
	MOV	A,M		;GET BYTE
	CPI	' '		;END BOTH
	RZ			;DONE
	ORA	1
	RET			;DONE
FCK2:	CMP	M		;COMPARE
	RNZ			;N,G.
	INX	D
	INX	H
	DCR	B		;DECREMENT COUNT
	JNZ	FCK1
	RET

;***************************************;
;
;         SEEKR:   SEEK DISK BLOCK
;
;         DE = A(LINK)
;
;***************************************;

SEEKR:	PUSH	D		;SAVE DE
	MVI	C,1		;SET DISK B
	CALL	SDSK
	POP	D
	PUSH	D
	LDAX	D		;GET SECTOR
	MOV	C,A
	CALL	SSEC		;SET SECTOR
	POP	D
	PUSH	D
	INX	D
	LDAX	D		;GET TRACK
	MOV	C,A
	CALL	STRK
	CALL	READ		;READ BLOCK
	POP	D
	RET

;*****************************************;
;
;       MOVE:   MOVE DATA
;
;	DE = A (SOURCE)
;	HL = A(DEST)
;	B = COUNT
;
;******************************************;

MOVE:	LDAX	D		;GET BYTE
	MOV	M,A		;STORE BYTE
	INX	H
	INX	D		;BUMP PTRS
	DCR	B		;DECREMENT COUNT
	JNZ	MOVE
	RET

;*******************************************;
;
;	CPM INTERFACE ROUTINES
;
;*******************************************;

SDSK:	LHLD	0001H		;GET BIOS ADDR
	MVI	L,1BH
	PCHL
SSEC:	LHLD	0001H
	MVI	L,21H
	PCHL
STRK:	LHLD	0001H
	MVI	L,1EH
	PCHL
READ:	LHLD	0001H
	MVI	L,27H
	PCHL
HOME:	LHLD	0001H
	MVI	L,18H
	PCHL

;******************************************;
;
;	BLOCK CONTROL AREA DEFINITIONS
;
;******************************************;

BCA	EQU	0
BCAL	EQU	0
BCALC	EQU	BCAL+2
BCBL	EQU	BCALC+1
BCBD	EQU	BCBL+128

;******************************************;
;
;		    DATA
;
;******************************************;
MSG1:	DB	'FILE NOT FOUND',0DH,0AH,'$'
MSG2:	DB	'I/O ERROR',0DH,0AH,'$'

DIRLNK:	DB	01,01
DENT:	DS	2
DCNT:	DS	1
BCNT:	DS	2
BCAP:	DS	2
	DS	64
STACK	EQU	$

DBCA:	DS	2
	DS	1
	DS	128
DBUF:	DS	128

FBCA:	DS	2
	DS	1
	DS	128
FBUF:	DS	128

TBUF	EQU	0080H
TFCB	EQU	005CH
CPM	EQU	0005H
BOOT	EQU	0000H
CREATE	EQU	22
WRITE	EQU	21
CLOSE	EQU	16
	END
