NAME	OPTIM
.XLIST
PAGE 105,132
TITLE	Fixed Disk Optimising Program
.LIST
COMMENT *
	Uses High resolution Timer routine to check speed of processes.
	*

;---------------------
; MACROS
;---------------------

DISPLAY	MACRO			; Display String @ DS:DX
	MOV	AH,9
	INT	21H
	ENDM
	
HEADSET	MACRO	 
	MOV	DL,CS:[DR_ID]
	MOV	DH,0
	MOV	CX,01H
	MOV	AX,21AH
	MOV	BX,OFFSET DTABUF
	INT	13H
	ENDM

;------------------	
;    EQUATES
;------------------

TIM_LOW		EQU	006CH	; Location of System Clock
BIOS_DSEG	EQU	0040H	; Address of BIOS Data segment
TIM_MODE	EQU	43H	; Control Port Address of 8253-5 chip
TIM_0		EQU	40H	; Read Port Address of 8253-5

;------------------
;    CODE
;------------------

	ASSUME	CS:CODE, DS:CODE
CODE	SEGMENT
MAIN	PROC	NEAR
	ORG	100H
	
BEGIN:	JMP	START

COUNT		DW	0	; Interrupt Ticks  54.925 msecs
COUNT_MICRO	DW	0	; Calculate from COUNT
COUNT_MILLI	DW	0	; Calculate from COUNT
TIM_MICRO	DW	0	; From 8253 counter
TIM_MILLI	DW	0	; Final Value
TIM_SEC		DW	0	; Final Value

TIM1MIC		DW	0	; Test 1 Microseconds
TIM1MIL		DW	0	; Test 1 Milliseconds
TIM1SEC		DW	0	; Test 1 Seconds

TIM2MIC		DW	0	; Test 2 Microseconds
TIM2MIL		DW	0	; Test 2 Milliseconds
TIM2SEC		DW	0	; Test 2 Seconds

TIM3MIC		DW	0	; Test 3 Microseconds
TIM3MIL		DW	0	; Test 3 Milliseconds
TIM3SEC		DW	0	; Test 3 Seconds

TIM4MIC		DW	0	; Test 4 Microseconds
TIM4MIL		DW	0	; Test 4 Milliseconds
TIM4SEC		DW	0	; Test 4 Seconds

COUNT_MAX	DW	65535	; Starting point
ADJUSTM		DW	0	; Compensating Factor
TIM_CONV	DW	8381	; 838.096 nsec/tick
COUNT_CONV	DW	54925	; 54.925 msec/tick
TEN_TH		DW	10000	; Divisor 1
FIVE_TH		DW	5000	; Divisor 2
THOU		DW	1000	; Divisor 3
TEN		DW	10	; Divisor 4
INTERLEAVE	DB	16	; Interleave Count
INTLVE		DB	0	; Optimum Interleave
LOWMIC		DW	0FFFFH
LOWMIL		DW	0FFFFH
LOWSEC		DW	0FFFFH
ANSYN		DB	'YYN',13
ANSCD		DB	'CCD',13
DR_ID		DB	80H

;-------------------
;  Message Area
;-------------------
SIGN_ON		DB	'ЩЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЛ',13
		DB	'К       CUMANA - Fixed Disk Installation and Optimisation - Version 1.20       К',13
		DB	'К       пппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп       К',13
		DB	'К                                                                              К',13
		DB	'К      This Program is designed to set up a Fixed Disk Unit from scratch.      К',13
		DB	'К                                                                              К',13
		DB	'К  Once you have elected to continue, the program will list the settings of    К',13
		DB	'К  the selected drive.    If you accept these settings as correct,  the        К',13
		DB	'К  program will then experimentally format  Cylinders 0 and 1 and time the     К',13
		DB	'К  access for each of 16 interleave values.  Once this process has ended,      К',13
		DB	'К  the whole disk will be formatted at the optimum interleave setting.         К',13
		DB	'К  This ensures that Fixed Disk performance will be efficiently matched to     К',13
		DB	'К  your machine.                                                               К',13
		DB	'К                                                                              К',13
		DB	'К  When formatting has been completed, you will be asked to enter details      К',13
		DB	'К  of defective areas of the disk.  These are usually written on the disk      К',13
		DB	'К  itself or the relevant documentation.  Make a note of the Cylinders and     К',13
		DB	'К  Heads involved BEFORE you run the program, so that you don',39,'t need to        К',13
		DB	'К  move the disk while it is in operation.  Cylinder numbers should be         К',13
		DB	'К  entered in decimal notation.   Upon correct completion, the program will    К',13
		DB	'К  Reboot to establish the Drive and then continue with software installation. К',13
		DB	'К                                                                              К',13
		DB	'К  Press a Key when you are ready to continue ...                              К',13
		DB	'ШЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭМ',13,'$'

