
	* * * * * * * * * * * * * * * * * * * * * * * * * * * *
	*						      *
	*      		      MULTIFMT.ASM	  	      *
	*  						      *
	*    COPYRIGHT (C) 1984,85,86 AMPRO COMPUTERS, INC.   *
	*						      *
	* * * * * * * * * * * * * * * * * * * * * * * * * * * *



; Assemble with ASM.COM or equivalent. There is no Z80 code.


;REVISION LOG:	
;
;		02/05/86 Version 2.3
;			 Changed index pulse detection so works
;			 better with microfloppies
;
;		06/24/85 Version 2.2
;			 Changed floppy restore to use 6ms rate
;
;		02/27/85 Version 2.1
;			 Deleted warning message, and added a
;			 list of the floppy drives available.
;
;		12/12/84 Version 2.0
;			 Added warning message for use with
;			 Bios version 2.1+
;
;		05/13/84 Version 1.2
;			 Added delays after line feeds.
;		
;		05/08/84 Unreleased Ver. 1.1X
;			 Added Pmc, Sanyo and Televideo.
;		
;		03/20/84 Release version 1.0.


;MULTIFMT allows formatting several foreign diskettes.  It is based
;on the code developed for AMPRODSK and uses most of the algorithms
;in that program.  The major differences are:
;
;	1. Added a selection menu at the beginning of the program
;	   to allow different formats.  Jump routines from this
;	   menu update TABLE near the end of the program for the
;	   new format.
;
;	2. Removed the "copy" code as it is not needed.
;
;	3. Added routines after formatting and before verify
;	   to write a "boot loader" on the diskette (required
;	   by several different formats). The TYPE byte determines
;	   which formats require a "boot loader".

; wd1770 equates
REST	EQU	0		; slow restore
RDSEC	EQU	88H		; read sector command
WRSEC	EQU	0A8H		; write sector command
WRTRK	EQU	0F8H		; write track command
STEPI	EQU	58H		; step in command
RDID	EQU	0C8H		; read address command
MOT	EQU	80H		; motor on status
WPR	EQU	40H		; write protected status
SPU	EQU	20H		; disk at speed status (type i)
TYP	EQU	20H		; record type status (types ii and iii)
RNF	EQU	10H		; record not found status
CRC	EQU	8		; crc error status
TK0	EQU	4		; track zero status (type i)
LDT	EQU	4		; lost data status (types ii and iii)
IDX	EQU	2		; index status (type i)
DRQ	EQU	2		; data request status (types ii and iii)
BSY	EQU	1		; controller busy status

ERRII	EQU	WPR+RNF+CRC+LDT	; type ii error status mask
ERRIII	EQU	WPR+LDT		; type iii error status mask

CMND	EQU	0C0H		; fdc command register
WTRK	EQU	CMND+1		; write to track register
WSEC	EQU	WTRK+1		; write to sector register
WDAT	EQU	WSEC+1		; write to data register

STAT	EQU	WDAT+1		; fdc status register
RTRK	EQU	STAT+1		; read from track register
RSEC	EQU	RTRK+1		; read from sector register
RDAT	EQU	RSEC+1		; read from data register

CONT	EQU	0		; system control port
ROMOFF	EQU	40H		; turn rom off

SID0	EQU	0EFH		; mask side bit off
SID1	EQU	10H		; side bit in control register
SDEN	EQU	20H		; single density bit in control register
TRY	EQU	3		; tries
TRYHARD	EQU	10		; we try harder

MSEC	EQU	167		; constant for 1 ms delay

CR	EQU	13		; carriage return
LF	EQU	10		; line feed
ESC	EQU	27		; escape key
UPCASE	EQU	5FH		; upper case mask

bdos	equ	5

	ORG	100H

	;embed the copyright notice
	;
START:	JMP	BEGIN		; leave room for copyright
	DB	' MULTIFMT Copyright (c) 1984,85,86 AMPRO Computers, Inc. '
	DB	13,10,26

	;set up the stack and print signon message
	;
BEGIN:	LXI	SP,STACK	; set local stack
	CALL	CLRSC		; clear the screen
	CALL	ILPRT		; print following text
	DB	CR,LF,'    Foreign Diskette Format/Verify Utility'
	DB	CR,LF,' Copyright (c) 1984,85,86 AMPRO Computers, Inc.'
	DB	CR,LF,'              Version 2.3$'

	call	get$bios$vers
	mvi	a,16
	jnz	new$sys
	lhld	1
	mvi	L,5ch
	mov	a,m
	jmp	plugem
new$sys:
	push	psw
	mvi	a,0
	lxi	h,jplug1
	mov	m,a
	inx	h
	mov	m,a
	inx	h
	mov	m,a
	pop	psw
plugem:
	adi	'@'
	sta	plug1
	inr	a
	sta	cplug1
	jmp	doit


DISP$FDEV:
;
; [E2.15]
;
;
	lda	lb$vers
	cpi	20
	rm

	LXI	D,D$FDEV$HDR	; Print header
	mvi	c,9
	call	bdos

	mvi	a,0		; starting unit #
D$NEXT$FDEV:
	sta	unit
	call	lb$get$ldte	; Get address of unit id	
	MOV	A,M		; Get unit id
	CPI	01		; Floppy?
	JNZ	D$BUMP$PTR	; No -- go to the next device
	inx	h		; Get drive #
	mov	a,m		; .
	ani	03h		; mask out excess bits
	MOV	l,a		; update floppy device number
	mvi	h,0		; .
	dad	h		; x2
	xchg
	LXI	H,FNAMES	; .
	dad	d		; x2
	dad	d		; x4
	dad	d		; x6
	lxi	d,d$fname	;
	lxi	b,6		; 
	db	0edh,0b0h	; . (LDIR)
	lda	unit		;
	adi	'A'		;
	sta	d$current	;
	LXI	D,D$FDEV$LIN	; and output the line
	mvi	c,9
	call	bdos

D$BUMP$PTR:
	lda	unit
	inr	a		; Bump to next unit
	cpi	16		; Done yet?
	jm	D$NEXT$FDEV	; No -- go do the next one
	RET

unit:	db	0

D$FDEV$HDR:	DB	CR,LF,LF,'- FLOPPY DISK ASSIGNMENTS -',CR,LF
		DB	' CP/M drive   '
		DB	'Floppy disk',CR,LF
		DB	' ------------------------',CR,LF,'$'

D$FDEV$LIN:
		DB	'  '
D$CURRENT:	DB	'x  '
D$EDISK:	DB	'   '
D$EBLANK:	DB	'         '
D$FNAME:	DB	'        '
		DB	CR,LF,'$'
