	.PAGE 96
	.TITLE	'FFC - FAST DISK DUPLICATION PROGRAM'
	.SBTTL	'EQUATES'
	.PREL
	.PHEX
;	W EARNEST MOD 4/03/82
;	5/14/82 ADD FORMAT CODE
;	9/1/82 CHANGE STEP AND SKEW FOR NEW DRIVES
;	1/16/83 FIX REFORM FLAG BUG
;	2/11/83 FIX STOP TEST BUG
;	7/29/83 MOD DRIVE RDY TEST
;	FOR BIGBOARD SYSTEM DATA ONLY COPY
VER	=	1
REV	=	5
	.PROGID	FFC,VER,REV
;
;	BIOS ENTRY POINT OFFSETS
;
CONSTA	=	06H	;CONSOLE STATUS (A=0, NO DATA)
CONIN	=	09H	;CONSOLE INPUT (INTO A)
CONOUT	=	0CH	;CONSOLE OUTPUT (FROM C)
SELDSK	=	1BH	;SELECT DISK (FROM C, 0..1)
SETTRK	=	1EH	;SET TRACK (FROM C, 0..76)
SETSEC	=	21H	;SET SECTOR (FROM C, 1..26)
SETDMA	=	24H	;SET DMA ADDRESS (FROM BC)
READ	=	27H	;READ SECTOR INTO DMA BUFFER
WRITE	=	2AH	;WRITE SECTOR FROM DMA BUFFER
;
DISK	=	10H		;DISK BASE ADDR
DCOM	=	DISK        	;DISK COMMAND PORT
STATP	=	DISK		;DISK STATUS PORT
TRACK	=	DISK+1        	;DISK TRACK COMMAND
SECTP	=	DISK+2        	;DISK SECTOR PORT
DDATA	=	DISK+3        	;DISK DATA PORT
ROMSEL	=	0F01BH		;FERGUSON SELECT SUBR.
NMIVEC	=	066H		;NMI ADDRESS
STEP	=	1		;STEPPING RATE 2=10 MSEC,1=6 MSEC
LF	=	0AH	;LINE FEED
CR	=	0DH	;CARRIAGE RETURN
BELL	=	07H	;BELL
;
FCB	=	5CH
BOOT	=	0000H
BDOS	=	5
NBPT	=	128*26
SKEW	=	7
DRVI	=	0	;DRIVE A INPUT
DRVO	=	1	;DRIVE B OUTPUT
;
	.SBTTL	'MAIN COPY ROUTINE'
START:	LXI	SP,STACK+64
	XRA	A
	STA	RFORM
;
;	PRINT HEADING
;
NEXTC:	LXI	H,STR1
	CALL	WASC
	CALL	CRCK
REDO:	MVI	A,2	;START TRACK
	STA	TRKI
	STA	TRKO
	STA	TRKV
	MVI	A,77
	STA	STPTRK	;DEFAULT FULL DISK
	MVI	A,5	;NR OF PASSES
	STA	PASCNT
;
;	BEGIN MAIN LOOP
;
	CALL	CRLF
	MVI	A,10	;RETRYS ALLOWED
	STA	ERCNT
COPY1:	MVI	C,DRVI
	MVI	E,SELDSK
	CALL	BIOSC
	CALL	DRDYTS
	JRNZ	COPY1
	MVI	A,'R'
	STA	RWCHR
	CALL	INIPAS
COPY2:	LHLD	PTR	;READ NEXT N TRACKS
	LDA	TRKI
	CALL	WSTS
	CALL	RDTRK
	CALL	CKEMT
	JRNZ	..A	;THIS TRACK HAS DATA
	LDA	TRKI
	STA	STPTRK	;MARK IT AS TOO FAR
	JMPR	COPY2A
..A:	CALL	INCSEC
	LDA	TRKI
	INR	A
	STA	TRKI
	LDA	TRKCNT
	DCR	A
	STA	TRKCNT
	JRNZ	COPY2
;
COPY2A:	MVI	C,DRVO
	MVI	E,SELDSK
	CALL	BIOSC
	CALL	DRDYTS
	JRNZ	COPY2A
	MVI	A,'W'
	STA	RWCHR
	CALL	INIPAS
COPY3:	LHLD	PTR	;WRITE NEXT N TRACKS
	LDA	TRKO
	CALL	WSTS
	CALL	WRTRK
	CALL	INCSEC
	LDA	TRKO
	INR	A
	STA	TRKO
	MOV	L,A	;HOLD NEXT TRACK
	LDA	STPTRK
	SUB	L	;THERE YET?
	JRZ	COPY4	;TIME TO STOP, FOUND EMPTY
	JM	COPY4	;IN CASE OVERSHOOT
	LDA	TRKCNT
	DCR	A
	STA	TRKCNT
	JRNZ	COPY3
