; ATFMT.ASM - low level hard disk format for PC-AT.
; Create DOSFM.COM as follows:
;	masm atfmt;
;	link atfmt;
;	exe2bin atfmt.exe atfmt.com
;	del atfmt.exe

cgroup	group	code
code	segment
	assume	cs:cgroup,ds:cgroup,es:cgroup

	org	100h

start:
	jmp	init

; Data

maxhead	db	?
maxcyl	dw	?

head	db	0
cyl	dw	0

warn	db	'Low-level hard disk format for AT.',13,10
	db	'Are you sure you want to destroy your disk (y/n)? $'
crlf	db	13,10,'$'
diskerr	db	13,10,'Disk error, format aborted',13,10,'$'

init:
	mov	dx,offset warn		; print warning message
	mov	ah,9
	int	21h
	mov	ah,1			; wait for key to be hit
	int	21h
	push	ax			; save the key
	mov	dx,offset crlf		; print new line
	mov	ah,9
	int	21h
	pop	ax			; get back the key
	cmp	al,'y'			; if Y or y, continue
	je	continue
	cmp	al,'Y'
	jne	done
continue:
	mov	ah,8			; get drive parameters
	mov	dl,80h			;  for drive c:
	int	13h
	jc	error
	and	cl,0c0h			; mask off max sector
	mov	maxcyl,cx
	mov	maxhead,dh

dotrack:
	mov	dh,head			; get head number
	mov	cx,cyl			; get cylinder number
	mov	bx,offset buff		; track interleave table address
	mov	dl,80h			; drive C
	mov	ah,5			; format track
	int	13h			; call bios
	jc	error
	
; Check for head overrun

	mov	dh,head
	cmp	dh,maxhead		; done all heads on one cylinder?
	je	nextcyl			; yes - go to next cylinder
	inc	dh			; no - go to next head
	mov	head,dh
	jmp	dotrack			; and format next track

; Check for cylinder overrun.  This is tricky since ch contains
; the low eight bits, and bits <7:6> of cl contain the high two bits.

nextcyl:
	mov	head,dh
	mov	head,0
	mov	cx,cyl
	cmp	cx,maxcyl		; done all cylinders?
	je	done			; yes - we're done
	inc	ch			; low byte wrapped around?
	jnz	nowrap			; no, skip incrementing high byte
	add	cl,40h			; increment high two bits
nowrap:
	mov	cyl,cx			; save new cylinder number
	mov	dl,'.'			; write a dot to screen
	mov	ah,2			;  to let them know we're
	int	21h			;  doing something
	jmp	dotrack			; go do next cylinder
	
error:
	mov	dx,offset diskerr	; print error message
	mov	ah,9
	int	21h
	mov	ax,4c01h		; error return
	int	21h

done:	mov	ax,4c00h		; normal return
	int	21h
	

; Track interleave table.  Quoting from the COMPAQ 386 Technical
; Reference, page 9-14:
;	"The table contains 2 bytes per sector on the track.
;	The first byte is 0 if the sector is to be formatted
;	normally, or 80h if the sector is to be formatted bad.
;	The second byte is the logical sector number of the
;	sector..."dd" is a "don't care" byte used to make up a
;	total of 512 bytes."
; The table shown here is for an interleave factor of 2.
; Tables for other interleaves are left as an exercise for the reader.

buff	db	0,1,0,0ah,0,2,0,0bh,0,3,0,0ch
	db	0,4,0,0dh,0,5,0,0eh,0,6,0,0fh
	db	0,7,0,10h,0,8,0,11h,0,9
	
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh

	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh

	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh

	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh
	dw	0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh,0ddddh

code	ends

	end	start