D$FDEV$HLEN	EQU	$-D$FDEV$LIN	; Line length

FNAMES:		DB	'First '
		DB	'Second'
		DB	'Third '
		DB	'Fourth'

; end of DISPLAY$FDEV


GET$BIOS$VERS:
; Get bios version -- Brings the current BIOS jump tables (starting
;     at warm boot) to a local area for ease of utility access.  If
;     this BIOS is version 2.1 or greater, the secondary jump table
;     is brought in as well.
;
; Entry: none
; Exit:  Z  = bios < 2.1 (old bios)
;        NZ = bios 2.1+  (fixed disk bios)
;        All registers are modified
;
	LHLD	1		; Get start of bios jump table
	LXI	D,LB$BIOS$TBL	; Move bios to local storage
	LXI	B,LB$LEN	; .  (length of bios area)
	DB	0edh,0b0h	; .  (move routine)
	MVI	A,0		; Test CP/M version
	CALL	LB$GETNXT	; Get next jump table
	STA	LB$VERS		; Save bios version
	INX	H		; See if HL is 0FFFFh
	MOV	A,H		; .
	ORA	L		; .
	RZ			; If so, then old version
	DCX	H		; Fix HL as it has the table addr
	LXI	D,LB$XTBL	; Move extra table to local storage
	LXI	B,LB$XLEN	; .  (length of extra table)
	db	0edh,0b0h	; .  (move routine)
	MVI	A,0FFH		; Set NZ to indicate bios
	ORA	A		; ... version 2.1+
	RET			; ... and return.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*							*
*		Data area . . .				*
*							*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * *

; Replicated BIOS for ease of use . . .
LB$BIOS$TBL:
LB$WBOOT	DB	0,0,0	; Warm boot
LB$CONST	DB	0,0,0	; Console status
LB$CONIN	DB	0,0,0	; Console input
LB$CONOUT	DB	0,0,0	; Console output
LB$LISTOUT	DB	0,0,0	; List output
LB$PUNCH	DB	0,0,0	; Punch output
LB$READER	DB	0,0,0	; Reader input
LB$HOMDSK	DB	0,0,0	; Home disk (move to track 00)
LB$SELDSK	DB	0,0,0	; Select disk drive
LB$SETTRK	DB	0,0,0	; Select track number
LB$SETSEC	DB	0,0,0	; Select sector number
LB$SETDMA	DB	0,0,0	; Set DMA address
LB$DSKREAD	DB	0,0,0	; Disk read
LB$DSKWRITE	DB	0,0,0	; Disk write
LB$LISTST	DB	0,0,0	; List status
LB$SECTRN	DB	0,0,0	; Sector translate routine
; AMPRO-specific BIOS calls
LB$GETNXT	DB	0,0,0	; Get bios ver & next tbl address
LB$GETEDSK	DB	0,0,0	; Get pointer to E-disk storage
LB$IOINIT	DB	0,0,0	; Set new I/O parameters
LB$SCSIDRV	DB	0,0,0	; SCSI direct driver

LB$LEN	EQU	$-LB$WBOOT	; Length of bios table

LB$XTBL:
LB$SWAP$DRV	DB	0,0,0	; Swap two logical drives
LB$WINDRV	DB	0,0,0	; Set/get win drive parameters
LB$PHYTAB	DB	0,0,0	; Set/get phytab access
LB$GET$LDTE	DB	0,0,0	; Get physical table entry address
LB$RESERVED	DB	0,0,0	; Reserved entry

LB$XLEN	EQU	$-LB$XTBL	; Length of extra table

LB$VERS		DB	0

doit:
	; main program begins here
	;
ASK1:	CALL	ILPRT		; print following string
	DB	CR,LF,LF,'FORMAT or VERIFY?  (F or V)'
	DB	CR,LF,'Press <ESC> or <^C> to exit.$'
ASK1A:	CALL	CONIN		; get response
	CPI	ESC
	JZ	EXIT		; exit to operation system
	CPI	3
	JZ	EXIT		; ctl c
	ANI	UPCASE		; force upper case
	CPI	'F'
	JZ	SETF		; if format
	CPI	'V'
	JZ	SETV		; if verify
	JMP	ASK1A		; otherwise, do this again

	; set function code and do it
	;
SETF:	MVI	A,1
	STA	FUNC
	JMP	FORMAT
SETV:	MVI	A,2
	STA	FUNC
	JMP	VERIFY

	;setup the format routine
	;
FORMAT:	CALL	CLRSC
	CALL	ILPRT
	DB	8,32,CR,LF,LF	; overwrite response and make new line
	DB	'FORMAT prepares a fresh diskette for data or '
	DB	'program storage.$'
	CALL	ASK5		; ask destination
	JC	ASK1		; restart if bad selection
	JMP	ASK2
FORM0:	CALL	ASK6		; give warning
	JC	ASK1
	CALL	EXEC		; do it
	JMP	ASK1		; restart at end of format

	;setup the verify routine
	;
VERIFY:	CALL	CLRSC
	CALL	ILPRT
	DB	8,32,CR,LF
	DB	CR,LF,'VERIFY checks the reliability of data on a disk.$'
	CALL	ASK5		; ask for destination disk
	JC	ASK1
	JMP	ASK2
VERF0:	CALL	ASK3		; ask to load disk
	JC	ASK1
	CALL	EXEC		; do it
	JMP	ASK1

	;get selection and update TABLE
	;
ASK2:	CALL	ILPRT		; print following string
	DB	CR,LF,LF,'Formats Available:'
 	DB	CR,LF,LF
	DB	'		'
	DB	'48 TPI FORMATS',CR,LF
	DB	'	    (48 tpi Drive Required)',CR,LF,LF
	DB	'A - H/Z 89 SSDD			'
	DB	'I - MORROW MD3 DSDD',CR,LF
	DB	'B - H/Z 89 DSDD			'
	DB	'J - OSBORNE 2 SSDD',CR,LF
	DB	'C - H/Z 89 SSXD 		'
	DB	'K - PMC-101 MicroMate DSDD',CR,LF
	DB	'D - H/Z 89 DSXD 		'
	DB	'L - SANYO MBC 1000/1100 DSDD',CR,LF	
	DB	'E - H/Z 100 SSDD		'
	DB	'M - TELEVIDEO 802/803 DSDD',CR,LF
	DB	'F - H/Z 100 DSDD		'
	DB	'N - TRS80-3 w/MEM MERCH CP/M SSDD',CR,LF
	DB	'G - KAYPRO II SSDD		'
	DB	'O - TRS80-4 w/MONTEZUMA CP/M SSDD',CR,LF
	DB	'H - MORROW MD2 SSDD',CR,LF,LF
	DB	'		'
	DB	'96 TPI FORMATS',CR,LF
	DB	'	    (96 tpi Drive Required)',CR,LF,LF
	DB	'P - DEC RAINBOW SSDD		'
	DB	'S - H/Z 89 DSDD ',CR,LF
	DB	'Q - EAGLE IIE-2 SSDD		'
	DB	'T - H/Z 89 SSXD',CR,LF
	DB	'R - H/Z 89 SSDD 		'
	DB	'U - H/Z 89 DSXD'
	DB	CR,LF,LF,'Choose one or <ESC> to Restart: $'