MESS_01		DB	'WARNING !!!  This program will ERASE all data on the selected drive!',13,10
		DB	'К Do you want to continue?  [N]$'
MESS_AVE	DB	' $'
MESS_SEC	DB	' Seconds$'
MESS_MIL	DB	'.$'
MESS_MIC	DB	' $'
MESS_RUN	DB	'Interleave '
MESS_EQ		DB	'   timed at $'
ASC_STR		DB	5 DUP('d'),'$'
BLANKLINE	DB	'                                                                            $'
LF		DB	13,10,'К $'
BELL		DB	7,'$'
MESS_OPT0	DB	'Optimising Interleave - $'
MESS_OPT1	DB	'Optimum Interleave is '
MESS_OPT2	DB	'    ',13,10,'К $'
MESS_OPT3	DB	' FORMATTING DRIVE '
MESS_OPT4	DB	'C'
		DB	'  with Interleave $'
MESS_OPT5	DB	'Any Bad Tracks to Enter? [N]$'
MESS_OPT6	DB	'Enter Cylinder Number (Decimal) ... $'
MESS_OPT7	DB	'Enter Head Number  ................ $'
MESS_OPT8	DB	'Bad Track Flagged!      Any more Bad Tracks? [N]$'
MESS_OPT9	DB	'Format Completed                         ',13,10,10,'К $'
MESS_OPT10	DB	'Entering Bad Track information ... ',13,10,'$'
DUFF_CONT	DB	'DISK CONTROLLER ERROR REPORTED!',13,10
		DB	'Please check Controller Cables and Connections.',13,10,'$'
LOG_PART	DB	'The Controller indicates that the Drive is set for LOGICAL PARTIONING ',13,10
		DB	'К This program cannot handle Logical Formatting - please us the ROM routine.',13,10,10,'$'
SELECT1		DB	'Select Drive to Format (C or D) [C]$'
DR_REPP		DB	'Selected Drive has these Settings ...',13,10,10
		DB	'К $'
DR_CYL		DB	'      Number of CYLINDERS ... : $'
DR_HDS		DB	'      Number of HEADS ....... : $'
CYLS		DW	00
HDS		DB	0		
ABORT		DB	13,10,'К Returning to Operating System ...',13,10,'$'
CONTINUE	DB	13,10,'К Writing Partition Table ...'
		DB	13,10,'К Rebooting to establish Drive'
		DB	10,10,10,10,10,10,10,10,13,'$'
CONFIRM		DB	'Are these correct? [Y]$'
BADCYL		DB	13,10,'К Invalid Cylinder Number!$'
BADHD		DB	13,10,'К Invalid Head Number!$'
		DB	'Author Jim Bates - BATES Associates'
	
	ASSUME	CS:CODE, DS:CODE, ES:CODE

SET_BADTRAK:
	MOV	DH,AL
	MOV	DL,BYTE PTR CS:[DR_ID]
	XCHG	BH,BL
	MOV	CX,6
	SHL	BL,CL
	ADD	BX,1
	MOV	CX,BX
	MOV	AX,601H
	INT	13H
	RET

GETNUM:
	mov	cl,30H
	mov	ch,cl
	mov	dx,cx
	mov	bl,0
GETNUM00:
	mov	ah,1
	int	21H
	cmp	al,0DH
	jnz	GETNUM01
	cmp	bl,0
	jnz	GETNUM07
	mov	ch,2
	ret	

GETNUM01:
	cmp	al,8
	jz	GETNUM05
	inc	bl
	cmp	bl,4
	ja	GETNUM02
	mov	dh,dl
	mov	dl,ch
	mov	ch,cl
	mov	cl,al
	jmp	GETNUM00
GETNUM02:
	mov	bh,0
GETNUM03:
	mov	dl,8
	mov	ah,2
	int	21H
	dec	bl
	cmp	bl,0
	jnz	GETNUM03
	cmp	bh,1
	jz	GETNUM
GETNUM04:
	mov	dl,20H
	mov	ah,2
	int	21H
	inc	bl
	cmp	bl,4
	jbe	GETNUM04
	inc	bh
	jmp	GETNUM03
GETNUM05:
	push	dx
	mov	dl,20H
	mov	ah,2
	int	21H
	cmp	bl,0
	jz	GETNUM06
	mov	dl,8
	mov	ah,2
	int	21H
	pop	dx
	mov	cl,ch
	mov	ch,dl
	mov	dl,dh
	mov	dh,30      ;"0"
	dec	bl
	jmp	GETNUM00
GETNUM06:
	pop	dx
	jmp	GETNUM00