;
	LDA	PASCNT
	DCR	A
	STA	PASCNT
	JNZ	COPY1	;LOOP UNTIL ALL PASSES DONE
;
COPY4:	LXI	H,STR5	;PRINT 'COPY COMPLETE'
	CALL	WASC
	JMP	START	;RESTART IT, CLEAN FLAGS
;
INIPAS:	LXI	H,TRKBUF
	SHLD	PTR
	MVI	A,15	;TRKCNT = NUMBER OF TRACKS PER PASS
	STA	TRKCNT
	MVI	A,1
	STA	STSECT
	RET
;
INCSEC:	LHLD	PTR
	LXI	D,NBPT
	DAD	D
	SHLD	PTR
	LDA	STSECT
	ADI	SKEW
	CPI	27
	JRC	..A
	SUI	26
..A:	STA	STSECT
	RET
	.SBTTL	'READ/WRITE ROUTINES'
;
;	RDTRK - READ ABSOLUTE TRACK INTO MEMORY
;
;	ENTRY CONDITIONS
;	HL........FWA OF AREA TO READ TRACK INTO
;	A.........TRACK NUMBER (0 TO 76)
;
RDTRK:	PUSH	D
	PUSH	H
	CALL	INIRW
RTRK0:	MVI	B,26	;SECTOR COUNTER
	LDA	STSECT	;INITIAL SECTOR #
	MOV	C,A	;SECTOR NR IN C
RDTRK1:	PUSH	B
	CALL	INISEC
	MVI	E,READ
	CALL	BIOSC	;READ A SECTOR
	ORA	A	;OK?
	JNZ	RERR	;NO GOOD
	CALL	INCPTR
	POP	B
	CALL	SECINC
NOWRP3:	DJNZ	RDTRK1
	POP	H
	POP	D
	RET
;
RERR:	POP	B	;CLEAN STACK
	LXI	H,RERCT
	DCR	M
	JZ	HERR	;HARD ERROR
	LHLD	HLDDMA
	SHLD	DMAPTR	;RESET IT
	JMP	RTRK0
;
INIRW:	SHLD	DMAPTR
	SHLD	HLDDMA
	MOV	C,A
	MVI	E,SETTRK
	CALL	BIOSC
	MVI	A,5
	STA	RERCT
	RET
;
INISEC:	MVI	E,SETSEC
	CALL	BIOSC
	LBCD	DMAPTR
	MVI	E,SETDMA
	JMP	BIOSC
;
INCPTR:	LHLD	DMAPTR
	LXI	D,80H
	DAD	D
	SHLD	DMAPTR	;UPDATE POINTER
	RET
;
SECINC:	INR	C
	MOV	A,C
	CPI	27
	RC
	SUI	26
	MOV	C,A
	RET
;
;	WRTRK - WRITE ABSOLUTE TRACK FROM MEMORY
;
;	ENTRY CONDITIONS
;	HL........FWA OF AREA TO WRITE TRACK FROM
;	A.........TRACK NUMBER (0 TO 76)
;
WRTRK:	PUSH	D
	PUSH	H
	CALL	INIRW
RWRTRK:	LDA	STSECT	;INITIAL SECTOR #
	MOV	C,A
	MVI	B,26	;SECTOR COUNT
WRTRK1:	PUSH	B
	CALL	INISEC
	MVI	E,WRITE
	CALL	BIOSC
	ORA	A
	JNZ	WERR
	CALL	INCPTR
	POP	B
	CALL	SECINC
NOWRP4:	DJNZ	WRTRK1
;
	LXI	H,VBUF
	SHLD	DMAPTR
	LDA	STSECT
	MOV	C,A
	MVI	B,26
VTRK1:	PUSH	B
	CALL	INISEC
	MVI	E,READ
	CALL	BIOSC
	ORA	A
	JNZ	VERR
	CALL	INCPTR
	POP	B
	CALL	SECINC
NOWRP5:	DJNZ	VTRK1
	POP	H
	POP	D
	RET
;
VERR:	POP	B	;CLEAN UP STACK
	LXI	H,ERCNT
	DCR	M
	LXI	H,STR7	;DEST ERR, SOFT?
	JZ	XERR
	POP	H	;RECOV BUFFER ADDR AT START
	PUSH	H
	SHLD	DMAPTR
	JMP	RWRTRK