ASKAGN:	CALL	CONIN		; get the answer
	CPI	3		; ^c?
	JZ	EXIT		; exit
	CPI	ESC		; esc?
	JZ	ASK1		; return
	ANI	UPCASE		; mask upper case
	sta	typeletter
	CPI	'A'		; a?
	JZ	H1		; h/z 89 ssdd 48tpi
	CPI	'B'		; b?
	JZ	H2		; h/z 89 dsdd 48tpi
	CPI	'C'		; c?
	JZ	H3		; h/z 89 ssxd 48tpi
	CPI	'D'		; d?
	JZ	H4		; h/z 89 dsxd 48tpi 
	CPI	'E'		; e?
	JZ	H9		; h/z 100 ssdd
	CPI	'F'		; f?
	JZ	H10		; h/z 100 dsdd
	CPI	'G'		; g?
	JZ	K2		; kaypro 2
	CPI	'H'		; h?
	JZ	MD2		; morrow md2
	CPI	'I'		; i?
	JZ	MD3		; morrow md3
	CPI	'J'		; j?
	JZ	OSB		; osborne 2
	CPI	'K'		; k?
	JZ	PMC		; pmc-101 type a
	CPI	'L'		; l?
	JZ	SAN		; sanyo mbc 1000/1100
	CPI	'M'		; m?
	JZ	TEL		; televideo 802/803
	CPI	'N'		; n?
	JZ	TR		; trs80-3 w/mem merchant cp/m
	CPI	'O'		; o?
	JZ	T4		; trs80-4
	CPI	'P'		; p?
	JZ	DEC		; dec rainbow
	CPI	'Q'		; q? 
	JZ	EG		; eagle
	CPI	'R'		; r?
	JZ	H5		; h/z 89 ssdd 96tpi
	CPI	'S'		; s?
	JZ	H6		; h/z 89 dsdd 96tpi
	CPI	'T'		; t?
	JZ	H7		; h/z 89 ssxd 96tpi
	CPI	'U'		; u?
	JZ	H8		; h/z 89 dsxd 96tpi
	JMP	ASKAGN		; anything else ask again	

typeletter:
	db	'a'

ASK2E:	STC			; set error flag
	RET

	;update TABLE routines begin here...
	;
K2:	MVI	A,2		; 512 bytes/sectors
	STA	SIZE		; store it
	MVI	A,24		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC512	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,K2SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

K2SKW:	DB	0,8,3,6,1,9,4,7,2,5,255	

EG:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	INR	A		;
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

T4:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,21		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,T4SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

T4SKW:	DB	1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,255	

TR:	MVI	A,2		; 512 bytes/sectors
	STA	SIZE		; store it
	MVI	A,24		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC512	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,TRSKW		; point to skew table
	JMP	MOVSKW		; move it to skew

TRSKW:	DB	1,6,2,7,3,8,4,9,5,10,255

OSB:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no sector bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

OSBSKW:	DB	1,2,3,4,5,255	

PMC:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no sector bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	INR	A
	STA	TWOSID		; double sided format
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

SAN:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,45		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	STA	TYPE		; type byte
	INR	A		; roll up a
	STA	TWOSID		; double sided format
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,SANSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

SANSKW: DB	1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,255

TEL:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,21		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	STA	TYPE		; type byte
	INR	A		; roll up a
	STA	TWOSID		; double sided format
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,TELSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

TELSKW: DB	1,4,7,10,13,16,2,5,8,11,14,17,3,6,9,12,15,18,255

MD2:	MVI	A,2		; 
	STA	TYPE		; 
	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no sector bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

MD3:	MVI	A,3		; 
	STA	TYPE		; 
	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no sector bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	INR	A		;
	STA	TWOSID		; double sided format
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

DEC:	MVI	A,2		; 512 bytes/sectors
	STA	SIZE		; store it
	MVI	A,24		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	TYPE		; no type byte
	STA	SBIAS		; no sector bias
	STA	TWOSID		; single sided format
	MVI	A,1		;
	STA	TPI96		; 0=48tpi, 1=96tpi format
	LXI	D,SEC512	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,DECSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

DECSKW:	DB	1,2,3,4,5,6,7,8,9,10,255	

H1:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,45		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	MVI	A,4		; 
	STA	TYPE		; type byte
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H1SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

H1SKW:	DB	1,12,7,2,13,8,3,14,9,4,15,10,5,16,11,6,255	

H2:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,45		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	INR	A		; roll up a
	STA	TWOSID		; double sided format
	MVI	A,5		;
	STA	TYPE		; type byte
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H1SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

H3:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	MVI	A,6		;
	STA	TYPE		; type byte
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

H4:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	INR	A		; roll up a
	STA	TWOSID		; double sided format
	MVI	A,7		;
	STA	TYPE		; type byte
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

H5:	MVI	A,1		; 256 bytes/sectors
	STA	SIZE		; store it
	MVI	A,45		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	INR	A		; 96 tpi format
	STA	TPI96		; 0=48tpi, 1=96tpi format
	MVI	A,8		;
	STA	TYPE		; type byte
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H1SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

H6:	MVI	A,1		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,45		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	INR	A		; roll up a
	STA	TPI96		; 0=48tpi, 1=96tpi format
	STA	TWOSID		; double sided format
	MVI	A,9		;
	STA	TYPE		; type byte
	LXI	D,SEC256	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H1SKW		; point to skew table
	JMP	MOVSKW		; move it to skew

H7:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TWOSID		; single sided format
	INR	A		; roll up a
	STA	TPI96		; 0=48tpi, 1=96tpi format
	MVI	A,10		;
	STA	TYPE		; type byte
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

H8:	MVI	A,3		; 1024 bytes/sectors
	STA	SIZE		; store it
	MVI	A,102		; gap3 size
	STA	GAP3		;
	MVI	A,79		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	INR	A		; roll up a
	STA	TPI96		; 0=48tpi, 1=96tpi format
	STA	TWOSID		; double sided format
	MVI	A,11		;
	STA	TYPE		; type byte
	LXI	D,SEC1K		; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,OSBSKW	; point to skew table
	JMP	MOVSKW		; move it to skew

