;HDFORMX/ASM - LDOS 5.1 or 6.x - 04/29/83
;*=*=*
;       Change Log
;Moved all system routines to end
;For easier 5.1/6.x compatibility -LM
;Put WD FORMAT code here instead of in driver
;Update system DCT for DIR cyl when done-04/26/83
;*=*=*
	IF	RAM
	ORG	2400H
	ELSE
	ORG	5400H
BEGIN	EQU	$
	ENDIF
;*****
;       FORMAT routine entry point
;*****
USER	PUSH	HL		;Save cmdline ptr
	LD	HL,HELLO$	;Log on
	CALL	@DSPLY		;Hello message
	POP	HL		;Rcvr ptr to cmdline
;*=*=*
;       Grab any parameters
;*=*=*
	PUSH	HL		;Save again
	DEC	HL
FNDPRN	INC	HL
	LD	A,(HL)
	CP	CR+1		;End of line?
	JR	C,FMT1		;No parms
	CP	'('
	JR	NZ,FNDPRN
	LD	DE,PARMTBL	;Parse any parameters
	CALL	@PARAM
	JP	NZ,PRMERR	;Jump on parm error
;*=*=*
;       Scan for drivespec on command line
;*=*=*
FMT1	POP	HL		;Cmd line again
	LD	A,(HL)		;Ignore spaces
	INC	HL
	CP	20H
	JR	Z,FMT1
	CP	':'		;Colon drive indicator?
	JR	NZ,WHDRV
	LD	A,(HL)		;P/u drive #
	SUB	'0'		;Cvrt to ASCII
	JP	C,PRMERR	;0 or larger
	CP	8		;Make sure not > 7
	JP	NC,PRMERR
	LD	(DISKIO+1),A	;Stuff drive
	JR	FMT2		;Don't ask
;*****
;       Drive not entered, prompt for it
;*****
WHDRV1	CALL	ABTJCL		;No reprompt if JCL
WHDRV	LD	HL,WHDRV$	;"which drive...
	CALL	GETARG		;Get one char
	SUB	'0'		;Cvrt to binary
	JP	C,WHDRV1	;Error if < 0
	CP	8		;Error if > 7
	JP	NC,WHDRV1
	LD	(DISKIO+1),A	;Stuff drive
;*=*=*
;       Get the DCT of the requested drive
;*=*=*
FMT2	OR	A
	JP	Z,NOTZER	;Can't do logical 0
	LD	C,A		;Set in drive register
	CALL	GETDCT@		;Find DCT pointer
	PUSH	IY
	POP	HL		;Put in HL
	LD	A,(HL)		;Be sure enabled
	CP	0C9H		; a RET?
	JP	Z,ILLEG		;Quit if disabled
	LD	(DCTPTR),HL	;Save for later
	LD	DE,FMTDCT	;Move SYSTEM DCT into
	PUSH	DE
	LD	BC,10		;  FORMAT's buffer so we
	LDIR			;  don't update the SYS
	POP	IY		;Use for FORMAT
;
	IF	MTI!LSI!ARM!TRS!PDC
;*=*=*
;       This format only for hard drive - check it
;*=*=*
	BIT	3,(IY+3)	;Check if hard drive
	ENDIF
;
	IF	LDI
;*=*=*
;       This format only for alien drive - check it
;*=*=*
	BIT	4,(IY+4)	;Check if alien drive
	ENDIF
;
	JP	Z,NOTHARD	;Only HD format allowed
	LD	L,(IY+1)	;Check if on HD driver
	LD	H,(IY+2)	;  compatible with this
	INC	HL		;  version of FORM...
	INC	HL		;Bump to start of name
	INC	HL
	INC	HL
	LD	DE,FORM$-1	;Pt to which version
	LD	B,3		;Check 3 bytes
CKVER	INC	HL
	INC	DE
	LD	A,(DE)		;Check if driver name
	CP	(HL)		;  is this version's
	JP	NZ,DIFDVR	;Go if wrong version
	DJNZ	CKVER
;*=*=*
;       Check on Pack Name entry
;*=*=*
NPARM	LD	HL,0		;Test if user entered
	LD	A,H		;  the NAME parameter
	OR	L
	JR	Z,DSKNAM	;Go if not
	INC	A		;Was it just NAME?
	JR	Z,DSKNAM	;Go if just NAME
	LD	DE,GATBUF+0D0H	;Yes, move name to field
	LD	B,8		;8-chars max