GETNUM07:
	mov	bl,0AH
	mov	al,39H
	cmp	cl,al
	jg	GETNUM08
	cmp	ch,al
	jg	GETNUM08
	cmp	dl,al
	jg	GETNUM08
	cmp	dh,al
	jg	GETNUM08
	mov	al,30H
	sub	cl,al
	jc	GETNUM08
	sub	ch,al
	jc	GETNUM08
	sub	dl,al
	jc	GETNUM08
	sub	dh,al
	jc	GETNUM08
	mov	al,dh
	mov	ah,0
	mul	bl
	mov	dh,0
	add	ax,dx
	mul	bl
	mov	dl,ch
	add	ax,dx
	mul	bl
	mov	dl,cl
	add	ax,dx
	mov	ch,0
	ret	
GETNUM08:
	mov	ch,2
	ret	


PRTDX:	PUSH	DS
	MOV	AX,CS
	MOV	DS,AX
	DISPLAY
	POP	DS
	RET	

RINGBELL:
	MOV	DX,OFFSET [BELL]
	CALL	PRTDX
	RET	

BACK2:	
	PUSH	AX
	PUSH	BX
	PUSH	DX
	PUSH	SI
	MOV	BH,0
	MOV	AH,3	; Get Cursor into DX
	INT	10H
	SUB	DL,2
	MOV	AH,2	; Set Cursor from DX
	INT	10H
	POP	SI
	POP	DX
	POP	BX
	POP	AX
	RET

GETANS:			; Set DI to point to required ANS string
	PUSH	ES
	PUSH	SI
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CLD
	PUSH	CS
	POP	ES
	PUSH	DI
G1:
	POP	DI
	PUSH	DI
	MOV	AH,8
	INT	21H
	AND	AL,0DFH	; Convert to Upper Case
	MOV	CX,4
	REPNZ	SCASB 
	JNZ	G1
	CMP	AL,0DH
	JZ	G2
	MOV	BH,0
	MOV	CX,1
	MOV	AH,0AH	; Show Character
	INT	10H
	JMP	G1
G2:
	POP	DI
	MOV	BH,0
	MOV	AH,8	; Get Character at Cursor
	INT	10H
	PUSH	AX
	CALL	GETCURS
	INC	DH
	MOV	DL,2
	CALL	SETCURS	; to Next Line col 3
	POP	AX
	POP	DX
	POP	CX
	POP	BX
	POP	SI
	POP	ES
	RET

GETCHARE:
	MOV	AH,1
	INT	21H
	RET	

GETCHAR:
	MOV	AH,8
	INT	21H
	RET	

GETCURS:
	PUSH	CX
	PUSH	AX
	PUSH	BX
	PUSH	SI
	MOV	AH,3
	MOV	BH,0
	INT	10H
	POP	SI
	POP	BX
	POP	AX
	POP	CX
	RET	

SETCURS:
	PUSH	AX
	PUSH	BX
	PUSH	CX
	PUSH	SI
	MOV	AH,2
	MOV	BH,0
	INT	10H
	POP	SI
	POP	CX
	POP	BX
	POP	AX
	RET	

GET_STATUS:
	PUSH	AX
	PUSH	DX
	CALL	GET_PORT_OFFSET
	IN	AL,DX
	AND	AL,80H
	CMP	AL,80H
	POP	DX
	POP	AX
	RET	

GET_PORT_OFFSET:
	PUSH	BX
	MOV	BX,77H
	MOV	BL,BYTE PTR [BX]
	XOR	BH,BH
	MOV	DX,322H
	ADD	DX,BX
	POP	BX
	RET	

HEX2ASC:
	push	bx
	push	cx
	push	dx
	push	si
	mov	bx,42H
	mov	WORD PTR [bx],2020H
	mov	WORD PTR [bx+02],2020H
	mov	WORD PTR [bx+04],2020H
	mov	bx,4
	mov	cx,0AH
CLRS1:
	xor	dx,dx
	div	cx
	add	dl,30H      ;"0"
	mov	si,42H
	mov	[bx+si],dl
	dec	bx
	cmp	ax,0
	jnz	CLRS1
	pop	si
	pop	dx
	pop	cx
	pop	bx
	ret	

SET_STAT:
	push	ax
	push	dx
	push	es
	call	GET_PORT_OFFSET
	in	al,dx
	call	GET_STATUS
	jc	STST
	push	bx
	mov	bx,43H
	mov	ah,[bx]
	pop	bx
	and	ah,20
	jz	STST
	mov	cl,4
	shr	al,cl