H9:	MVI	A,2		; 512 bytes/sectors
	STA	SIZE		; store it
	MVI	A,121		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	STA	TWOSID		; single sided format
	MVI	A,12		;
	STA	TYPE		; type byte
	LXI	D,SEC512	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H100SKW	; point to skew table
	JMP	MOVSKW		; move it to skew

H100SKW: DB	1,2,3,4,5,6,7,8,255

H10:	MVI	A,2		; 512 bytes/sectors
	STA	SIZE		; store it
	MVI	A,121		; gap3 size
	STA	GAP3		;
	MVI	A,39		; # of tracks
	STA	MAXTRK		;
	XRA	A		; zero out accum
	STA	SBIAS		; no bias
	STA	TPI96		; 0=48tpi, 1=96tpi format
	INR	A		; roll up a
	STA	TWOSID		; double sided format
	MVI	A,13		;
	STA	TYPE		; type byte
	LXI	D,SEC512	; point to data
	CALL	MOVDAT		; move to dat0
	LXI	D,H100SKW	; point to skew table
	JMP	MOVSKW		; move it to skew

	;move the new data to TABLE
	;
MOVDAT:	MVI	B,8		; # of bytes to move
	LXI	H,DAT0		; point to data location
MOVDT:	LDAX	D		; move byte to accum
	MOV	M,A		; store it
	INX	D		; roll up reg de
	INX	H		; roll up reg hl
	DCR	B		; count down 1
	JNZ	MOVDT		; done?
	RET

MOVSKW:	LXI	H,SKEW		; point to skew
MOVSK:	LDAX	D		; move into accum
	MOV	M,A		; store it
	CPI	0FFH		; done?
	JZ	RETURN		;
	INX	D		; roll up de
	INX	H		; roll up hl
	JMP	MOVSK		; again 
RETURN: LDA	FUNC		; get function #
	CPI	1		; was it a format?
	JZ	FORM0		; 
	JMP	VERF0		; if not format must be verify

SEC128:	DB	32,0E5H,32,0E5H,32,0E5H,32,0E5H
SEC256:	DB	64,0E5H,64,0E5H,64,0E5H,64,0E5H
SEC512:	DB	128,0E5H,128,0E5H,128,0E5H,128,0E5H
SEC1K:	DB	0,0E5H,0,0E5H,0,0E5H,0,0E5H

	;tell them to put the disk in
	;
ASK3:	lda	typeletter
	call	conout
	CALL	ILPRT		; print the following string
	DB	CR,LF,LF,'Place disk in Drive '
ASK30s:	db	'a'
	DB	CR,LF,LF,'Press <RETURN> to VERIFY, '
	DB	'<ESC> to quit.  $'
	JMP	ASK6E

ASK5:
	call	disp$fdev
	CALL	ILPRT
	DB	CR,LF,LF,'Destination drive?  (A - '
plug1:	db	'D) $'
ASK5E:	CALL	CONIN		; get the answer
	CPI	ESC
	JZ	EXIT
	CPI	3
	JZ	EXIT
	ANI	UPCASE		; force upper case
	CPI	'A'		; first valid drive
	JC	ASK5E
cplug1:	equ	$+1
	CPI	'E'		; first invalid drive
	JNC	ASK5E
	sta	ask60d
	sta	ask30s
	push	psw
	call	conout
	pop	psw
	sui	'A'
jplug1:	jmp	ask50s
	call	lb$get$ldte
	mov	a,m
	cpi	1
	jnz	ask5
	inx	h
	mov	a,m
	ani	3
ask50s:
	STA	DDRIV
	CALL	SETSEL		; disk select bits
	ORA	A
	RET

ASK6:	lda	typeletter
	call	conout
	CALL	ILPRT		; print the following string
	DB	CR,LF,LF,'Place destination disk on drive '
ask60d	DB	'a'
	DB	CR,LF,LF,'Press <RETURN> to write, '
	DB	'<ESC> to quit.  $'
ASK6E:	CALL	CONIN		; get answer
	CPI	CR
	RZ
	CPI	ESC
	JZ	EXIT
	JMP	ASK6E

	;execute it!
	;
EXEC:	CALL	ILPRT
	DB	CR,LF,LF,'$'
	LDA	FUNC		; function 1=fmt, 2=vfy
	CPI	1
	JZ	FMT
	CPI	2
	JZ	VFY		; 
	RET

	;format routines...
	;
FMT:	LDA	DDRIV
	CALL	SETSEL
	CALL	SETUP
	XRA	A
	STA	TRACK
	STA	HEAD
NEXTRK:	CALL	KEY
	LXI	H,FRMSG
	CALL	PRINT
	CALL	TMRPRT
	CALL	MAKETRK
	MVI	A,TRY
	STA	TRIES
NT3:	CALL	WRITRK
	JZ	NT5
	LXI	H,TRIES
	DCR	M
	JNZ	NT3
	CALL	ILPRT
	DB	CR,'                              '
	DB	CR,LF,'FORMAT failed.',CR,LF,'$'
	CALL	REPORT
	RET

NT5:	LDA	TWOSID
	ORA	A
	LDA	TRACK
	JZ	NT0
	LDA	HEAD
	ORA	A
	LDA	TRACK
	JZ	NT1
NT0:	LXI	H,MAXTRK
	CMP	M
	JNZ	NT1
	CALL	ILPRT
	DB	CR,'                              '
	DB	CR,LF,'FORMAT complete.',CR,LF,LF,'$'

	;check the TYPE byte to see if a boot loader is needed
	;
	LDA	TYPE
	ANI	0FH		; mask off upper nibble
	CPI	2		; if morrow md2
	JZ	MD2GEN		; write boot loader
	CPI	3		; if morrow md3
	JZ	MD3GEN		; write boot loader
	CPI	4		; if h/z 89 ssdd
	JZ	H1GEN		; write boot loader
	CPI	5		; if h/z 89 dsdd
	JZ	H2GEN		; write boot loader
	CPI	6		; if h/z 89 ssxd (48tpi)
	JZ	H3GEN		; write boot loader
	CPI	7		; if h/z 89 dsxd (48tpi)
	JZ	H4GEN		; write boot loader
	CPI	8		; if h/z 89 ssdd (96tpi)
	JZ	H5GEN		; write boot loader
	CPI	9		; if h/z 89 dsdd (96tpi)
	JZ	H6GEN		; write boot loader
	CPI	10		; if h/z 89 ssxd (96tpi)
	JZ	H7GEN		; write boot loader
	CPI	11		; if h/z 89 dsxd (96tpi)
	JZ	H8GEN		; write boot loader
	CPI	12		; if h/z 100 ssdd
	JZ	H9GEN		; write boot loader
	CPI	13		; if h/z 100 dsdd
	JZ	H10GEN		; write boot loader
	JMP	VFY		; anything else begin verify