MOVNAM	LD	A,(HL)		;P/u a char
	CP	'"'		;Closing "
	JR	Z,CKNAME	;Exit if end of parm
	CP	20H		;Permit all but controls
	JP	C,CKNAME
	CP	'a'
	JR	C,MOVNAM1
	CP	'z'+1
	JR	NC,MOVNAM1
	XOR	20H		;Turn off lc
MOVNAM1	LD	(DE),A
	INC	HL
	INC	DE
	DJNZ	MOVNAM
	JR	CKNAME
;*****
;       Prompt user for name parameter
;*****
DSKNAM1	CALL	ABTJCL
DSKNAM	LD	HL,DSKNAM$	;"diskette name?
	LD	B,8
	CALL	GETARGX
	JR	Z,DSKNAM1	;Reprompt if none entered
	LD	C,B		;Only move to name field
	LD	B,0		;  how many were entered
	LD	DE,GATBUF+0D0H
	LDIR
CKNAME	LD	DE,GATBUF+0D0H
	CALL	CKMPW0
	JP	NZ,BADNAM
;*=*=*
;       Get today's date
;*=*=*
GETDAT	LD	HL,GATBUF+0D8H	;Get today's date & stuff
	CALL	@DATE
;*=*=*
;       Check master password entry
;*=*=*
MPWPARM	LD	HL,0		;Did user enter the MPW?
	LD	A,H
	OR	L
	JR	Z,MPW		;Go prompt if not
	INC	A		;Test if just MPW
	JR	Z,MPW		;Go if just MPW
	LD	DE,MPWBUF	;Shift to pswd field
	LD	B,8
MOVMPW	LD	A,(HL)
	CP	30H		;No spaces permitted
	JR	C,PRSMPW	;End also on closing "
	CP	'a'		;Need cvrt to UC?
	JR	C,MOVMPW1
	CP	'z'+1
	JR	NC,MOVMPW1
	RES	5,A		;Cvrt to UC
MOVMPW1	LD	(DE),A
	INC	DE
	INC	HL
	DJNZ	MOVMPW
	JR	PRSMPW
; ****
;       Prompt for master password
;*****
MPW1	CALL	ABTJCL
MPW	LD	HL,MPW$		;"master...
	CALL	INPMPW
	JR	Z,MPW1		;Re-prompt on no entry
;*****
;       Parse the password & stuff into GAT sector buf
;*****
PRSMPW	LD	DE,MPWBUF
	CALL	CKMPW		;Check for valid MPW
	JR	NZ,MPW1		;Invalid entry
	LD	(GATBUF+0CEH),HL	;Stuff it
;*****
;       Routine to galculate the # of grans per logical
;       cylinder so that the GAT byte can be constructed
;*****
CALCGPC	LD	A,(IY+8)	;P/u # of grans per cyl
	RLCA			;Rotate to bits 0-2
	RLCA
	RLCA
	AND	7		;Strip off other data
	INC	A		;Adj for zero offset
;*=*=*
;       If double cylindering, double the count
;*=*=*
	BIT	5,(IY+4)	;Double?
	JR	Z,$+3
	ADD	A,A		;Count * 2
	LD	BC,0FFFFH	;Init GAT byte to ones
CGPC1	SLA	B		;Now keep removing low
	DEC	A		;  order bits , 1 bit for
	JR	NZ,CGPC1	;  each available granule
	LD	A,B		;Save the default byte
	LD	(CALC1+1),A	;  for dir test
	LD	HL,GATBUF	;Pt to GAT buffer area
	LD	A,(IY+6)	;P/u highest # cylinder
CGPC2	LD	(HL),B		;Stuff the GAT byte into
	INC	L		;  each position of the
	CP	L		;  Gat, one byte per
	JR	NC,CGPC2	;  cylinder
;*=*=*
;       Test if we are at 202 first by ignoring the
;       first two instructions with LD DE,xxxx
;*=*=*
	LD	A,0CBH		;Continue to stuff GAT
	DB	11H		;  until cyl 202