STST:
	mov	cl,4
	and	al,7
	shl	al,cl
	xor	ah,ah
	push	ax
	push	ds
	push	es
	push	ax
	mov	ax,0
	mov	ds,ax
	pop	ax
	mov	bx,104H
	push	ax
	mov	ax,0
	mov	es,ax
	pop	ax
	mov	bx,es:[bx]
	pop	es
	pop	ds
	pop	ax
	add	bx,ax
	pop	es
	pop	dx
	pop	ax
	ret	

SETBLANK:
	mov	si,42H
	mov	cx,5
STB1:
	mov	al,[si]
	cmp	al,20H      ;" "
	jnz	STB2
	inc	si
	dec	cx
	jmp	STB1
STB2:
	ret	

SHOWNUM:
	MOV	DL,[SI]
	MOV	AH,2
	INT	21H
	INC	SI
	LOOP	SHOWNUM
	RET
	

;###

TIM_START:		; Start Clock 
	PUSH	AX
	PUSH	DX
	PUSH	DS
	MOV	TIM_MICRO,0	; Clear area for final results
	MOV	TIM_MILLI,0	;
	MOV	TIM_SEC,0	;
	
	;Initialise counter 0 of 8253 chip
	 
	MOV	AL,00110100B	; Set mode for Counter 0
	CLI
	OUT	TIM_MODE,AL
	SUB	AX,AX		; Set Counter at Zero
	OUT	TIM_0,AL	; LSB
	OUT	TIM_0,AL	; MSB
	MOV	DX,BIOS_DSEG	; Read current setting of System Clock
	MOV	DS,DX
	MOV	AX,DS:[TIM_LOW]
	STI
	POP	DS
	MOV	COUNT,AX	; Save it
	POP	DX		; Restore Registers
	POP	AX
	RET

; Elapsed timer since Timer start =
;	1) Timer count ticks @ 840 nSecs
;	2) Interrupt ticks @ 54 mSecs

TIM_STOP:		; Stop Clock
	PUSH	AX
	PUSH	BX
	PUSH	DX
	MOV	AL,0		; Ready to read 8253
	CLI			; Interrupts off until system clock read
	OUT	TIM_MODE,AL	; Set Mode for read
	IN	AL,TIM_0	; Read LSB
	MOV	DL,AL		; Save it
	IN	AL,TIM_0	; Read MSB
	MOV	DH,AL		; Save it
	MOV	AX,COUNT_MAX
	SUB	AX,DX		; Timer Count Value
	MUL	TIM_CONV	; Make to tenths of a nanosecond
	DIV	TEN_TH		; Make to microseconds
	MOV	TIM_MICRO,AX	; Save it
	CMP	DX,FIVE_TH	; Round nanoseconds 
	JB	CONT		; Round down
	INC	TIM_MICRO	; Round up
CONT:	MOV	DX,BIOS_DSEG
	MOV	DS,DX
	MOV	AX,DS:[TIM_LOW]	; Collect System Clock reading
	PUSH	CS
	POP	DX		
	MOV	DS,DX		; Restore DS register
	SUB	AX,COUNT	; System ticks since start
	MUL	COUNT_CONV	; Make to thousandths of millisecond
	DIV	THOU		; Make to milliseconds
	MOV	COUNT_MILLI,AX	; Save millisecs
	MOV	COUNT_MICRO,DX	; Save microsecs
	CMP	AX,0		; Check for elapsed time less than 1 mSec
	JNE	JIT		; If not - no problem
	MOV	AX,ADJUSTM	; Compensation amount
	CMP	TIM_MICRO,AX	; Less than microseconds?
	JAE	JIT		; No - so OK
	MOV	TIM_MICRO,AX	; Yes so use compensation
	
JIT:	MOV	AX,DX		; This is System Microsecs
	ADD	AX,TIM_MICRO	; Add Timer Microsecs
	CMP	AX,ADJUSTM	; any underflow?
	JAE	COMP		; No - so continue
	DEC	COUNT_MILLI	; Yes - so borrow
	ADD	AX,1000	
COMP:	SUB	AX,ADJUSTM	; Apply compensation
	MOV	TIM_MICRO,AX	
	CMP	AX,1000		; any overflow?
	JB	FLDOK		; No - so continue
	SUB	DX,DX		; TIM_MICRO too large!
	DIV	THOU		; so carry into TIM_MILLI
	MOV	TIM_MILLI,AX
	MOV	TIM_MICRO,DX
FLDOK:	MOV	AX,COUNT_MILLI	; Get System milliseconds
	ADD	TIM_MILLI,AX	; Add to timer milliseconds
	CMP	TIM_MILLI,1000	; any overflow
	JB	QUIT		; No - so continue
	SUB	DX,DX		; 
	MOV	AX,TIM_MILLI	; TIM_MILLI too large
	DIV	THOU		; so carry into TIM_SEC
	MOV	TIM_SEC,AX	; Save Seconds
	MOV	TIM_MILLI,DX	; Save Milliseconds