NT1:	INR	A
	STA	TRACK
	CALL	STEPIN
	JMP	NEXTRK

	;verify routines begin here
	;
VFY:	MVI	A,0
	STA	HEAD
	LDA	DDRIV
	CALL	SETSEL
	CALL	SETUP
	MVI	A,TRY
	STA	TRIES
V1:	CALL	READID
	JZ	V0
	LXI	H,TRIES
	DCR	M
	JNZ	V1
	CALL	ILPRT
	DB	CR,LF,'VERIFY failed.  Cannot read source disk.',cr,lf,'$'
	RET
V0:
	LDA	TWOSID
	CPI	1
	MVI	A,0
	JC	VF0
	INR	A
VF0:	STA	TWOSID
	XRA	A
	STA	TRACK		; start with track 0
VLOOP:	CALL	KEY
	LXI	H,VFMSG
	CALL	PRINT
	CALL	TMRPRT
	MVI	A,TRY
	STA	TRIES
VL1:	CALL	READTRK
	JZ	VL0
	LXI	H,TRIES
	DCR	M
	JNZ	VL1
	CALL	ILPRT
	DB	CR,'                              '
	DB	CR,LF,'VERIFY failed.  Unrecoverable read error.',CR,LF,'$'
	CALL	REPORT
	RET

VL0:	LDA	TWOSID
	ORA	A
	LDA	TRACK
	JZ	VF1
	LDA	HEAD
	ORA	A
	LDA	TRACK
	JZ	VF2
VF1:	LXI	H,MAXTRK
	CMP	M
	JNZ	VF2
	CALL	ILPRT
	DB	CR,'                              '
	DB	CR,LF,'VERIFY complete.',CR,LF,'$'
	RET

VF2:	INR	A
	STA	TRACK
	CALL	STEPIN
	JMP	VLOOP

	;boot loader routine begin here
	;
	;gen as in sysgen!
	; 
GEN:	LDA	DDRIV		;
	CALL	SETSEL		;
	CALL	SETUP		; setup write  
	XRA	A		; zero out acc
	STA	TRACK		; track 0
	STA	HEAD		; 
	LXI	H,TKBUF		; get point
	SHLD	DMAADR		; save buffer pointer
	LXI	H,SKEW1		; point to new skew
	CALL	WTLOOP		; write data
	JMP	VFY

MD2GEN:	CALL	MDGEN		;
	LXI	D,DAT4		; point to next data
	MVI	B,25		;
	CALL	MOVDT		;
	JMP	MD1GEN		;

MD3GEN:	CALL	MDGEN		;
	LXI	D,DAT5		; point to next data
	MVI	B,25		; move double sided dpb
	CALL	MOVDT		;
	JMP	MD1GEN		;

MDGEN:	MVI	A,1		;
	STA	SKEW1		;
	INR	A		;
	STA	SKEW1+1		;
	MVI	A,255		;
	STA	SKEW1+2		;
	LXI	D,DAT3		; point to morrow data
	MVI	B,60		; # of bytes to move
	LXI	H,TKBUF		; point to buffer area
	CALL	MOVDT		; move data
	MVI	E,0		; fill data
	MVI	D,68		; # of bytes to move
	CALL	LOAD		; move them
	RET

MD1GEN:	MVI	E,0		;
	MVI	D,103		;
	CALL	LOAD		;
	CALL	MOVE5		;
	CALL	LOAD		;
	CALL 	MOVE5		;
	CALL	LOAD		;
	CALL	MOVE5		;
	CALL	LOAD		;
	LXI	D,DAT3		;
	MVI	B,60		;
	CALL	MOVDT		;
	MVI	D,68		;
	MVI	E,0		;
	CALL	LOAD		;
	CALL	MOVE5
	CALL	LOAD
	CALL	MOVE5
	CALL	LOAD
	CALL	MOVE5
	CALL	LOAD
	CALL	MOVE5
	CALL	LOAD
	JMP	GEN		;

MOVE5:	MVI	E,0E5H		;
	MVI	D,0		;
	RET

H1GEN:	CALL	HGEN		; load skew1
	LXI	D,H1DAT		; point to h1 data
	JMP	HGEN1		; store data

H2GEN:	CALL	HGEN		; load skew1
	LXI	D,H2DAT		; point to h2 data
	JMP	HGEN1		; store the data

H3GEN:	CALL	HGEN
	LXI	D,H3DAT
	JMP	HGEN2

H4GEN:	CALL	HGEN
	LXI	D,H4DAT
	JMP	HGEN2

H5GEN:	CALL	HGEN
	LXI	D,H5DAT
	JMP	HGEN1

H6GEN:	CALL	HGEN
	LXI	D,H6DAT
	JMP	HGEN1

H7GEN:	CALL	HGEN
	LXI	D,H7DAT
	JMP	HGEN2

H8GEN:	CALL	HGEN
	LXI	D,H8DAT
	JMP	HGEN2

H9GEN:	CALL	HGEN
	LXI	D,H9DAT
	JMP	HGEN2

H10GEN:	CALL	HGEN
	LXI	D,H10DAT
	JMP	HGEN2

HGEN:	MVI	A,1		; load 
	STA	SKEW1		; skew
	MVI	A,255		; table
	STA	SKEW1+1		;
	RET

HGEN1:	;use this routine for 256 byte sector h/z formats
	MVI	B,29		; # of bytes to move
	LXI	H,TKBUF		; point to buffer area
	CALL	MOVDT		; move data
	MVI	E,0E5H		; fill data
	MVI	D,227		; # of bytes to move
	CALL	LOAD		; move them
	JMP	GEN

HGEN2:	;use this routine for 512/1024 byte sector h/z formats
	MVI	B,29		; # of bytes to move
	LXI	H,TKBUF		; point to buffer area
	CALL	MOVDT		; move data
	MVI	E,0E5H		; fill data
	MVI	D,227		; # of bytes to move
	CALL	LOAD		; move them
	CALL	MOVE5
	CALL	LOAD
	CALL	MOVE5
	CALL	LOAD
	CALL	MOVE5
	CALL	LOAD
	JMP	GEN

	;step in the drive
	;
STEPIN:	LDA	TWOSID
	ORA	A
	JZ	STI		; single sided
	LDA	HEAD
	ORA	A
	MVI	A,1
	JZ	STI0
	MVI	A,0