CGPC3	LD	(HL),C
	INC	L
	CP	L
	JR	NZ,CGPC3
;*=*=*
;       Check if this pack is already formatted
;*=*=*
PFMT3	PUSH	IY		;Xfer DCT ptr to HL
	POP	HL		;  & move DCT again
	LD	DE,TMPDCT
	LD	BC,10
	LDIR
;*=*=*
;       May be formatted, is there SYSTEM information?
;*=*=*
	LD	HL,$-$		;NOSTOP entered?
NOSTOP	EQU	$-2		;Via param
	LD	A,H
	OR	L
	JP	NZ,PFMT6	;No testing if set
	LD	HL,HITBUF	;Pt to i/o buffer
	LD	DE,0		;Init to cyl 0, sect 0
	CALL	RDSEC		;Now try to read BOOT
	JP	NZ,PFMT6	;Assume unformatted if err
	LD	HL,HASDAT$	;Init "disk contains data
	CALL	@LOGOT
	LD	HL,NOFMT$	;Init "non-std format
;*=*=*
;       BOOT was read, is there a valid directory pointer
;*=*=*
	LD	A,(HITBUF+2)	;P/u dir cyl # (possible)
	CP	(IY+6)		;Check against max cyl #
	JR	NC,PFMT5	;Go if bigger (or =)
;*=*=*
;       Read the assummed GAT & test it
;*=*=*
	LD	HL,HITBUF
	LD	E,L		;Tricky way to get a zero
	LD	D,A		;Pt to assumed GAT sector
	LD	HL,HITBUF	;Pt to buffer
	CALL	RDSEC		;Read the sector
	CP	6		;Dir errcod returned?
	JR	Z,PFMT4		;Jump if yes & grab data
	LD	HL,CANTRD$	;Init "unreadable dir...
	JR	PFMT5
PFMT4	LD	HL,NODIR$	;Init "non-init dir
	LD	A,(HITBUF+0DAH)	;Check if date field
	CP	'/'		;  is present
	JR	NZ,PFMT5
;*=*=*
;       The directory is readable - request its MPW
;*=*=*
PFMT4A	LD	HL,HITBUF+0D0H
	LD	DE,PACKID$+5	;Move name & date into
	LD	BC,8		;Display message field
	LDIR
	LD	DE,PACKID$+14H
	LD	C,8
	LDIR
	LD	HL,PACKID$
	CALL	@LOGOT		;Log the id field
	CALL	ABTJCL		;Abort if in JCL
;*=*=*
;       User must enter Current Pack's MPW to proceed
;*=*=*
OLDMPW	LD	HL,OLDMPW$	;"What's the old MPW?
	CALL	INPMPW		;Grab user input to match
	JR	Z,OLDMPW
	LD	DE,MPWBUF
	CALL	HASHMPW		;Hash user entry
;*****
;       Routine to test master password for match
;*****
	EX	DE,HL		;Xfer hashed MPW to DE
	LD	HL,(HITBUF+0CEH)	;Else grab pack MPW
	XOR	A		;Clear carry flag
	SBC	HL,DE		;Did user enter pack MPW?
	JP	NZ,BADMPW	;Abort if no match
	JR	PFMT6
;*=*=*
;       The directory was not readable - req assurance
;*=*=*
PFMT5	CALL	@LOGOT		;Log "unreadable...
	CALL	ABTJCL1		;Abort if JCL running
	LD	HL,SURE?$	;"Are you sure?...
	LD	B,3
	CALL	GETARGX		;Give user chance to
	LD	A,(HL)		;  proceed with format
	CP	'Y'
	JP	NZ,FMTABT
;*=*=*
;       OK to format - Shift DCT to work area
;*=*=*
PFMT6	PUSH	IY		;Move drive code table
	POP	DE		;Back into place
	LD	HL,TMPDCT
	LD	BC,10
	LDIR
;*=*=*
;       allow user to lock out tracks manually
;*=*=*
;
	BIT	3,(IY+3)	;Hard drive?
	JP	Z,NOLCT		;Go if floppy