QUIT:	
	POP	DX		; Restore registers
	POP	BX
	POP	AX
	RET

;----------------------------------
;  Decode and Display Time readings
;----------------------------------	
SHOW_AVE:
	PUSH	AX
	PUSH	BX
	PUSH	DX
	LEA	DX,MESS_AVE
	JMP	SHOW0
SHOW:
	PUSH	AX		; Save registers
	PUSH	BX
	PUSH	DX
	LEA	DX,MESS_RUN	; Display Seconds Message
SHOW0:	CALL	PRTDX
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_SEC	; Get Value of Seconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	MOV	DX,BX		; Transfer pointer
	CALL	PRTDX			; Display Seconds value
	LEA	DX,MESS_MIL	; Display Decimal point
	CALL	PRTDX
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_MILLI	; Get Value of Milliseconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	LEA	DX,ASC_STR+2	; Point to last three digits
	CALL	PRTDX			; Display Milliseconds Value
	LEA	DX,MESS_MIC	; Display comma
	CALL	PRTDX
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_MICRO	; Get Value of Microseconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	LEA	DX,ASC_STR+2	; Point to last three digits
	CALL	PRTDX			; Display Microseconds value
	LEA	DX,MESS_SEC
	CALL	PRTDX
	POP	DX		; Restore registers
	POP	BX
	POP	AX
	RET

;--------------------------------------------
;    Binary to ASCII conversion into ASC_STR
;--------------------------------------------
;    Value to be converted is passed in AX and written to ASC_STR

BIN2ASC:
	PUSH	DX			; Save registers
	PUSH	CX
	PUSH	AX
	MOV	CX,5			; Clear ASC_STR
CLBUF:	MOV	BYTE PTR [BX],30H	; Put zeroes in
	INC	BX
	LOOP	CLBUF
CONV:	SUB	DX,DX			; Clear upper half of dividend
	DIV	TEN			; = (DX:AX)/10
	ADD	DX,30H			; Convert to ASCII
	DEC	BX			; bump pointer
	MOV	[BX],DL			; Save digit
	OR	AX,AX			; Check if finished?
	JNZ	CONV			; No - go again!
	POP	AX			; Restore registers
	POP	CX
	POP	DX
	RET

;------------------------
;  CONVERT TIME TO ASCII
;-----------------------

TIM2ASC:
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_SEC	; Get Value of Seconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_MILLI	; Get Value of Milliseconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	LEA	BX,ASC_STR	; Point to ASC_STR area
	MOV	AX,TIM_MICRO	; Get Value of Microseconds
	CALL	BIN2ASC		; Convert from binary to ASCII
	RET
;------------------------
;  MAIN CODE    XXXXX
;------------------------	
	

START:
	MOV	AX,600H
	MOV	CX,0
	MOV	DX,184FH
	MOV	BH,1FH
	INT	10H
	MOV	DX,0
	CALL	SETCURS	
	LEA	DX,SIGN_ON	; Display Sign-on Message
	CALL	PRTDX		; Prints frame
	MOV	AH,01
	INT	21H
	MOV	AX,600H
	MOV	CX,0302H
	MOV	DX,164DH
	MOV	BH,1FH
	INT	10H
	
	MOV	AX,40H
	MOV	DS,AX
	MOV	AX,0		; Reset Fixed Drive 1
	MOV	DX,0
	MOV	DL,80H
	MOV	CX,1
	INT	13H
	MOV	DX,0402H
	CALL	SETCURS
	MOV	AH,14H		; Controller Diagnostics
	MOV	DL,80H
	INT	13H
	JNC	START1
	LEA	DX,DUFF_CONT	; Controller Faulty
	CALL	PRTDX
QQQ:
	LEA	DX,ABORT
	CALL	PRTDX
	MOV	AX,4C01H
	INT	21H		; END
;==========================  
START1:

	PUSH	CS
	POP	DS
	CLI
	CALL	TIM_START	; Start the Clock
	CALL	TIM_STOP	; Stop the Clock
	STI
	MOV	DX,TIM_MICRO	; Read elapsed time (overhead)
	MOV	ADJUSTM,DX	; Save as compensation factor

	LEA	DX,MESS_01	; Show Warning Message
	CALL	PRTDX
	CALL	BACK2
	LEA	DI,ANSYN
	CALL	GETANS
	CMP	AL,'Y'
	JZ	DRSEL		; Answer was 'Y'
	JMP	QQQ