STI0:	STA	HEAD
	JZ	STI1

STI:	LDA	SELBYT
	ANI	SID0		; mask side bit off
	OUT	CONT		; select side 0
	STA	SELBYT
	CALL	WAIT
	MVI	A,STEPI
	CALL	OUTCMD
STILP:	IN	STAT
	RAR
	JC	STILP
	RET

STI1:	LDA	SELBYT
	ORI	SID1
	OUT	CONT		; select side 1
	STA	SELBYT
	LXI	H,TRACK
	DCR	M
	JMP	WAIT

	;write a track
	;
WRITRK:	IN	STAT
	RAR
	JC	WRITRK
	LXI	H,TKBUF
	MVI	A,WRTRK		; write track command
	CALL	OUTCMD
	CALL	WR
	MOV	A,B
	STA	STATUS
	ANI	ERRIII
	RET

WR:	IN	STAT		; get fdc status
	MOV	B,A		; save status
	RAR			; check busy
	RNC			; end of command, return to caller
	RAR			; check for drq
	JNC	WR		; if not
	MOV	A,M		; get a byte from buffer
	OUT	WDAT		; to fdc
	INX	H		; bump hl
	JMP	WR		; again

	;make a track in memory
	;
MAKETRK: LXI	H,TKBUF		; create track image in memory
	MVI	B,60
	MVI	A,4EH
MTLP:	MOV	M,A		; write gap4a
	INX	H
	DCR	B
	JNZ	MTLP
	SHLD	DMAADR		; sector 1 starts here
	LDA	HEAD
	STA	SIDE
	LXI	H,SKEW		;load skew table pointer

LOOP:	MOV	C,M
	INX	H
	INR	C
	JZ	ENDTRK		; if c was 0ffh
	DCR	C
	LDA	SBIAS
	ADD	C
	STA	SECTOR
	PUSH	H		; save skew pointer on stack
	CALL	MAKTRK
	POP	H
	JMP	LOOP

ENDTRK:	LHLD	DMAADR
	LXI	B,1000
ETLP:	MVI	M,4EH		;end track fill data
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	ETLP
	SHLD	DMAADR
	RET

MAKTRK:	LHLD	DMAADR		; track image
	PUSH	H		; save it
	LXI	H,TABLE		; track format table
MAKT1:	MOV	D,M		; get count
	INX	H		; bump pointer
	MOV	E,M		; get data
	INX	H		; bump pointer
	MOV	A,E		; check for end of table (0ffh)
	INR	A		; 0ffh + 1 = 0
	JZ	MAKT2		; if end of table
	XTHL			; point to track buffer
	CALL	LOAD		; fill track buffer
	XTHL			; point to format table
	JMP	MAKT1		; again
MAKT2:	POP	H		; get track buffer address from stack
	SHLD	DMAADR		; save pointer to track buffer
	RET			; to caller

	;write current track from read buffer
	;
WRITETRK:
	LXI	H,RDBUF
	SHLD	DMAADR
	LXI	H,SKEW		; point to skew table	
WTLOOP:	MOV	C,M
	INX	H		; bump pointer
	INR	C
	RZ			; finished, end of table is 0ffh
	DCR	C
	LDA	SBIAS
	ADD	C
	OUT	WSEC		; to fdc
	PUSH	H		; save skew pointer
	CALL	WRITESEC
	POP	H
	JMP	WTLOOP

	;write a sector from DMA buffer
	;
WRITESEC:
	IN	STAT		; clear status
	IN	RDAT		; clear any trash
	LHLD	DMAADR
	MVI	A,WRSEC		; write sector command
	CALL	OUTCMD		; to fdc
	CALL	WR		; write the data
	SHLD	DMAADR		; save pointer
	MOV	A,B		; get status
	STA	STATUS
	ANI	ERRII
	RZ			; return to this caller
	POP	H		; adjust stack from writetrk
	POP	H
	RET			; return to previous caller

	;read current track into read buffer
	;
READTRK: 
	LXI	H,RDBUF
	SHLD	DMAADR
	LXI	H,SKEW		; point to skew table
RTLOOP:	MOV	C,M		; get sector number from table
	INX	H		; bump pointer
	INR	C
	RZ			; finished, end of table is 0ffh
	DCR	C
	LDA	SBIAS
	ADD	C
	STA	SECTOR
	OUT	WSEC		; to fdc
	PUSH	H		; save skew pointer
	CALL	READSEC		; read the sector
RT0:	POP	H
	JMP	RTLOOP

READSEC:
	IN	STAT		; clear status
	IN	RDAT		; clear any trash
	LHLD	DMAADR		; pointer to read buffer
	MVI	A,RDSEC		; read sector command
	CALL	OUTCMD		; to fdc
	CALL	RD		; read the data
	SHLD	DMAADR		; save pointer
	MOV	A,B
	STA	STATUS
	ANI	ERRII
	RZ
	POP	H		; adjust stack from readtrk
	POP	H
	RET			; to previous caller

RD:	IN	STAT		; get fdc status byte
	MOV	B,A		; save status
	RAR			; rotate busy bit to carry
	RNC			; end of command, return to caller
	RAR			; rotate data request to carry
	JNC	RD		; wait for data request
RD0:	IN	RDAT		; get data from fdc
	MOV	M,A		; put it into buffer
	INX	H		; bump hl
	JMP	RD		; again

READID:	IN	STAT
	IN	RDAT
	LXI	H,IDSV
	MVI	A,RDID
	CALL	OUTCMD
	CALL	RD
	MOV	A,B		; get status
	STA	STATUS
	ANI	ERRIII
	RET

	;allow FDC to setup properly
	;
WAIT:	LXI	B,50 * MSEC
WT0:	DCX	B
	MOV	A,B
	ORA	C
	JNZ	WT0
	RET

WAIT10: LXI	B,10 * MSEC
	JMP	WT0

LOAD:	MOV	M,E		; (e) to track buffer
	INX	H		; increment pointer
	DCR	D		; decrement count
	JNZ	LOAD		; again
	RET

CLRSC:	MVI	D,24		; print 24 line feed chars to clear screen
CLS:	MVI	A,LF
	CALL	CONOUT		; out to console
	CALL	WAIT10		; wait 10 ms after line feed
	DCR	D		; decrement count
	JNZ	CLS		; again
	RET

PRINT:	MOV	A,M		; hl points to text string
	INX	H		; bump hl
	CPI	'$'		; check for terminator
	RZ			; return to caller
	CALL	CONOUT		; send byte to console
	JMP	PRINT		; again