;
WERR:	POP	B
	LXI	H,RERCT
	DCR	M
	LXI	H,STR4
	JRZ	XERR	;WRITE ERROR, MAYBE SOFT
	LHLD	HLDDMA
	SHLD	DMAPTR
	JMP	RWRTRK	;TRY WRITE AGAIN
;
HERR:	LXI	H,STR3	;HARD SOURCE ERROR MESSAGE
	JMP	ERRC
;
XERR:	CALL	WASC	;REPORT DEST ERR
	LDA	RFORM	;HISTORY
	ORA	A
	JNZ	ERR	;HARD ERROR
	POP	B
	DCR	A
	STA	RFORM	;NARK FORMAT NOW
	LXI	H,STR6
	CALL	WASC
	CALL	FORMT	;REFORMAT THE DEST
	JMP	REDO
;
ERR:	LXI	H,STR2	;HARD DEST ERROR
ERRC:	CALL	WASC
	JMP	START
;
;	WASC - WRITE ASCII STRING TO CONSOLE
;
WASC:	MOV	A,M
	ORA	A
	RZ
	CALL	WACC
	INX	H
	JMPR	WASC
;
;	CRLF - WRITE END OF LINE TO CONSOLE
;
CRLF:	MVI	A,CR
	CALL	WACC
	MVI	A,LF
;
;	WACC - WRITE ASCII CHARACTER TO CONSOLE
;
WACC:	PUSH	H
	PUSH	D
	PUSH	B
	MOV	C,A
	MVI	E,CONOUT
	CALL	BIOSC
	POP	B
	POP	D
	POP	H
	RET
;
;	RACC - READ ASCII CHARACTER FROM CONSOLE
;
RACC:	PUSH	H
	PUSH	D
	PUSH	B
KBLP:	CALL	CONSTT
	ORA	A
	JRZ	KBLP	;WAIT FOR SOMETHING
	MVI	E,CONIN
	CALL	BIOSC
	ANI	7FH
	POP	B
	POP	D
	POP	H
	RET
;
CONSTT:	MVI	A,30	;HALF MIN
	STA	0FF6CH	;KEEP DISK MOTORS ON
	MVI	E,CONSTA
	CALL	BIOSC
	RET
;
;	CRCK - TEST FOR CR INPUT
;
CRCK:	CALL	RACC
	CPI	0DH
	RZ
	CPI	3
	JZ	BOOT
	CPI	60H
	JRC	..A
	ANI	5FH
..A:	CPI	'F'
	JRNZ	CRCK
	CALL	FORMT
	JMP	START
;
WSTS:	PUSH	PSW
	MVI	A,0DH	;CR
	CALL	WACC
	LDA	RWCHR
	CALL	WACC
	MVI	A,' '
	CALL	WACC
	POP	PSW
	PUSH	PSW
	CALL	HXBYT
	POP	PSW
	RET
;
HXBYT:	PUSH	PSW
	RAR
	RAR
	RAR
	RAR
	CALL	HOUT
	POP	PSW
HOUT:	ANI	0FH
	ADI	90H
	DAA
	ACI	40H
	DAA
	JMP	WACC
;
BIOSC:	MVI	D,0	;FORCE LOW
	LXI	H,0EA00H	;BIOS START ADDR
	DAD	D	;CALC ADDR
	PCHL		;DO CALL
;
DRDYTS:	IN	DISK
	BIT	7,A
	RZ		;DRIVE IS READY
DRDYLP:	IN	DISK
	CMA
	BIT	7,A
	RNZ		;DRIVE IS READY
	CALL	CONSTT
	ORA	A
	JRZ	DRDYLP	;WAIT FOR SOMETHING
	MVI	E,CONIN
	CALL	BIOSC
	ANI	7FH
	CPI	'C'-40H
	JZ	START	;ABORT IT
	JMP	DRDYLP	;TEST AGAIN
;
CKEMT:	PUSH	H
	PUSH	B
	LHLD	HLDDMA	;DATA START
	LXI	B,26*128	;AMOUNT OF DATA
EMTLP:	MOV	A,M
	CPI	0E5H		;NULL PATTERN
	JRNZ	..A		;NOT EMPTY
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JRNZ	EMTLP
..A:	POP	B
	POP	H
	RET
;
FORMT:	DI			;NO INTERRUPTS BUT NMI (NO CLOCK)
	LXI	H,26
	SHLD	FSECT		;DEFINE # SECTORS & FIRST TRK
	MVI	C,1
	CALL	ROMSEL
	CALL	HOME
	CALL	DOFORM