DRSEL:		
	MOV	AX,40H
	MOV	DS,AX
	MOV	BX,75H		; How many H Disks?
	CMP	BYTE PTR [BX],2 
	JZ	DRSEL01		; 2 Drives so Select
	MOV	AL,0		; 1 Drive so Jump
	JMP	SRSEL03 
DRSEL01:
	CALL	GET_STATUS
	JC	DRSEL02		; Logical Partitioning Set Up
	JMP	SRSEL01
DRSEL02:
	LEA	DX,LOG_PART
	CALL	PRTDX
	JMP	QQQ

SRSEL01:
	LEA	DX,SELECT1
	CALL	PRTDX
	CALL	BACK2
	LEA	DI,ANSCD
	CALL	GETANS
	CMP	AL,'C'
	JZ	SRSEL02
	MOV	AL,0
	MOV	BYTE PTR CS:[DR_ID],81H
	MOV	BYTE PTR CS:[MESS_OPT4],44H
	JMP	SRSEL03
SRSEL02:
	MOV	AL,20H
SRSEL03:
	MOV	BX,43H
	MOV	[BX],AL
	call	GET_STATUS
	jnc	DRREP1
	mov	bx,43H
	cmp	BYTE PTR [BX],60H
	jz	DRREP1
	JMP	DRSEL02
DRREP1:
	LEA	dx,DR_REPP
	call	PRTDX
	call	SET_STAT
	MOV	AX,800H
	MOV	DX,0
	MOV	DL,BYTE PTR CS:[DR_ID]
	INT	13H			;CH=62H  CL=1 0010001
	INC	DH
	MOV	CS:[HDS],DH		; Number of Heads
	MOV	AX,CX
	MOV	CX,6
	SHR	AL,CL
	XCHG	AH,AL
	ADD	AX,2
	MOV	CS:[CYLS],AX
	PUSH	AX
	LEA	DX,DR_CYL
	CALL	PRTDX
	POP	AX
	CALL	HEX2ASC	
	CALL	SETBLANK
	CALL	SHOWNUM
	LEA	DX,LF
	CALL	PRTDX
	LEA	DX,DR_HDS
	CALL	PRTDX
	SUB	AX,AX
	MOV	AL,CS:[HDS]
	CALL	HEX2ASC	
	CALL	SETBLANK
	CALL	SHOWNUM
	CALL	GETCURS
	INC	DH
	INC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,CONFIRM
	CALL	PRTDX
	CALL	BACK2
	LEA	DI,ANSYN
	CALL	GETANS
	CMP	AL,'Y'
	JZ	FMTCMD0
	JMP	QQQ
FMTCMD0:
	LEA	DX,MESS_OPT0
	CALL	PRTDX

FMTCMD:
	PUSH	CS
	POP	DS
	MOV	CX,2		; Two Tracks to FORMAT
FMTRAKS:
	PUSH	CX		; Save track count
	MOV	AL,CL		; Use it to mark Track
	DEC	AL
	MOV	CX,4		; Four Heads to use
FMTRAK:
	PUSH	CX		; Save Head Count
	PUSH	AX		; Save Track indicator
	MOV	DH,CL		; Set Head number
	DEC	DH
	MOV	CH,AL		; CYL NO.
	MOV	AH,05H		; Format command
	MOV	AL,BYTE PTR [INTERLEAVE]
	MOV	BX,OFFSET DTABUF
	MOV	CL,1		; SECT=1
	MOV	DL,BYTE PTR [DR_ID]	; Drive
	INT	13H
	POP	AX
	POP	CX
	LOOP	FMTRAK
	POP	CX
	LOOP	FMTRAKS

;--------------------------------------------------
; Each of the following loops sets the Disk Head to a position,
; Starts the clock, resets the Disk Head and then stops the clock.
; The subsequent time is then converted and displayed.
;--------------------------------------------------
; This runs the Disk test routine 8 times and places the
; successive results in TIM1 to TIM8 Data Words
;--------------------------------------------------

	IRP	?X,<1,2,3,4>
	HEADSET	0,0	
	CLI
	CALL	TIM_START
	HEADSET	3,310
	CALL	TIM_STOP
	STI
	CALL	TIM2ASC
	MOV	SI,OFFSET TIM_MICRO
	MOV	DI,OFFSET TIM&?X&MIC
	MOV	CX,6
	REP	MOVSB
	ENDM

;--------------------------------------------------
; Now we must average out the 8 test results obtained
; and put the answer back into TIM_MICRO +++
;--------------------------------------------------

	SUB	AX,AX			; Clear AX for addition
	
	IRP	?X,<1,2,3,4>
	ADD	AX,DS:[TIM&?X&MIC]
	ENDM

	MOV	TIM_MICRO,AX