;Calc possible heads and adjust msg
	LD	A,(IY+4)	;Starting head #
	AND	00001111B	;Field
	ADD	A,30H		;ASCII offset
	NOP			;Possible DEC if hd # are
	LD	E,A		;Given starting w/0
	INC	A		;Make number
	LD	D,A		;Save
	LD	(PHYD1$),A	;1st possible head
	LD	A,(IY+7)	;# of heads
	RLCA
	RLCA
	RLCA
	AND	7		;Field
	INC	A		;Real #
	LD	(HDNB),A	;Save
HCLP	INC	E		;Start fm 1st hd # -1
	DEC	A		;Get highest head #
	JR	NZ,HCLP		;By counting
	LD	A,E
	LD	(PHYD2$),A	;
	LD	(HDNBRS),DE	;Save valid range
;
;Set up trk number message
	LD	H,0
	LD	L,(IY+6)	;Trk count to BC
	INC	HL		;Fix offset fm 0
	BIT	5,(IY+4)	;Double?
	JR	Z,ISREAL
	ADD	HL,HL		;*2
ISREAL	DEC	HL		;Back to offset fm 0
	LD	(HTRK),HL
	LD	DE,PHYT1$	;Posn for #
	CALL	HEXDEC		;Stuff ASCII
	JR	LCQUES
;Ask question
LCQUES1	CALL	ABTJCL
LCQUES	LD	HL,LOCK$	;Lock out any...
	CALL	GETARG
	CP	'Y'
	JR	Z,LCHD1		;Yes..
	CP	'N'
	JR	Z,NOLCT		;Skip if not wanted
	JR	LCQUES1
GTPHD	CALL	ABTJCL		;No errors allowed if JCL
LCHD1	LD	HL,PHYHD$	;Which head...
	CALL	GETARG
	LD	HL,$-$		;Range
HDNBRS	EQU	$-2
	CP	H
	JR	C,GTPHD		;Too low
	INC	L
	CP	L
	JR	NC,GTPHD	;Too high
	LD	(LCHD),A	;Save track
	JR	LCTR1
GTPHTR	CALL	ABTJCL
LCTR1	LD	HL,PHYTR$	;Trk #..
	LD	B,3
	CALL	GETARGX
	CALL	DECHEX		;Make binary in BC
	LD	A,B
	OR	C
	JR	Z,GTPHTR	;Can't lock out 0
	LD	HL,$-$
HTRK	EQU	$-2		;Highest trk #
	OR	A
	SBC	HL,BC		;Entered >legal?
	JR	C,GTPHTR	;Number was too high
;
;Convert physical numbers to logical GAT posn
;
	LD	A,(IY+8)
	RLCA
	RLCA
	RLCA
	AND	7
	INC	A
	LD	E,A		;E has grans/cyl (w/o double)
	LD	A,$-$
HDNB	EQU	$-1		;Number of heads
	PUSH	BC
	PUSH	DE		;Save grans/phys cyl
	CALL	DIVEA@		;Grans/head
	POP	DE	
	LD	D,E		;Save grans/phys cyl
	LD	E,A		;Keep grans/phys trk
	POP	HL		;Trk # to HL
	LD	A,(PHYD1$)
	LD	C,A
	LD	A,$-$		;Physical hd #
LCHD	EQU	$-1		;Entered value
	SUB	C		;Minus starting offset
;A=trk offset fm logical start/D=grans/trk/HL=trk to lock
	PUSH	DE
	CALL	MULTEA@		;A=gran offset fm start
	POP	DE
	BIT	5,(IY+4)	;Double tracking?
	JR	Z,N1
	SRA	H
	RR	L		;Div trk # by 2
;HL=>logical trk c set if 1st of pair
	JR	NC,N1		;1st cyl-go
	ADD	A,D		;Else add in a cyls grans
N1	LD	H,GATBUF<-8	;
	LD	B,E		;#grans to lock
	LD	E,(HL)		;Get alloc byte
;A=grans before locked out trk
	DEC	A		;Offset fm 0
OFFS2	INC	A		;Set a bit for each gran
	PUSH	AF
	CALL	SETBIT		;Of the physical track
	POP	AF
	DJNZ	OFFS2
	LD	(HL),E		;And put back GAT byte
	JP	LCQUES		;Ask for more
;
NOLCT	LD	HL,DBL$
	BIT	5,(IY+4)	;Double tracking
	CALL	NZ,@DSPLY	;Notify user
	PAGE
;