pCONOUT:
	PUSH	B		; save
	PUSH	D		;  the
	PUSH	H		;   registers
	MOV	E,A		; text to be printed
	MVI	C,2		; console output function
	CALL	5		; bdos
	POP	H		; restore
	POP	D		;  the
	POP	B		;   registers
	RET

	;prints next byte pointed to by top of stack
	;until delimiter $ is found
	;
ILPRT:	XTHL			; return address to hl points to text
ILP:	MOV	A,M		; get next byte
	INX	H		; bump pointer
	CPI	'$'		; check for string terminator
	JZ	ILPE		; if end of string
	CALL	pCONOUT		; send byte to console
	JMP	ILP		; again
ILPE:	XTHL			; put updated pointer on stack
	RET

CONOUT:	PUSH	B		; save
	PUSH	D		;  the
	PUSH	H		;   registers
	MOV	E,A		; text to be printed
	MVI	C,6		; console output function
	CALL	5		; bdos
	POP	H		; restore
	POP	D		;  the
	POP	B		;   registers
	RET

CONIN:	MVI	A,9		; bios call avoids echo to console
BIOS:	LHLD	1
	MOV	L,A
	PCHL

CONINB:	PUSH	B
	PUSH	D		; save
	PUSH	H		;  registers
	MVI	C,1		; console input function
	CALL	5		; bdos
	POP	H		; restore
	POP	D		;  registers
	POP	B
	RET

	;
	;restore the disk and wait for status
	;

; The current setup routine does a restore with the 1772
; motor on flag enabled.  It exits as soon as the BUSY
; status bit goes away, or after a 4 second timeout.

SETUP:	LDA	SELBYT		; get selected drive
	OUT	CONT		; select the drive
  	MVI	A,REST		; restore command
	CALL	OUTCMD		; output the command
	LXI	H,4000		; 4000 ms timeout setup
DEL0:	MVI	C,0
DEL1:	DCR	C
	JNZ	DEL1
	IN	STAT
	RAR
	JNC	READY		; go on if 1772 done
	DCX	H
	MOV	A,H
	ORA	L
	JNZ     DEL1
	MVI	A,0D0H		; timed out -- force interrupt,
	CALL	OUTCMD		;   then report failure
	JMP	FAILED

; The current ready function checks to see if a diskette
; is inserted in a drive.  A read address command with 
; the motor on flag enabled is used.  If the command
; hangs up, the 1772 is not receiving index pulses,
; indicating the lack of a spinning diskette.

READY:	
	MVI	A,0C0H		; read address command
	CALL	OUTCMD		
	LXI	H,4000		; 4000 mS timeout setup
	MVI	C,0
RDY1:	DCR	C
	JNZ	RDY1
	IN	STAT
	RAR
	RNC			; finished, if 1772 done
	DCX	H
	MOV 	A,H
	ORA	L
	JNZ	RDY1		; loop till timeout
	MVI	A,0D0H		; timeout -- force interrupt,
	CALL	OUTCMD		;   then report failure
	
FAILED:
	LDA	SELBYT
	ANI	0FH
	MVI	C,0
FLD1:	INR	C
	RAR
	JNC	FLD1
	MOV	A,C
	adi	30H		; add ascii bias
	STA	DRI
	CALL	ILPRT		; print following string
	DB	CR,LF,'Drive '
DRI:	DB	'A Not Ready, Insert disk, close door, and try again.',CR,LF,'$'
	POP	B		; adjust stack
        RET

	;send a command to the FDC
	;
OUTCMD:	OUT	CMND
	MVI	A,10
OC0:	DCR	A
	JNZ	OC0		; wait 35 us. for fdc to set-up
	RET

KEY:	push	b
	push	d
	mvi	c,6
	mvi	e,0ffh
	call	5
	pop	d
	pop	b
	rz
	CPI	3
	JZ	EXIT
	PUSH	PSW
	CALL	ILPRT
	DB	CR,'                              ',CR,'$' ; clear the line
	POP	PSW
	CPI	ESC
	RNZ
	POP	H
	RET

EXIT:	JMP	0		; warm boot

TMRPRT:	LDA	TRACK
	LXI	D,TKMSG0
	CALL	BINASC
	LDA	HEAD
	LXI	D,SDMSG0
	CALL	BINASC
	LXI	H,TKMSG
	JMP	PRINT		; print returns to caller

REPORT:	LXI	D,DR		; point to error message
	LDA	SELBYT
	ANI	0FH		; mask upper nybble
	MVI	C,0		; clear counter
R1:	INR	C		; bump it
	RAR			; rotate selbit into carry
	JNC	R1		; again?
	MOV	A,C
	ADI	30H		; add ascii bias
	STAX	D		; store it in message
	STA	WPRMSG0
	LDA	STATUS
	ANI	WPR		; is disk protected?
	JZ	R2
	LXI	H,WPRMSG	; write protected message
	CALL	PRINT
	POP	H		; adjust the stack
	CALL	CONIN		; get response
	CPI	CR		; carriage return?
	JZ	EXEC		; if so
	RET			; get out of here
R2:	LXI	D,TK		; in error message
	LDA	TRACK
	CALL	BINASC
	LXI	D,HD
	LDA	SIDE
	ORA	A		; set flags
	JZ	RPRT1
	MVI	A,1
RPRT1:	CALL	BINASC
	LXI	D,SC
	LDA	SECTOR
	CALL	BINASC
	LXI	D,ST
	LDA	STATUS
	ANI	RNF
	JNZ	SRNF
	LXI	H,CRCER
	CALL	MOV3
	JMP	RPRT2
SDNR:	LXI	H,DNRER
	CALL	MOV3
	JMP	RPRT2
SRNF:	LXI	H,RNFER
	CALL	MOV3
RPRT2:	LXI	H,ERRMSG
RPRT3:	JMP	PRINT		; print returns to caller

MOV3:	MVI	B,3
MOVL:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVL
	RET

BINASC:	PUSH	PSW		; save value
	PUSH	D		; save string ptr
	MVI	A,'0'		; ascii zero
	STAX	D
	LXI	B,2		; b=0, c=2
	XRA	A		; a=0
B0:	INX	D		; bump ptr
	STAX	D		; zero to str
	DCR	C
	JNZ	B0		; again please
	POP	D		; restore de
	LXI	H,TBL		; conversion table
B1:	MVI	C,0		; clear count
	MOV	A,M		; table value
	INR	A
	JZ	BEND		; end of table, conv done
	POP	PSW		; restore value
B3:	SUB	M		; begin division
	JC	B2
	INR	C		; keep count
	JMP	B3