;--------------------------------------------------

	SUB	AX,AX			; Clear AX for addition
	
	IRP	?X,<1,2,3,4>
	ADD	AX,DS:[TIM&?X&MIL]
	ENDM

	MOV	TIM_MILLI,AX
;--------------------------------------------------

	SUB	AX,AX			; Clear AX for addition
	
	IRP	?X,<1,2,3,4>
	ADD	AX,DS:[TIM&?X&SEC]
	ENDM

	MOV	DX,0
	MUL	THOU
	ADD	AX,[TIM_MILLI]
	JNC	NEXT1
	INC	DX
NEXT1:
	MUL	THOU
	ADD	AX,[TIM_MICRO]
	JNC	NEXT2
	INC	DX
NEXT2:
	SHR	DX,1
	RCR	AX,1
	SHR	DX,1
	RCR	AX,1
			; Now DX:AX contains binary number of Microsecs
	DIV	THOU
	MOV	[TIM_MICRO],DX
	XOR	DX,DX
	DIV	THOU
	MOV	[TIM_MILLI],DX
	MOV	[TIM_SEC],AX		

	CMP	[LOWSEC],AX
	JC	LBL2
	CMP	[LOWMIL],DX
	JC	LBL2
	MOV	[LOWMIL],DX
	MOV	[LOWSEC],AX
	MOV	AX,WORD PTR [INTERLEAVE]
	MOV	WORD PTR [INTLVE],AX
LBL2:	
	MOV	AL,BYTE PTR [INTERLEAVE]
	AAM
	OR	AX,3030H
	XCHG	AH,AL
	MOV	WORD PTR [MESS_EQ],AX
	CALL	GETCURS
	PUSH	DX
	LEA	DX,MESS_RUN	; Display Seconds Message
	CALL	PRTDX
	CALL	SHOW_AVE		; Display Average time
	POP	DX
	CALL	SETCURS
	DEC	BYTE PTR [INTERLEAVE]
	JZ	FINISH
	JMP	FMTCMD
FINISH:
	CALL	GETCURS
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,BLANKLINE
	CALL	PRTDX
	CALL	GETCURS
	MOV	DL,2
	CALL	SETCURS
	MOV	AL,BYTE PTR [INTLVE]
	AAM
	OR	AX,3030H
	XCHG	AH,AL
	MOV	WORD PTR [MESS_OPT2],AX
	LEA	DX,MESS_OPT1		; Display IntLve Message
	CALL	PRTDX
	CALL	GETCURS
	INC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,MESS_OPT3
	CALL	PRTDX
	LEA	DX,MESS_OPT2
	CALL	PRTDX	
	MOV	AL,BYTE PTR [INTLVE]
	MOV	DH,0
	MOV	DL,BYTE PTR [DR_ID]
	MOV	CX,1
	MOV	AH,7
	INT	13H		; Drive Formatted HERE
	CALL	GETCURS
	MOV	DL,2
	DEC	DH
	CALL	SETCURS
	LEA	DX,MESS_OPT9	; Format Complete
	CALL	PRTDX
TEST:
	LEA	DX,MESS_OPT5	; Bad Tracks? N       Line 1
	CALL	PRTDX
	CALL	BACK2
	LEA	DI,ANSYN
	CALL	GETANS
	CMP	AL,'Y'
	JZ	BAD_TRAKS00
	JMP	QQQ1

BAD_TRAKS00:
	CALL	GETCURS
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,MESS_OPT6	; Enter Track		Line 2
	CALL	PRTDX
	CALL	GETNUM	
; TEST AX FOR VALID CYLINDER
	CMP	AX,WORD PTR CS:[CYLS]
	JC	CYLOK
	CALL	RINGBELL
	LEA	DX,BADCYL
	CALL	PRTDX
	CALL	GETCURS
	DEC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,BLANKLINE
	CALL	PRTDX
	JMP	BAD_TRAKS00
CYLOK:	
	push	ax
CYLOK1:
	CALL	GETCURS
	INC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,MESS_OPT7	; Enter Head		Line 3
	CALL	PRTDX
	CALL	GETNUM
; TEST AX FOR VALID HEAD NUMBER	
	CMP	AL,BYTE PTR CS:[HDS]
	JC	HDOK
	CALL	RINGBELL
	LEA	DX,BADHD
	CALL	PRTDX
	CALL	GETCURS
	DEC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,BLANKLINE
	CALL	PRTDX
	CALL	GETCURS
	DEC	DH
	MOV	DL,2
	CALL	SETCURS
	JMP	CYLOK1
HDOK:
; AX HAS HEAD NUMBER, STACK HAS CYLINDER NUMBER
; FORMAT BAD TRACK
	POP	BX
	CALL	SET_BADTRAK
	CALL	GETCURS
	INC	DH
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,MESS_OPT8	; Track Flagged - MORE?   Line 4
	CALL	PRTDX
	CALL	BACK2
	LEA	DI,ANSYN
	CALL	GETANS
	CMP	AL,'Y'
	JZ	BAD_TRAKS01
	JMP	QQQ1