ENDFIL:	CALL	HOME
	MVI	C,0
	CALL	ROMSEL
	EI			;INTERRUPTS OK NOW
	JMP	CRLF		;BACK TO MENU
;
;	DISK FORMATTING ROUTINES.
;
DOFORM:	LXI	H,TRKBUF	;POINT TO TRACK BUFFER
	MVI	A,'F'
	STA	RWCHR
	XRA	A
	CALL	WSTS
	CALL	INDX
DOF1:	CALL	ADDR
	CALL	DATA
	LDA	FSECT
	DCR	A		;DECR SECTOR COUNT
	STA	FSECT
	JNZ	DOF1
	CALL	FILBUF		;FILL END OF BUFFER WITH FF'S
	LXI	D,TRKBUF
	ORA	A
	DSBC	D		;CALC SIZE OF BUFFER BUILT
	INR	H		;ADJUST FOR FIRST DCR
	SHLD	CNTSAV		;NEED MORE THAN ONCE
	LXI	H,NMWCOD
	LXI	B,NMWEND-NMWCOD
	LXI	D,NMIVEC
	LDIR
;
DOF4:	LXI	H,TRKBUF	;POINT TO FORMAT BUFFER
	CALL	FILADR		;PLACE TRACK AND SECTOR NRS IN BUFF
	LXI	H,TRKBUF	;POINT TO TRACK BUFFER
	LXI	B,DDATA		;DATA PORT FOR OUTI,CLEAR B
	LDED	CNTSAV		;REALLY JUST D REG
	IN	STATP		;CLEAR ANY LEFTOVER FLAGS
	MVI	A,0F4H		;TRACK WRITE COMMAND
	CALL	CMDOUT		;START & KILL SOME TIME
;
DOF7:	HLT			;WAIT FOR INTERRUPT
	JMP	DOF7		;LOOP TILL ALL DONE
;
TRKDUN:	CALL	BUSY		;MAKE SURE SHUT DOWN
	ANI	0FFH		;TEST IT
	JNZ	ERRMSG		;ERROR HERE, DIDNT WORK
	LDA	TRK		;TRACK NO
	INR	A		;INCREMENT IT
	STA	TRK
	CPI	77		;PAST LAST TRK?
	RZ			;IF DONE ALL TRACKS
	CALL	WSTS
	MVI	A,58H+STEP	;STEP COMMAND,NO VERIF
	CALL	WTCMD		;ISSUE IT
	JMP	DOF4
;
WTCMD:	CALL	CMDOUT		;EXECUTE & FALL THRU
;
BUSY:	IN	STATP		;TEST 1771 BUSY
	BIT	0,A
	JNZ	BUSY		;LOOP TILL FINISHED
	RET
;
CMDOUT:	OUT	DCOM		;ISSUE COMMAND
PAUSE:	XTHL
	XTHL
	RET
;
;	INDX  -  INDEX BLOCK FOR IBM FORMATS (NOT REQUIRED FOR 1771)
;			73 IN MEM, 73 ON DSK
;
INDX:	LXI	B,40<8+0FFH	;40 COUNT,ONES BYTE
	CALL	MOVEIT		;STORE THE BLOCK
	LXI	B,6<8+0		;COUNT 6, ZERO DATA
	CALL	MOVEIT		;STORE THE BLOCK
	MVI	M,0FCH		;INDEX MARK
	INX	H		;INCR POINTER
	LXI	B,26<8+0FFH	;NOW 26 MORE FF'S
	JMP	MOVEIT		;STORE THE BLOCK
;
;	ADDR  -  ADDRESS BLOCK  12 IN MEM, 13 ON DSK
;
ADDR:	LXI	B,6<8+0		;WRITE 6 ZEROS
	CALL	MOVEIT
	MVI	M,0FEH		;ID ADDRESS MARK
	INX	H
	MVI	B,4		;TRACK AND SECTOR ZERO INITIALLY
	CALL	MOVEIT
	MVI	M,0F7H		;WRITE 2 CRC'S
	INX	H
	RET
;
;	DATA  -  WRITE DATA BLOCK FILLED WITH E5'S
;			180 IN MEM, 181 ON DSK
DATA:	LXI	B,11<8+0FFH	;WRITE 11 FF'S
	CALL	MOVEIT
	LXI	B,6<8+0		;NOW 6 ZEROS
	CALL	MOVEIT
	MVI	M,0FBH		;DATA ADDRESS MARK
	INX	H
	LXI	B,128<8+0E5H	;DATA FILL CHARACTER
	CALL	MOVEIT
	MVI	M,0F7H		;WRITE 2 CRC'S
	INX	H
	LXI	B,33<8+0FFH	;INTERRECORD GAP, FALL THRU