B2:	ADD	M		; restore acc
	PUSH	PSW		; save it
	MOV	A,C		; count
	CPI	0
	JNZ	STSTR		; set ascii value in string
	MOV	A,B
	CPI	0		; 1st time?
	JNZ	STSTR
B4:	INX	H		; bump tbl ptr
	JMP	B1		; next

STSTR:	MVI	B,1		; flag 1st time
	MOV	A,C		; count to c
	ADI	30H		; ascii bias
	STAX	D		; write it into string
	INX	D		; bump str ptr
	JMP	B4

BEND:	POP	PSW		; adjust stack
	RET			; return to caller

TBL:	DB	100
	DB	10
	DB	1
	DB	255		; end of table

	;setup the selbyt
	;
SETSEL:	inr	a
	MOV	C,A
	XRA	A
	STC
STSL:	RAL
	DCR	C
	JNZ	STSL
	ORI	ROMOFF
	STA	SELBYT
	RET

	;error messages...
ERRMSG:
	DB	CR,LF,' Error:  Drive '
DR:	DB	0,':  Track '
TK:	DB	0,0,0,'  Head '
HD:	DB	0,0,0,'  Sector '
SC:	DB	0,0,0,'  Status  '
ST:	DB	0,0,0,CR,LF,'$'
TKMSG:	DB	'Track '
TKMSG0:	DB	0,0,0,'  Side '
SDMSG0:	DB	0,0,0,CR,'$'
VFMSG:	DB	'Verify  $'
FRMSG:	DB	'Format  $'
WPRMSG:	DB	CR,'                              '
	DB	CR,LF,'Remove write protect tab from '
	DB	'destination diskette.'
	DB	CR,LF,'Place diskette in drive '
WPRMSG0:DB	'A, then press <RETURN>.  $'
DNRER:	DB	'DNR'
RNFER:	DB	'RNF'
CRCER:	DB	'CRC'

	;the main data table..
	;
TABLE:	DB	12,0		; defines sector format (#bytes,data)
	DB	3,0F5H		; write 0a1h
	DB	1,0FEH		; id address mark
	DB	1
TRACK:	DB	0
	DB	1
SIDE:	DB	0
	DB	1
SECTOR:	DB	1
	DB	1
SIZE:	DB	3		; always 512 bytes
	DB	1,0F7H		; write crc (2 bytes)
GAP2:	DB	22,4EH		; gap 2 length, data
PREAM:	DB	12,0		; preamble
	DB	3,0F5H		; write 0a1h
	DB	1,0FBH		; data address mark
DAT0:	DB	0,0E5H		; bytes of data fill
	DB	0,0E5H		; bytes of data fill
	DB	0,0E5H		; bytes of data fill
	DB	0,0E5H		; bytes of data fill
	DB	1,0F7H		; write crc (2 bytes)
GAP3:	DB	0,4EH		; gap 3 length, data
	DW	-1		; end of table (0ffffh)

SKEW:	DS	40

DAT3:	DB	0,0,0,3EH,0C9H,32H,255,253,0CDH,255,253,21H,254,255,39H,5EH
	DB	23H,56H,21H,17H,0,19H,0EBH,31H,0,255,0D3H,0F6H,0CDH,3,0,0C3H
	DB	18H,0,CR,LF,'Not a SYSTEM Diskette',CR,LF

DAT4:	DB	0,0,0,0,0,0,0,0,0
	DB	40,0,4,15,1,5EH,0,7FH,0,0C0H,0,32,0,2,0,0E1H

DAT5:	DB	0,4,0,0,0,0,0,0,0
	DB	40,0,4,15,1,0C2H,0,0BFH,0,0E0H,0,30H,0,2,0,89H

H1DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,62H,0E5H,2,8,0E5H,0E5H,0,0E5H
	DB	20H,0,3,7,0,97H,0,7FH,0,0F0H,0,20H,0,2,0,0ADH

H2DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,63H,0E5H,2,16,0E5H,0E5H,0,0E5H
	DB	20H,0,4,15,0,9BH,0,255,0,0F0H,0,40H,0,2,0,0F7H

H3DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,66H,0E5H,8,8,0E5H,0E5H,0,0E5H
	DB	28H,0,3,7,0,0BDH,0,7FH,0,0F0H,0,20H,0,2,0,75H

H4DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,67H,0E5H,8,16,0E5H,0E5H,0,0E5H
	DB	28H,0,4,15,0,0C2H,0,255,0,0F0H,0,40H,0,2,0,0BEH

H5DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,6AH,0E5H,2,16,0E5H,0E5H,1,0E5H
	DB	20H,0,4,15,1,9BH,0,7FH,0,0C0H,0,20H,0,2,0,0BEH

H6DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,6BH,0E5H,2,16,0E5H,0E5H,1,0E5H
	DB	20H,0,4,15,0,3BH,1,255,0,0F0H,0,40H,0,2,0,4DH

H7DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,6EH,0E5H,8,16,0E5H,0E5H,1,0E5H
	DB	28H,0,4,15,1,0C2H,0,7FH,0,0C0H,0,20H,0,2,0,85H

H8DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,6FH,0E5H,8,16,0E5H,0E5H,1,0E5H
	DB	28H,0,4,15,0,8AH,1,255,0,0F0H,0,40H,0,2,0,0ECH

H9DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,22H,1,4,8,27H,80H,0,11H
	DB	20H,0,3,7,0,97H,0,127,0,0F0H,0,20H,0,2,0,0C6H

H10DAT:	DB	0E5H,0E5H,0E5H,0E5H,0,23H,1,4,16,27H,80H,0,11H
	DB	20H,0,4,15,1,9BH,0,255,0,0F0H,0,40H,0,2,0,15

SKEW1:	DS	4		; 

TYPE:	DB	0		; 2=morrow ss, 3=morrow ds etc.
FUNC:	DS	1		; function 1=format, 2=verify, 
MAXTRK:	DB	39		; maximum track
TWOSID:	DB	0		; 0=ss , 1=ds
HEAD:	DB	0		;
SDRIV:	DS	1		; source drive
DDRIV:	DS	1		; destination drive
SELBYT:	DS	1		;
SBIAS:	DB	0		; sector bias  0=ss, 10h=ds, 30h=ds96
TPI96:	DB	1		; 0=48tpi , 1=96tpi
DMAADR:	DS	2		;
STATUS:	DS	1		;
TRIES:	DS	1		;
	DS	64		; space for 32 level stack
STACK:	DS	2		; space for ccp stack pointer
IDSV:	DS	6		; id save area
RDBUF:	DS	10 * 512	; read buffer
TKBUF:	END	START		; end of program