BAD_TRAKS01:
	CALL	GETCURS
	MOV	DL,2
	MOV	CX,5

BAD_TRAKS02:	
	PUSH	CX
	CALL	SETCURS
	LEA	DX,BLANKLINE
	CALL	PRTDX
	CALL	GETCURS
	DEC	DH
	MOV	DL,2
	POP	CX
	LOOP	BAD_TRAKS02
	CALL	GETCURS
	MOV	DL,2
	CALL	SETCURS
	LEA	DX,MESS_OPT10
	CALL	PRTDX
	JMP	BAD_TRAKS00
QQQ1:
	LEA	DX,CONTINUE
	CALL	PRTDX
; set up variables in BOOT_TRAK buffer and DX before writing Partition Table

	DEC	CYLS
	DEC	CYLS
	MOV	AX,[CYLS]
	MOV	CX,6
	SHL	AH,CL
	OR	AH,11H
	XCHG	AH,AL
	MOV	[XSECTS],AX	
	INC	CYLS
	MOV	AL,44H
	CBW
	MUL	CYLS
	SUB	AX,11H
	MOV	XSEC_END,AX
	MOV	AX,301H
	MOV	BX,OFFSET BOOT_TRAK
	MOV	DX,0
	MOV	DL,BYTE PTR [DR_ID]
	MOV	CX,1
	INT	13H

	MOV	AX,40H
	MOV	DS,AX
	INT	19H		; Terminate program and Reboot

BOOT_TRAK:
	DB	0EBH,74H,90H,49H,6EH,76H,61H,6CH,69H,64H
	DB	20H,70H,61H,72H,74H,69H,74H,69H,6FH,6EH
	DB	20H,74H,61H,62H,6CH,65H,20H,6FH,6EH,20H
	DB	66H,69H,78H,65H,64H,20H,64H,69H,73H,6BH
	DB	0DH,0AH,00H,4EH,6FH,20H,6FH,70H,65H,72H
	DB	61H,74H,69H,6EH,67H,20H,73H,79H,73H,74H
	DB	65H,6DH,20H,6FH,6EH,20H,66H,69H,78H,65H
	DB	64H,20H,64H,69H,73H,6BH,0DH,0AH,00H,45H
	DB	72H,72H,6FH,72H,20H,6CH,6FH,61H,64H,69H
	DB	6EH,67H,20H,73H,79H,73H,74H,65H,6DH,20H
	DB	66H,72H,6FH,6DH,20H,66H,69H,78H,65H,64H
	DB	20H,64H,69H,73H,6BH,0DH,0AH,00H,0FAH,0FCH
	DB	33H,0C0H,8EH,0D8H,8EH,0C0H,8EH,0D0H,0BCH,00H
	DB	7CH,0BEH,00H,7CH,0BFH,00H,7EH,0B9H,00H,02H
	DB	0F3H,0A4H,0B8H,0E0H,07H,50H,0B8H,97H,00H,50H
	DB	0CBH,0FBH,0BFH,03H,00H,0BBH,0BEH,7FH,0B9H,04H
	DB	00H,2BH,0F6H,80H,3FH,00H,74H,0BH,80H,3FH
	DB	80H,75H,12H,0BH,0F6H,75H,0EH,8BH,0F3H,83H
	DB	0C3H,10H,0E2H,0EBH,0BFH,2BH,00H,0BH,0F6H,75H
	DB	03H,0EBH,2BH,90H,8BH,14H,8BH,4CH,02H,0BBH
	DB	00H,7CH,0BDH,03H,00H,0B0H,01H,0B4H,02H,0CDH
	DB	13H,73H,09H,4DH,75H,0F5H,0BFH,4FH,00H,0EBH
	DB	0FH,90H,0BFH,2BH,00H,81H,0BFH,0FEH,01H,55H
	DB	0AAH,75H,03H,1EH,53H,0CBH,2EH,8AH,05H,47H
	DB	3CH,00H,74H,09H,0BBH,07H,00H,0B4H,0EH,0CDH
	DB	10H,0EBH,0EFH,0EBH,0FEH
	DB	239 DUP (0)
	DB	80H,01H,01H,00H,04H,03H

XSECTS		DW	6291H
		DB	11H,00H,00H,00H
XSEC_END	DW	0A23BH
		DB	00H,00H,55H,0AAH
	
DTABUF	DW	4 DUP (?)



MAIN	ENDP
CODE	ENDS
END	BEGIN
			
		