;
;	MOVEIT ROUTINE HL --> MEMORY, DE = COUNT, B CONTAINS BYTE
;
MOVEIT:	MOV	M,C		;STORE BYTE
	INX	H
	DJNZ	MOVEIT
	RET
;
;	FILADR  -  FILL IN TRACK AND SECTOR NUMBERS
;
FILADR:	LXI	B,26*256+1
	LXI	D,190		;FILL ADDR OFFSET (180+12)-2
	LXI	H,TRKBUF+80	;LOCATION OF FIRST TRACK NUMBER
FIL01:	LDA	TRK		;TRACK NO
	MOV	M,A		;TO BUFFER
	INX	H
	INX	H		;POINT TO SECTOR
	MOV	M,C		;SECTOR NUMBER TO BUFFER
	DAD	D		;INCR BUFFER POINTER
	INR	C		;INCR SECTOR MAP NUMBER
	DJNZ	FIL01
	RET
;
;	FILBUF  -  FILL END OF TRACK WITH FF'S
;
FILBUF:	LXI	D,1024		;END OF TRACK FILL
	MVI	C,0FFH		;FILL CHAR
ET1:	MOV	M,C
	INX	H
	DCX	D		;DECR COUNT
	MOV	A,D
	ORA	E
	JNZ	ET1
	RET
;
;  ERROR ROUTINE
;
ERRMSG:	JMP	ENDFIL
;
;    HOME SELECTED DRIVE
;
HOME:	IN	STATP		;CHECK IF BUSY
	RRC
	JC	HOME
	MVI	A,0+STEP		;HOME COMMAND
	CALL	WTCMD		;ISSUE COMMAND, WAIT TILL NOT BUSY
	IN	STATP		;READ DISK STATUS
	ANI	4		;CHECK TRACK ZERO FLAG
	RNZ
;
HOMERR:	JMP	ENDFIL		;EXIT
;
NMWCOD:	OUTI
	RNZ
	DCR	D
	RNZ
	POP	D
	JMP	TRKDUN
NMWEND	=	.
;
;	STRING DATA
;
STR1:	.ASCII	'Fast Disk Duplicator Utility'
	.ASCII	' V '[VER+'0']'.'[REV+'0']' '
	.DATE	
	.BYTE	CR,LF
	.ASCII	'Source in Drive 0(A), Blank  in Drive 1(B)'[CR][LF]
	.ASCII	'Press RETURN to copy, "F" to format,'[CR][LF]
	.ASCIZ	'Ctrl-C to Exit.'[CR][LF]
STR2:	.ASCIZ	' error, Disk Unsalvagable, Aborting'[BELL][CR][LF]
STR3:	.ASCIZ	[CR][LF][BELL]'HARD Error on Source disk, Aborting'[CR][LF]
STR4:	.ASCIZ	[CR][LF]'Write'
STR5:	.ASCIZ	[CR][LF]'COPY COMPLETE'[BELL][CR][LF][LF]
STR6:	.ASCIZ	[BELL]' error, Attempting reformat'[CR][LF]
STR7:	.ASCII	[CR][LF]'Verification'
;
	.LOC	.DATA.
;
TRKNO:	.BLKB	1	;TRACK NUMBER
DMAPTR:	.BLKW	1	;DMA POINTER
HLDDMA:	.BLKW	1	;DMA HOLD FOR RETRY
CNTSAV:	.BLKW	1		;D REG SAVE OF BUFFER SIZE CNT
FSECT:	.BLKB	1		;SECTOR COUNT USED IN FORMATTING
TRK:	.BLKB	1		;TRACK NUMBER USED IN FORMATTING DISK
;
PTR:	.BLKW	1
VPTR:	.BLKW	1
TRKI:	.BLKB	1	;INPUT TRACK NUMBER
TRKO:	.BLKB	1	;OUTPUT TRACK NUMBER
TRKV:	.BLKB	1	;VERIFY TRACK NUMBER
STPTRK:	.BLKB	1
RFORM:	.BLKB	1
RWCHR:	.BLKB	1	;R OR W FOR STATUS
ERCNT:	.BLKB	1	;ERROR COUNTER
RERCT:	.BLKB	1	;RETRY COUNTER
PASCNT:	.BLKB	1	;PASS COUNT
TRKCNT:	.BLKB	1	;TRACK COUNT
STSECT:	.BLKB	1	;STARTING SECTOR
STACK:	.BLKW	32
VBUF:	.BLKB	26*128
TRKBUF	=	.
;
	.END	START
