;
;  DZ80 V3.4.1 8080 Disassembly of ccsinit.com
;  2010/04/29 16:21
;  Disassembled and commented by Martin Eberhard 2 May 2010
;
;
FALSE	EQU 0FFFFH
TRUE	EQU	NOT FALSE
;
;*********************************************************************
; BUGS FOUND:
; + MEANS THIS IS FIXED WITH MFEFIX OPTION BELOW, - MEANS NOT
;
; + A Z80 INSTRUCTION IS USED IN THE 'ABORT' ERROR MESSAGE ROUTINE
; + THE 'QUIT' ROUTINE READS AND WRITES WRONG BIOS DATA IN PAGE 0
; - WHEN FORMATTING A SINGLE TRACK, IT WILL DO BOTH SIDES OF THE DISK
; - THE 'ABORT' ERROR ROUTINE WILL PRINT THE NUMBER OF SIDES WHERE IT
;   SHOULD PRINT THE FAILING (CURRENT) SIDE
; - THE CODE TO ASK IF THE DISK IS MOUNTED SEEMS TO BE MISSING
; - NO BOUNDS CHECKING ON NUMBER OF TRACKS FOR MINI DISK
; + TERMINATION CHARACTER FOR HEX INPUT IS SPACE, NOT CR
;
;*********************************************************************
; SWITCH TO FIX BUGS THAT I FOUND IN THIS CODE
;   THESE FIXES ARE DESIGNED AS MUCH AS POSSIBLE TO KEEP THE CODE
;   AT ITS ORIGINAL ADDRESSES.
;*********************************************************************
MFEFIX	EQU	FALSE
;
; CP/M BDOS EQUATES
;
WBOOT	EQU	0000H	;JUMP TO BIOS WARM BOOT
IOBYTE	EQU	0003H
LOGIN	EQU	0004H	;LOGIN DRIVE AND CURRENT USER
BDOS	EQU	0005H	;DOS ENTRY POINT
;
; BDOS FUNCTION CODES, PASSED IN REGISTER C
;
RESETF	EQU	0	;SYSTEM RESET
CONSF	EQU	1	;READ CONSOLE
TYPEF	EQU	2	;TYPE ON CONSOLE FUNCTION
PRINTF	EQU	9	;BUFFER PRINT ENTRY
BRKF	EQU	11	;BREAK KEY FUNCTION (TRUE IF CHAR READY)
DRSTF	EQU	13	;RESET DISK
OPENF	EQU	15	;FILE OPEN
READF	EQU	20	;READ FUNCTION
;
FCB	EQU	5CH	;FILE CONTROL BLOCK ADDRESS
BUFF	EQU	80H	;INPUT DISK BUFFER ADDRESS
;
;	FILE CONTROL BLOCK DEFINITIONS
FCBDN	EQU	FCB+0	;DISK NAME
FCBFN	EQU	FCB+1	;FILE NAME
FCBFT	EQU	FCB+9	;DISK FILE TYPE (3 CHARACTERS)
FCBRL	EQU	FCB+12	;FILE'S CURRENT REEL NUMBER
FCBRC	EQU	FCB+15	;FILE'S RECORD COUNT (0 TO 128)
FCBCR	EQU	FCB+32	;CURRENT (NEXT) RECORD NUMBER (0 TO 127)
FCBLN	EQU	FCB+33	;FCB LENGTH
;
;ASCII EQUATES
NULL	EQU	0
CTRLC:	EQU	3	;ASCII ETX
BELL:	EQU	7	;ASCII BELL CHARACTER
CR:	EQU	0DH	;ASCII CARRIAGE RETURN
LF:	EQU	0AH	;ASCII LINE FEED
;
;
; CCS 2780 DISK CONTROLLER EQUATES
;
DSTAT	EQU	30H	;DISK STATUS PORT
DCMMD	EQU	DSTAT	;DISK COMMAND PORT
DTRCK	EQU	DSTAT+1	;DISK TRACK PORT
DSCTR	EQU	DSTAT+2	;DISK SECTOR PORT
DDATA	EQU	DSTAT+3	;DISK DATA PORT
DFLAG	EQU	DSTAT+4	;DISK FLAG PORT (STATUS PORT 1)
DCTRL	EQU	DSTAT+4	;DISK CONTROL PORT
BSTAT	EQU	4	;STATUS PORT 2
BCTRL	EQU	4	;DISK STATUS 2 PORT
;
;TYPE 1 1793 COMMANDS
RSTRCM	EQU	00000000B	;BASIS OF RESTORE COMMAND
SEEKCM	EQU	00010000B	;BASIS OF SEEK COMMAND
STPCM	EQU	00100000B	;BASIS OF STEP COMMAND
STPICM	EQU	01000000B	;BASIS OF STEP-IN COMMAND
STPOCM	EQU	01100000B	;BASIS OF STEP OUT COMMAND
STPUPD	EQU	00010000B	;TRACK UPDATE FLAG FOR STEP COMMANDS
ST03MS	EQU	00000000B	;3 MS STEP RATE
ST06MS	EQU	00000001B	;6 MS STEP RATE
ST10MS	EQU	00000010B	;10 MS STEP RATE
ST15MS	EQU	00000011B	;15 MS STEP RATE
VERTRK	EQU	00000100B	;VERIFY ON DEST TRACK
HDLOAD	EQU	00001000B	;HEAD LOAD BIT
;
STEPI:	EQU	STPICM + STPUPD + HDLOAD	;STEP IN COMMAND
;
;TYPE 3 1793 COMMANDS
RTRKCM	EQU	11100000B	;READ TRACK COMMAND
WTRKCM	EQU	11110000B	;WRITE TRACK COMMAND
DAMDEL	EQU	00000100B	;DATA ADDRESS MARK 15 MS DELAY
;;
; CONTROL REGISTER 1 (DCTRL) BITS
;
DS1	EQU	00000001B	;DRIVE SELECT 1
DS2	EQU	00000010B	;DRIVE SELECT 2
DS3	EQU	00000100B	;DRIVE SELECT 3
DS4	EQU	00001000B	;DRIVE SELECT 4
MAXI	EQU	00010000B	;0=MINI DISK, 1 = MAXI DISK
MOTON	EQU	00100000B	;MOTOR ON
DDEN	EQU	01000000B	;DOUBLE DENSITY ENABLE
AUTOW	EQU	10000000B	;AUTO WAIT
;
; CONTROL REGISTER 2 (BCTRL) BITS
;
EJECT	EQU	00000100B	;REMOTE EJECT CONTROL FOR PERSCI DRIVES
FASTSK	EQU	00010000B	;FAST SEEK FOR VOICE-COIL DRIVES
SIDE0	EQU	01000000B	;0=SIDE 1, 1=SIDE 0
ROMEN	EQU	10000000B	;1 ENABLES ONBOARD ROM ON CCS 2422
;
; STATUS REGISTER 1 (DFLAG) BITS
;
SINTRQ	EQU	00000001B	;STATE OF 1793 INTRQ SIGNAL, ACTIVE HIGH
SDS1	EQU	00000010B	;STATE OF DS1 IN CONTROL REG 1
SDS2	EQU	00000100B	;STATE OF DS2 IN CONTROL REG 1
SDS3	EQU	00001000B	;STATE OF DS3 IN CONTROL REG 1
SDS4	EQU	00010000B	;STATE OF DS4 IN CONTROL REG 1
SSHLD	EQU	00100000B	;STATE OF 1793 HLD SIGNAL, ACTIVE HIGH
SAUTOB	EQU	01000000B	;STATE OF AUTO-BOOT JUMPER, 0=AUTO-BOOT
SDRQ	EQU	10000000B	;STATE OF 1793 DRQ SIGNAL, 1=READY
;
; STATUS REGISTER 2 (BSTAT) BITS
;
STRK0	EQU	00000001B	;WHEN ON TRACK 0: 0=MINI, 1=MAXI
SMINI	EQU	00000010B	;INVERSE OF CCTRL REG BIT: 0=MAXI, 1=MINI
SWPRT	EQU	00000100B	;0=SELECTED DISK IS WRITE-PROTECTED
SSIDE0	EQU	00001000B	;STATE OF SIDE0 BIT IN CONTRO; REG 2
SINDEX	EQU	00010000B	;STATE OF INDEX SIGNAL, ACTIVE LOW
SDDEN	EQU	00100000B	;STATE OF DDEN SIGNAL IN CONTROL REG 1
SSIDED	EQU	01000000B	;0=SELECTED DISK IS 2-SIDED
;
;
	org	100h
;
;*********************************************************************
; CCINIT DISK FORMATTER FOR THE CCS 2722 FLOPPY DISK CONTROLER       *
; MAIN ROUTINE                                                       *
;*********************************************************************
CCINIT:	lxi	sp,STACK	;(0100H)SET UP LOCAL STACK
	di
;
;---------------------------------------------------------------------
; REMEMBER DISK STATE BEFORE WE CHANGE EVERYTHING, SO WE CAN PUT IT
; BACK WHEN WE ARE DONE. sAVE THE STATE IN A FORMAT THAT IS SUITABLE
; FOR DCTRL.
;---------------------------------------------------------------------
	in	BSTAT		;IS CURRENT DISK A MIN OR 8"?
	ani	SMINI
	mvi	a,20h		;MOTOR ON, NOT MAXI DISK
	jnz	CCIN1		;JUMP IF MINI
	mvi	a,30h		;MOTOR ON, 8" (MAXI) DISK
CCIN1:	mov	b,a		;(010FH) SAVE FOR A MOMENT
	in	DFLAG
	ani	SAUTOB		;GET AUTO-BOOT JUMPER
	ora	b		;COMBINE WITH WHAT WE ALREADY DOSCOVERED
	mov	b,a
	in	DFLAG
	rar			;GET DRIVE SELECT BITS
	ani	0fh
	ora	b		;COMBINE SELECT BITS WITH WHAT WE ALREADY GOT
	sta	DCTSAV		;STORE THE STATE FOR WHEN WE'RE DONE
	in	DTRCK		;GET THE CURRENT TRACK FROM THE 1793
	sta	TRKSAV		;SAVE IT TOO.
;
;---------------------------------------------------------------------
; PRINT CCS INIT SIGN-ON MESSAGE, AND GET PARAMETERS FROM THE USER
;---------------------------------------------------------------------
	lxi	h,CCSSTR	;GET CCS SIGN-ON MESSAGE
	call	PRINT		;PRINT MESSAGE TO CONSOLE
;
GETDRV:	lxi	h,DRVSTR	;(012AH) ASK USER WHICH DRIVE
	call	PRTGET		;PRINT MESSAGE, THEN GET CHARACTER
	ani	5fh		;STRIP OFF PARITY AND LOWERCASE-NESS
	sta	RQDISK		;REMEMBER REQUESTED DISK AS ASCII
	sui	41h		;REMOVE ASCII LETTER BIAS AND TEST
	jc	GETDRV		;ERROR: NOT AN ASCII LETTER, SO TRY AGAIN
	cpi	4		;TEST FOR TOO BIG
	jnc	GETDRV		;ERROR: BIGGER THAN 'D', SO TRY AGAIN
	sta	DISKNO		;REMEMBER SELECTED DISK
;
GETSID:	lxi	h,SIDSTR	;(0142H) ASK USER IF IT'S SINGLE OR DOUBLE SIDED
	call	PRTGET		;PRINT MESSAGE, THEN GET CHARACTER
	sui	30h		;REMOVE ASCII NUMBER BIAS AND TEST
	jc	GETSID		;ERROR: NOT A NUMBER, SO TRY AGAIN
	cpi	2		;ONLY 0 AND 1 ARE ALLOWED
	jnc	GETSID		;ERROR:NUMBER TOO BIG, SO TRY AGAIN
	sta	SIDED2		;REMEMBER SIDED-NESS
;
GETDNS:	lxi	h,DENSTR	;(0155H) ASK USER IF IT'S AN SD OR DD DISK
	call	PRTGET		;PRINT MESSAGE, THEN GET CHARACTER
	ani	5fh		;STRIP OFF PARITY AND LOWERCASE-NESS
	sui	'D'		;LESS THAN 'D'?
	jz	GOTDD		;'D' IS A GOOD ANSWER SO GO WITH IT
	sui	'S'-'D'		;IF NOT A 'D', IS IT AN 'S'?
	jnz	GETDNS		;ERROR: NEITHER 'S' OR 'D' SO TRY AGAIN
	inr	a		;MAKE A=1
GOTDD:	sta	DENSITY		;(0168H) SAVE DENSITY: 0=DOUBLE, 1=SINGLE
;
GTTRNO:	lxi	h,TRKSTR	;(016BH) ASK USER FOR TRACK NUMBER
	call	PRINT		;PRINT MESSAGE TO CONSOLE
	call	GETHEX		;GET AN 8-BIT HEX NUMBER FROM THE USER
	jc	GTTRNO		;ERROR: BAD HEX, SO TRY AGAIN
	sta	TRACKNO		;REMEMBER REQUESTED TRACK NUMBER
	call	PCRLF		;PRINT A CR LF ON THE CONSOLE
;
GETSIZ:	lxi	h,SSIZSTR	;(017DH) ASK USER WHAT IS THE SECTOR SIZE
	call	PRTGET		;PRINT MESSAGE, THEN GET CHARACTER
	sui	30h		;REMOVE ASCII NUMBER BIAS
	jc	GETSIZ		;ERROR: NOT A NUMBER, SO TRY AGAIN
	cpi	4		;ANSWER MUST BE 0-3
	jnc	GETSIZ		;ERROR: TOO BIG, SO TRY AGAIN
	sta	SECSIZE		;SAVE SECTOR SIZE
;
GTMINI:	lxi	h,MINISTR	;(0190H) ASK USER IF IT IS A MINI DRIVE
	call	PRTGET		;PRINT MESSAGE, THEN GET CHARACTER
	ani	5fh		;STRIP OFF PARITY AND LOWERCASE-NESS
	sta	ISMINI		;SAVE ANSWER ABOUT MINI
	cpi	'Y'		;YES?
	jnz	FINDTB		;8" DISKS ALWAYS HAVE THE SAME NUMBER OF TRACKS
;
GETTKS:	lxi	h,TKNSTR	;(01A0H) GET NUMBER OF TRACKS ON MINI FROM USER
	call	PRINT		;PRINT MESSAGE TO CONSOLE
	call	GETHEX		;GET AN 8-BIT HEX NUMBER FROM THE USER
	jc	GETTKS		;ERROR: BAD HEX, SO TRY AGAIN
	sta	TRACKS		;SAVE NUMBER OF TRACKS
	call	PCRLF		;PRINT A CR LF ON THE CONSOLE.
	lda	ISMINI		;'Y' MEANS IT IS A MINI DISK
;
;---------------------------------------------------------------------
; FIND THE BEGINNING OF THE CORRECT DISK PARAMETER TABLE INTO HL
; BEGIN BUILDING 1793 DISK CONTROLLER COMMAND C
; BEGIN BUILDING DCTRL VALUE IN A, AND SAVE IT IN SAVDCL
;---------------------------------------------------------------------
FINDTB:	lxi	b,200BH		;(01B5H) B=20 FOR NOT MAXI SELECT + MOTOR ON, 
				;C=HDLOAD + ST15MS (MINI STEP TIME)
	cpi	'Y'		;IS SELECTED DISK A MINI DISK?
	lxi	h,DPTABL	;BASE OF MINI DISK PARAMETER TABLES
	lxi	d,MINIDD-MINISD	;DISTANCE FROM ONE TABLE TO THE NEXT
	jz	MINI1		;B & C ARE SET FOR A MINI DRIVE
	dad	d		;POINT TO MAXI TABLES
	dad	d
	lxi	b,300AH		;B=30 FOR MAXI DISK + MOTOR ON,
				;C=HDLOAD + ST10MS (MAXI STEP RATE)
	cpi	'N'		;'N' IS THE ONLY OTHER LEGAL ANSWER
	jnz	GTMINI		;ERROR: NEITHER 'Y' OR 'N', SO TRY AGAIN
	mvi	a,77		; 8" DISKS ALWAYS HAVE 78 TRACKS
	sta	TRACKS		; SET NUMBER OF TRACKS TO 77
MINI1:	lda	DENSITY		;(01D2H) 0= DOUBLE DENSITY, 1=SINGLE
	dcr	a		;0=SINGLE, 0FFH=DOUBLE
	mov	a,b		;A=MOTOR ON + MINI/NOT-MINI
	jz	SETDDN		;JUMP IF SINGLE DENSITY
	dad	d		;POINT TO THE DOUBLE-DENSITY TABLE
	ori	DDEN		;SET DOUBLE DENSITY ENABLE BIT
SETDDN:	sta	SAVDCL		;(01DDH) SAVE PARTIAL DCTRL VALUE
;
;---------------------------------------------------------------------
; RESTORE THE DISK THAT WE WILL FORMAT.
; A = MINI/MAXI + MOTOR ON + SD/DD
; C = HEAD LOAD + STEP RATE
; HL POINTS TO THE CORRECT 8-BYTE DISK PARAMETER TABLE
; DISKNO = THE DISK NUMBER (0-3)
; SECSIZE = SECTOR SIZE (0-3), WHICH MEANS (128,256,512,1024) BYTES
; TRACKS = THE NUMBER OF TRACKS ON THE DISK
; TRACKNO = THE PARTICULAR TRACK TO FORMAT, WHERE 0FFH MEANS DO ALL
;---------------------------------------------------------------------
	mov	b,a		;SETUP WANTS PARTIALLY BUILT DCTRL IN B
	push	b		;SAVE C, PARTICULARLY
	call	SETUP		;SETUP DISK WITH BITS IN B AND DISKNO
	pop	b		;RECOVER HEAD LOAD & STEP RATE BITS
	mov	a,c		;1793 COMMAND IS 0000XXXX=RESTORE
	sta	CT1BITS		;REMEMBER HEAD LOAD AND STEP RATE BITS
	call	DODCMMD		;SEND RESTORE COMMAND, THEN WAIT TILL DONE
;
;---------------------------------------------------------------------
; GET BUFFER END ADDRESS, AND GET POINTER INTO FORMAT TABLE FROM THE
; DISK PARAMETER TABLE.
;---------------------------------------------------------------------
	mov	e,m		;DE GETS BUFFER END FROM PARAMETER TABLE
	inx	h
	mov	d,m
	inx	h		;HL POINTS TO 2ND WORD ENTRY IN PARAM TABLE
	xchg			;SAVE BUFFER END ADDRESS
	shld	BUFEND
	xchg
	mov	e,m		;POINT DE TO THE CORRECT FORMAT TABLE
	inx	h
	mov	d,m
;
;---------------------------------------------------------------------
; COMPUTE THE SECTORS PER TRACK - ON ENTRY, HL POINTS TO THE 
; BEGINNING OF THE CORRECT SPT TABLE, DE POINTS TO THE CORRECT FORMAT
; TABLE, AND SECSIZE HAS (0-3) FOR SECTOR SIZE
;---------------------------------------------------------------------
	lda	SECSIZE	;GET SECTOR SIZE (0-3)
	inr	a		;A=SECTOR SIZE (1-4)
NXTSPT:	inx	h	;LOOP TO GET POINTER TO SECTORS/TRACK
	dcr	a
	jnz	NXTSPT
	mov	a,m		;FINALLY, GET THE SECTORS/TRACK FROM TABLE
;
	inr	a		;TEST FOR 0FFH=ILLEGAL SEC SIZE/DENSITY COMBO
	jz	BADVAL		;REPORT BAD VALUE AND TRY AGAIN
	xchg			;RECOVER POINTER INTO FORMAT TABLE
	mov	m,a		;WRITE SPT IN 12TH BYTE OF FORMAT TABLE
	lxi	d,-11		;POINT HL TO FORMAT TABLE BEGINNING
	dad	d
	lda	TRACKS		;GET NUMBER OF TRACKS
	mov	m,a		;WRITE THE MAX TRACK TRACK INTO THE TABLE
	lda	TRACKNO		;GET TRACK NUMBER
	inr	a		;TEST FOR ALL TRACKS
	jz	DOTRAK		;JUMP IF WE SHOULD DO ALL TRACKS
	cmp	m		;IS REQUESTED TRACK HIGHER THAN HIGHEST TRACK?
	jnc	BADVAL		;REPORT BAD VALUE AND TRY AGAIN
	dcr	a		;JUST UNDO INCREMENT FROM BEFORE
	jz	DOTRAK		;JUMP IF ITS TRACK ZERO REQUESTED
;
;---------------------------------------------------------------------
; SEEK THE ONE TRACK WE ARE SUPPOSED TO FORMAT
; NO NEED TO SEEK IF EITHER WE ARE GOING TO FORMAT TRACK 0 OR WE ARE
; GOING TO FORMAT ALL TRACKS - THE RESTORE ALREADY PUT US ON TRACK 0.
;---------------------------------------------------------------------
	out	DDATA		;SEND TRACK NUMBER TO 1793
	lda	CT1BITS		;RECOVER HEAD LOAD AND STEP RATE BITS
	ori	SEEKCM + HDLOAD	;BUILD SEEK COMMAND
	call	DODCMMD		;SEND A TO 1793, THEN WAIT TILL IT IS DONE
	in	DTRCK		;WHERE IS THE HEAD ANYWAY?
;
;---------------------------------------------------------------------
; BEGIN THE PROCESS OF FILLING THE BUFFER UP FOR A TRACK
; ON ENTRY, A HAS THE TRACK NUMBER TO FORMAT
;---------------------------------------------------------------------
DOTRAK:	sta	CURTRK		;(022CH) REMEMBER CURRENT TRACK
	mvi	a,0d0h		;SELECT SIDE 0, FAST SEEK, ENABLE ROM
;				;(ROM IS DISABLED VIA BANK REGISTER INSTEAD)
	out	BCTRL
	xra	a		;START ON SIDE 0
;
;---------------------------------------------------------------------
; LOOP THROUGH BOTH SIDES, IF FULL FORMAT OF A DOUBLE-SIDED DISK
; ON ENTRY, A HAS THE SIDE TO DO
;---------------------------------------------------------------------
DOSIDE:	sta	SIDE		;(0234H) REMEMBER CURRENT SIDE
;
;---------------------------------------------------------------------
; WRITE ONE TRACK HEADER INTO THE BUFFER
;---------------------------------------------------------------------
	push	h		;SAVE POINTER TO BEGINNING OF FORMAT TABLE
				;WHERE MAX TRACK NUMBER IS STORED
	inx	h		;POINT TO SECOND BYTE IN FORMAT TABLE
	lxi	d,TRKBUF	;BUILD TRACK DATA SO WE CAN POP IT OUT
	mvi	c,5		;PULL 5 PATTERNS FROM THE TABLE
	call	PATFIL		;...USE 'EM TO WRITE HEADER IN TRACK BUFFER
;
	mvi	a,1		;START WITH SECTOR 1
;
;---------------------------------------------------------------------
; WRITE INTO THE BUFFER: THE SECTOR PREAMBLE, SECTOR DATA, AND THEN
; THE SECTOR POSTAMBLE
; ON ENTRY, A HAS THE SECTOR NUMBER
;---------------------------------------------------------------------
DOSECT:	sta	CURSEC		;(0243H) SAVE CURRENT SECTOR NUMBER
	push	h		;SAVE POINTER TO MAX SECTOR NUMBER IN
				;THE FORMAT TABLE
	inx	h
;
;---------------------------------------------------------------------
; WRITE SECTOR PREAMBLE INTO THE BUFFER, UP THROUGH THE ADDRESS MARK
; THEN FOLLOW THE ADDRESS MARK WITH TRACK, SIDE, SECTOR AND SECTOR
; SIZE (WHICH IS 0-3) FOLLOW WITH THE REST OF THE HEADER UP TO WHERE
; THE DATA STARTS
;---------------------------------------------------------------------
	mvi	c,3		;3 MORE PATTERNS
	call	PATFIL		;GO FILL THE BUFFER
;
	lda	CURTRK		;GET CURRENT TRACK NUMBER
	stax	d		;WRITE IT INTO THE BUFFER
	inx	d
	lda	SIDE		;GET CURRENT SIDE NUMBER
	stax	d		;WRITE IT INTO THE BUFFER
	inx	d
	lda	CURSEC		;GET CURRENT SECTOR NUMBER
	stax	d		;WRITE IT INTO THE BUFFER
	inx	d
	lda	SECSIZE		;GET SECTOR SIZE (0-3)
	stax	d		;WRITE IT INTO THE BUFFER
	inx	d
	mvi	c,5		;EVERYTHING UP TO THE SECTOR DATA
	call	PATFIL
;
;---------------------------------------------------------------------
; COMPUTE THE NUMBER OF BYTES PER SECTOR (BASED ON SECSIZE BETWEEN 0
; AND 3) AND PUT IT IN BC
;---------------------------------------------------------------------
	lda	SECSIZE		;GET SECTOR SIZE (0-3)
	inr	a		;A=SECTOR SIZE (1-4)
	push	h
	lxi	h,40h			;64
SSLUP:	dad	h		;(026EH) HL GETS HL * 2
	dcr	a
	jnz	SSLUP
	mov	b,h		;ACTUAL SECTOR BYTE COUNT GOES IN BC
	mov	c,l
	pop	h
;
;---------------------------------------------------------------------
;LOOP TO FILL THE DATA FIELD IN THE BUFFER WITH THE PROVIDED BYTE
;---------------------------------------------------------------------
DODATA:	mov	a,m		;(0276H) GET THE DATA FIELD FILL BYTE
	stax	d		;AND PUT IT IN THE BUFFER
	inx	d

	dcx	b		;16-BIT DECREMENT
	mov	a,b
	ora	c
	jnz	DODATA
;
;---------------------------------------------------------------------
; WRITE THE SECTOR POSTAMBLE INTO THE BUFFER
;---------------------------------------------------------------------
	inx	h
	mvi	c,2		;2 MORE PATTERNS
	call	PATFIL		;FILL THEM IN
;
;---------------------------------------------------------------------
; NEXT SECTOR, UNLESS WE JUST DID THE LAST SECTOR ON THE TRACK
;---------------------------------------------------------------------
	lda	CURSEC		;GET CURRENT SECTOR NUMBER
	inr	a		;NEXT SECTOR
	pop	h		;POINT TO MAX SECTOR STORED IN FORMAT TABLE
	cmp	m		;DONE WITH ALL SECTORS ON THIS TRACK?
	jnz	DOSECT		;NO - GO DO ANOTHER ONE
;
;---------------------------------------------------------------------
; ALL SECTORS ON THIS TRACK NOW WRITTEN.
;---------------------------------------------------------------------
	dcx	h		;POINT TO THE LAST DATA OF THE TRACK HEADER
;
;---------------------------------------------------------------------
; COMPUTE TRACK POSTAMBLE LENGTH BY SUBTRACTING THE ADDRESS OF THE
; LAST BYTE WRITTEN INTO THE BUFFER (STILL IN DE) FROM THE BUFFER END
; ADDRESS GIVEN IN THE DISK PARAMETER TABLE (STASHED AT BUFEND)
; BC = BUFEND - DE
;---------------------------------------------------------------------
	lda	BUFEND		;GET BUFFER END ADDRESS LOW BYTE
	sub	e		;DO A 16-BIT SUBTRACT
	mov	c,a
	lda	BUFEND+1	;GET BUFFER END ADDRESS HIGH BYTE
	sbb	d
	mov	b,a
;
;---------------------------------------------------------------------
; TRACK POSTAMBLE: FILL THE REMAINING BUFFER WITH THE SAME DATA THAT
; ENDED THE TRACK HEADER
;---------------------------------------------------------------------
TPLOOP:	mov	a,m		;(0299H) GET TRACK HEADER DATA BYTE
	stax	d		;WRITE INTO BUFFER
	inx	d		;BUMP POINTER
	dcx	b		;16-BIT COUNTER DECREMENT
	mov	a,b
	ora	c
	jnz	TPLOOP		;LOOP UNTIL IT IS DONE
;
;---------------------------------------------------------------------
; NOW THAT THE BUFFER IS COMPLETE, IT IS TIME TO KICK OFF THE FORMAT.
;---------------------------------------------------------------------
	call	FORMAT		;GO FORMAT THE TRACK NOW!
;
;---------------------------------------------------------------------
; NEXT SIDE, UNLESS WE JUST DID THE LAST SIDE
;---------------------------------------------------------------------
	pop	h		;POINT TO MAX TRACK NO IN FORMAT TABLE
	lda	SIDED2		;1 MEANS DOUBLE-SIDED DISK REQUESTED
	mov	b,a
	lda	SIDE		;GET SIDE NUMBER
	sub	b		;HAVE WE DONE ALL THE SIDES WE CAN DO?
	jz	NXTTRK		;NEXT TRACK IF SO
;
	mvi	a,90h		;SELECT SIDE 1, FAST SEEK, ROM ENABLE
;				;(ROM IS DISABLED VIA BANK REGISTER INSTEAD)
	out	BCTRL
	mvi	a,1
	jmp	DOSIDE		;DO SAME TRACK ON THE OTHER SIDE OF THE DISK
;
;---------------------------------------------------------------------
; NEXT TRACK, UNLESS WE JUST DID THE LAST TRACK ON THE DISK, OR WE
; WERE ONLY SUPPOSED TO DO ONE TRACK
; ON ENTRY, HL POINTS TO MAX TRACK IN THE SECTOR BUFFER.
;---------------------------------------------------------------------
NXTTRK:	lda	TRACKNO		;(02BAH) GET TRACK NUMBER
	inr	a		;TEST FOR 0FFH MEANS DO ALL TRACKS
	jnz	GETDRV		;GO ASK ABOUT A NEW DISK IF WE JUST DID A
				; 1-TRACK FORMAT
;
	lda	CT1BITS		;RECOVER HEAD LOAD AND STEP RATE BITS
	ori	STEPI		;BUILD A STEP-IN COMMAND
	call	DODCMMD		;ISSUE STEP-IN CMD, THEN WAIT TILL IT IS DONE
	lda	CURTRK		;GET CURRENT TRACK NUMBER
	inr	a		;DID WE JUST DO THE LAST TRACK?
	cmp	m		;COMPARE TO MAX TRACK NO IN FORMAT TABLE
	jnz	DOTRAK		;NO: GO DO ANOTHER TRACK
;
;---------------------------------------------------------------------
; ALL DONE: SELECT TRACK 0, SINGLE DENSITY, AND START OVER. THIS WILL
; RESTORE THE DRIVE, CAUSE TRACK 0 TO BE RE-FORMATTED, AND THEN
; QUIT VIA ASKING FOR A NEW DRIVE VIA JNZ GETDRV ABOVE. A LITTLE
; HOKEY...
;---------------------------------------------------------------------
	xra	a
	sta	SECSIZE		;SET SECTOR SIZE TO 0 (MEANS 128 BYTES)
	sta	TRACKNO		;SELECT TRACK 00
	inr	a
	sta	DENSITY		;SET SINGLE DENSITY
	lda	ISMINI		;Y MEANS IT IS A MINI DISK
	jmp	FINDTB		;GO FIND THE RIGHT TABLE
;
;*********************************************************************
; SUBROUTINE TO REPORT BAD DENSITY, OR SECTOR SIZE/DENSITY COMBO,    *
; AND TRY AGAIN                                                      *
;*********************************************************************
BADVAL:	lxi	h,BADSTR	;(02E2H) REPORT BAD INPUT TO USER
	call	PRINT		;PRINT MESSAGE TO CONSOLE
	jmp	GETDNS		;GO ASK FOR DENSITY AGAIN
;
;*********************************************************************
;SUBROUTINE TO SEND COMMAND IN A TO 1793, THEN WAIT TILL IT IS DONE  *
;*********************************************************************
DODCMMD:	out	DCMMD		;(02EBH) SEND COMMAND TO 1793 
DCWAIT:	in	DFLAG		;(02EDH) WAIT FOR DISK CONTROLLER TO COMPLETE
	rar			;TEST 1793 INTRQ FLAG		.
	jnc	DCWAIT		;LOOP UNTIL DONE
;
	in	DSTAT		;(02F3H) GET 1793 STATUS
	sta	CURSTAT		;AND SAVE IT FOR MESSAGES
	ani	98h		;ANY ERRORS FROM 1793?
	rz			;KEEP GOING IF NOT
;
	lxi	h,SEEKST	;POINT TO 'SEEK'STRING
	jmp	ABORT		;ERROR: COMPLAIN AND QUIT
;
;*********************************************************************
; SUBROUTINE TO FILL TRACK BUFFER ACCORDING TO THE PLAN IN THE BIG   *
; TABLE. THE TABLE CONTAINS PAIRS OF BYTES- THE FIRST BYTE OF EACH   *
; PAIR IS THE NUMBER OF TIMES THE SECOND BYTE SHOULD BE WRITTEN INTO *
; THE TRACK BUFFER. ON ENTRY:                                        *
;    C = THE NUMBER OF BYTE PAIRS TO PROCESS                         *
;    HL POINTS TO THE PLAN IN THE CORRECT FORMAT TABLE               *
;    DE POINTS TO THE CORRECT PLACE IN THE TRACK BUFFER              *
;*********************************************************************
PATFIL:	call	ONEFIL		;(0301H) ONE PATTERN AT A TIME
	dcr	c		;AS MANY TIMES AS C SAYS		.
	jnz	PATFIL
	ret
;
;*********************************************************************
; SUBROUTINE TO FILL BUFFER STARTING AT DE WITH (HL) COPIES OF THE   *
; DATA BYTE AT (HL+1). HL IS ADVANCED UPON EXIT.                     *
;*********************************************************************
ONEFIL:	mov	b,m		;(0309H) B GETS NUMBER OF COPIES
	inx	h
	mov	a,m		;A GETS FILL BYTE
	inx	h
;
;WRITE (B) COPIES OF (A) IN TRKBUF STARTING AT (DE)
FILLUP:	stax	d		;(030DH) WRITE IT ONCE		.
	inx	d		;POINT TO NEXT LOCATION		.
	dcr	b		;BUMP COUNTER		.
	jnz	FILLUP
	ret
;
;*********************************************************************
; SUBROUTINE TO FORMAT ONE TRACK FROM THE BUFFER                     *
;*********************************************************************
FORMAT:	lda	SAVDCL		;(0314H) RECOVER DISK COMMAND FOR DCTRL
	ori	AUTOW		;SET THE AUTO-WAIT BIT
	mov	b,a		;GET READY FOR SETUP
	in	DDATA		;FLUSH DISK CONTROLLER READ BUFFER
	call	SETUP		;SETUP DISK WITH BITS IN B AND DISKNO
;
;---------------------------------------------------------------------
; SETUP BC AS BYTE COUNTER FOR THE TRACK, AND SP AS POINTER INTO
; THE TRACK BUFFER, SO WE CAN POP THE DATA FROM THE BUFFER AND SEND
; IT TO THE 1793 AS QUICKLY AS POSSIBLE
;---------------------------------------------------------------------
	lhld	BUFEND		;GET THE BUFFER END ADDRESS FOR THIS TYPE OF DISK
	lxi	b,0-TRKBUF-2	;BC GETS BUFFER LENGTH
	dad	b
	mov	b,h
	mov	c,l
	lxi	h,0			;MOVE THE SP INTO HL
	dad	sp
	lxi	sp,TRKBUF	;USE STACK POINTER TO POP DATA FROM TRKBUF
	pop	d		;POP THE FIRST 2 BYTES
;
;---------------------------------------------------------------------
; INITIATE THE WRITE TRACK COMMAND
;---------------------------------------------------------------------
	mvi	a,WTRKCM + DAMDEL	;WRITE TRACK COMMAND
	out	DCMMD		;KICK OFF THE WRITE TRACK COMMAND
;
;---------------------------------------------------------------------
; FAST LOOP TO WRITE AN ENTIRE TRACK FROM THE BUFFER TO THE 1793
; DATA PORT
; ON ENTRY:
;    BC HAS THE BYTE COUNT
;    DE HAS THE FIRST 2 BYTES OF DATA FROM THE BUFFER
;    SP POINTS TO THE 3RD BYTE IN THE BUFFER
;---------------------------------------------------------------------
WTLUP:	mov	a,e		;(0334H)
	out	DDATA		;WRITE ONE BYTE
	dcr	c		;DOUBLE BUMP BYTE COUNT		.
	dcr	c
	mov	a,d		;AND THEN GET THE SECOND BYTE
	pop	d		;GET THE 2 NEXT BYTES FROM THE BUFFER
	out	DDATA		;AND FEED 2ND BYTE TO THE HUNGRY 1793
	jnz	WTLUP		;LOOP UNTIL C IS EXHAUSTED

	dcr	b		;BUMP THE COUNTER HIGH BYTE
	jnz	WTLUP		;KEEP GOING UNTIL BC PAIR IS EXHAUSTED
;
;---------------------------------------------------------------------
; WAIT FOR THE TRACK WRITE TO COMPLETE, THEN CHECK FOR ERRORS
;---------------------------------------------------------------------
	sphl			;REPAIR THE STACK POINTER
;
WAIT1:	in	DFLAG		;(0345) WAIT FOR THE 1793 TO COMPLETE
	rar
	jnc	WAIT1
;
	in	DSTAT		;GET 1793 STATUS
	sta	CURSTAT		;AND SAVE IT FOR MESSAGES
	ani	64h		;DID THE 1793 REPORT ANY ERRORS?
	rz			;KEEP GOING IF NO ERRORS
	lxi	h,INITST	;OTHERWISE, COMPLAIN TO USER AND QUIT
;	FALL INTO ABORT
;
;*********************************************************************
; PRINT ERROR MESSAGE AND START OVER AGAIN
; ON ENTRY, HL POINTS TO ONE OF THE 4-BYTE ERROR STRINGS - EITHER
; INITST OR SEEKST. tHIS STRING IS PASTED INTO THE ERROR MESSAGE
; STRING (ERRMSG) USING A Z80 COMMAND, AND THE MESSAGE IS PRINTED.
; THEN WE JUMP BACK TO THE BEGINNING.
;
; NOTE THIS ROUTINE FAILS TO REPAIR BCTRL, LEAVING THE ROM ENABLED
; IN BCTRL. THIS MEANS THAT THE CCS 2422 MUST BE CONFIGURED TO USE
; THE BANK REGISTER TO CONTROL ROMENABLED, NOT THE ROM ENABLE BIT IN
; BCTRL - OTHERWISE CP/M WILL NOT BE THERE FOR A 60K-64K
; IMPLEMENTATION - AND THE ERROR MESSAGE WILL FAIL AND IT WILL CRASH!
;*********************************************************************
ABORT:
IF	MFEFIX			;ELIMINATE Z80 COMMAND
	PUSH	H
	CALL	PCRLF		;INITIAL CRLF
	POP	H
	CALL	PRINT		;PRINT NOW NULL-TERMINATED 4-BYTE MSG
	LXI	H,ERRMFE	;PRINT THE REST OF THE ERROR MESSAGE
ENDIF
IF 	NOT MFEFIX
	lxi	d,ERRMSG	;(0356) TARGET ADDRESS FOR MESSAGE COPY
	lxi	b,X0004		;BYTE COUNT FOR COPY MESSAGE
	dW	LDIR		;(Z80 INSTRUCTION) EDH, B0H
	lxi	h,CRLFST	;CRLFST FALLS INTO ERRMSG
ENDIF
	call	PRINTW		;PRINT STRING, WITH BINARY VALUES IN IT
	jmp	CCINIT		;START OVER FROM BEGINNING
;
;*********************************************************************
; ONE DATA STORAGE BYTE, WEIRDLY IN THE MIDDLE OF CODE               *
;*********************************************************************
SAVDCL:	DS	1		;(0367) DISK COMMAND FOR DCTRL
;
;*********************************************************************
; SUBROUTINE TO SETUP DISK CONTROL REGISTER (DCTRL)                  *
; ON ENTRY, B HAS BASIS OF COMMAND AND DISKNO HAS THE DISK NUMBER.   *
; ON EXIT, A=COMMAND WITH SELECT BITS INCLUDED                       *
; TRASHES C,FLAGS                                                    *
;*********************************************************************
SETUP:	lda	DISKNO		;(0368) GET SELECTED DISK NUMBER
	mov	c,a
	inr	c		;C HAS DISK NUMBER 1-4
	xra	a
	stc			;PREPARE TO SET SELECT BIT
SBLOOP:	ral			;(036F) LOOP SELECT BIT INTO PLACE		.
	dcr	c
	jnz	SBLOOP
;
	ora	b		;COMBINE SELECT BITS ONTO COMMAND
	out	DCTRL		;SET THE DRIVE UP
	ret
;
;*********************************************************************
; CONSOLE PRINT SUBROUTINES. HERE ARE THE EXTERNAL ENTRY POINTS:     *
;  *  PCRLF PRINTS A CR LF                                           *
;  *  PRINT PRINTS A NULL TERMINATED STRING AT (HL)                  *
;  *  PRINTW PRINTS A NULL TERMINATED STRING AT (HL). AN 80H         *
;        INDICATES THAT THE NEXT BYTE IS A BINARY NUMBER THAT SHOULD *
;        BE CONVERTED TO HEXIDECIMAL, THEN PRINTED.	             *
;  *  PRTGET PRINTS NULL TERMINATED STRING, THEN WAITS FOR A         *
;        RESPONSE FROM THE USER. THE RESPONSE IS RETURNED IN A.      *
;*********************************************************************
;
;*********************************************************************
;PRINT CR LF ON THE CONSOLE
;*********************************************************************
PCRLF:	lxi	h,CRLFSTR	;(0378) CR LF STRING
;	FALL INTO PRINT
;
;*********************************************************************
;PRINT NULL-TERMINATED STRING AT (HL) ON CONSOLE
;*********************************************************************
PRINT:	mov	a,m		;(037B) GET STRING CHARACTER
	ana	a		;CHECK FOR DELIMITER
	rz
	call	PRTCHR		;GO PRINT CHR IN A ON CONSOLE
	inx	h
	jmp	PRINT		;PRINT MESSAGE TO CONSOLE
;
;*********************************************************************
;PRINT A AS A 2-DIGIT HEXIDECIMAL VALUE (USED ONLY BY PRINTW)
;*********************************************************************
P2HEX:	push	psw		;(0385) SAVE LEAST SIG NIBBLE
	rar			;MOVE UPPER NIBBLE DOWN
	rar
	rar
	rar
	call	P1HEX		;CONVERT AND PRINT HIGH NIBBLE
	pop	psw		;NOW DO LOW NIBBLE
;
; PRINT LOW NIBBLE OF A AS A HEXIDECIMAL VALUE USING TRICKY CONVERSION
P1HEX:	ani	0fh		;(038E) ONLY CARE ABOUT LOWER NIBBLE
	adi	90h		;HERE COMES THE TRICKY CONVERSION
	daa
	aci	40h
	daa
;FALL INTO PRINT CHARACTER AND RETURN
;		'
;*********************************************************************
; PRINT CHARACTER IN A ON CP/M CONSOLE
; ALL REGISTERS ARE PRESERVED
;*********************************************************************
PRTCHR:	push	h		;(0396) PRESERVE REGISTERS
	push	d
	push	b
	mov	e,a		;BDOS WANTS THE CHR IN E
	mvi	d,0		;AND D MUST BE 0
	mvi	c,TYPEF		;TYPE CHARACTER IN E ON CONSOLE
	call	BDOS
	pop	b		;RESTORE REGISTERS
	pop	d
	pop	h
	ret
;
;*********************************************************************
; SUBROUTINE TO PRINT MESSAGE AT (HL), AND THEN GET INPUT FROM USER. *
; RETURN CHR IN A. IF THE USER TYPES A CARRIAGE RETURN, THEN QUIT    *
; THE PROGRAM VIA THE QUIT (SUB)ROUTINE BELOW.                       *
;*********************************************************************
PRTGET:	call	PRINT		;(03A5) PRINT MESSAGE TO CONSOLE
	call	CONIN		;GET ONE CHARACTER FROM THE CONSOLE
	push	psw		;SAVE A, WHICH HAS THE CHARACTER
	call	PCRLF		;PRINT A CR LF ON THE CONSOLE
	pop	psw		;RECOVER A, WHICH HAS THE CHARACTER
	cpi	CR		;DID THE USER TYPE A CARRIAGE RETURN?
	rnz			;IF NOT, WE ARE DONE, CHARACTER IS IN A
;
;	USER TYPED A CR: FALL INTO QUIT
;
;*********************************************************************
; WE ARE DONE SO FIX EVERYTHING UP AND QUIT                          *
;                                                                    *
; IT LOOKS A LOT LIKE CCS BIOS STORED THE BCTRL AND TRACK NUMBERS IN *
; THE BIOS ARE IN PAGE 0, AND THIS PROGRAM ATTEMPTS TO USE THEM TO   *
; RESTORE STATE AFTER A DISK FORMAT. (THEY WOULD NEED TO DO THIS     *
; BECAUSE THERE IS NO WAY TO READ THE STATE OF FAST-SEEK OR ROM-     *
; ENABLE FROM THE CCS 2422 BOARD, BUT CCINIT MUST WRITE BCTRL        *
; IN ORDER TO SELECT THE DISK SIDE) UNFORTUNATELY, CCS DID N      *
; KEEP THE ADDRESS OF THESE STORAGE BYTES CONSTANT WHEN THEY REVISED *
; CCBIOS - SO THEY DO NOT LINE UP WITH THE RIGHT BYTES IN THE MEMORY.*
; THIS IS A PROBLEM THAT SHOULD BE FIXED.                            *
;                                                                    *
;*********************************************************************
QUIT:	lda	DCTSAV		;(03B3H) GET THE ORIGINAL CONTROLLER STATE
	out	DCTRL		;AND PUT IT BACK
;
IF MFEFIX
	NOP			;USE NOPS TO KEEP CODE IN PLACE
	NOP
	NOP			;WIPE OUT CCS CODE FOR 2 REASONS:
	NOP			;1) RESTORING THE DISK IS NOT
	NOP			;   NECESSARY, SINCE THE NEXT CALL TO
	NOP			;   THE BDOS PERFORMS A WARM BOOT
	NOP
	NOP			;2) SINCE THE BIOS MEMORY LOCATIONS
	NOP			;   REFERENCED ARE WRONG HERE, THE
	NOP			;   DISK RESTORE CALL TO THE BDOS
	NOP			;   COULD HAVE UNPREDICTABLE RESULTS.
	NOP
	NOP
	NOP
	NOP
	NOP
ENDIF
IF NOT MFEFIX
	lda	X0043		;STORAGE IN BIOS AREA
	out	BCTRL		;RESTORE BCTRL
	lda	TRKSAV		;GET THE ORIGINAL TRACK
	out	DTRCK		;AND PUT IT BACK
	sta	X0041		;SAVE TRACK NUMBER IN BIOS AREA
	mvi	c,DRSTF		;RESTORE THE DISK
	call	BDOS
ENDIF
;
	ei
	call	RESETF		;ASK BDOS TO WARM-BOOT THE SYSTEM
	hlt			;THE BDOS SHOULD NEVER RETURN!
;
;*********************************************************************
;ASK BDOS TO GET ONE CHR FROM THE CONSOLE AND RETURN WITH IT IN A    *
;*********************************************************************
CONIN:	mvi	c,CONSF		;(03CFH) GET CHARACTER FROM CONSOLE INTO A
	jmp	BDOS
;
;*********************************************************************
; GET A 2-DIGIT HEX NUMBER FROM THE USER. IF THE USER TYPES AN       *
; ASTERISK, THEN CONVERT IT TO 0FFH, WHICH MEANS MAX VALUE. kEEP     *
; GETTING DIGITS UNTIL THE USER TYPES A SPACE (CR WITH FIX).         *
; ON EXIT, A= VALUE, AND THE CARRY FLAG IS SET FOR INPUT ERROR.      *
;*********************************************************************
GETHEX:	call	CONIN		;(03D4H) GET ONE CHARACTER FROM THE CONSOLE
	cpi	CR		;DID THE USER TYPE A CARRAIGER RETURN?
	jz	QUIT		;IF SO, WE ARE DONE.
	cpi	'*'		;ASTERISK MEANS MAX VALUE
	mov	c,a		;SAVE USER RESONSE
	mvi	a,0ffh		;0FFH MEANS ASTERIX TYPED
	rz			;RETURN WITH A=FFH AND Z SET FOR MAX VALUE
;
	mov	a,c		;GET MOST-SIGNIFICANT DIGIT
	mvi	b,0		;ACCUMULATE COMPLETE NUMBER IN B
;
CHKHEX:	sui	'0'		;(03E5H) SUBTRACT ASCII NUMBER BIAS
	rc			;ERROR: RETURN WITH CARRY IF N0T A NUMBER
;
	cpi	6		;WAS INPUT BIGGER THAN ASCII F?
	cmc			;SET CARRY IF ERROR
	rc			;ERROR:RETURN WITH CARRY SET IF NOT HEX DIGIT
	cpi	10		;0-9?
	jc	DGDONE		;DIGIT DONE IF SO
	sui	'A'-'9'		;SKIP CHARACTERS BETWEEN '9' AND 'A'
	cpi	10		;DID USER TYPE ONE OF THESE CHRS?
	rc			;ERROR WITH C SET IF SO
;
DGDONE:	add	b		;(03F6H) ACCUMULATE ANY PREVIOUS DIGITS
	mov	b,a		;SAVE ACCUMULATION IN B
	push	b		;
	call	CONIN		;GET ANOTHER CHARACTER FROM THE CONSOLE
	pop	b		;
	mov	c,a		;A HAS CONSOLE CHARACTER
IF	MFEFIX
	CPI	CR		;A CR ENDS IT
ENDIF
IF	NOT MFEFIX
	cpi	' '		;A SPACE ENDS IT
ENDIF 
	mov	a,b		;GET MAYBE FINISHED RESULT
	rz			;RETURN WITH RESULT IN A AND Z SET IF DONE
	rlc			;PUSH HIGH DIGIT OVER
	rlc
	rlc
	rlc
	mov	b,a		;SAVE ACCUMULATION IN B
	mov	a,c		;NEW CHR IN A
	jmp	CHKHEX		;CHECK IT, AND GET ANOTHER CHR
;
;---------------------------------------------------------------------
; PRINT NULL-TERMINATED VALUE AT (HL+1) AS A DECIMAL VALUE
;---------------------------------------------------------------------
HEXPRT:	inx	h		;(040BH)
	mov	a,m		;GET THE FIRST CHARACTER
	inx	h		;POINT TO THE NEXT CHARACTER
	call	P2HEX		;PRINT A AS A 2-DIGIT DECIMAL VALUE
;
;*********************************************************************
; PRINT NULL-TERMINATED STRING AT (HL). IF THE CHARACTER IS AN 80H,  *
; THEN THE NEXT BYTE SHOULD BE CONVERTED TO ASCII HEXIDECIMAL AND    *
; THEN PRINTED.                                                      *
;*********************************************************************
PRINTW:	mov	a,m		;(0411H) GET THE NEXT CHARACTER
	ana	a		;TEST FOR NULL
	rz			;NULL IS THE ONLY WAY OUT
	cpi	80h		;FLAG FOR BINARY VALUE?
	jz	HEXPRT		;YES: CONVERT IT TO DECIMAL, THEN PRINT IT
	call	PRTCHR		;PRINT CHARACTER IN A ON CONSOLE
	inx	h		;NECT CHARACTER
	jmp	PRINTW
;
;*********************************************************************
; MESSAGE STRINGS                                                    *
;*********************************************************************
;(0420H)
CCSSTR:		DB	CR,LF,'CCS DISK FORMATTER PROGRAM V2.0',CR,LF,NULL
;(0444H)
DRVSTR:		DB	'WHICH DRIVE (A-D)? ',NULL
;(0458H)
MINISTR:	DB	'IS IT A MINI (Y/N)? ',NULL
;(046DH)
DENSTR:		DB	'SINGLE OR DOUBLE DENSITY (S/D)? ',NULL
;(048EH)
SSIZSTR:	DB	'SECTOR SIZE (0-3)? ',NULL
;(04A2H)
TRKSTR:		DB	'TRACK NUMBER (0-4C OR *)? ',NULL
;(04BDH)
;*****A LABEL IS MISSING. DOES THIS MESSAGE EVER GET USED?*****
	DB	'IS THE DISKETTE MOUNTED (Y/N)? ',NULL
;(04DDH)
SIDSTR:	DB	'SINGLE OR DOUBLE SIDED (O OR 1)? ',NULL
;(04FFH)
BADSTR:	DB	'BAD TRACK OR SECTOR SIZE/DENSITY SELECTION:',CR,LF,NULL
;(052EH)
TKNSTR:	DB	'NUMBER OF TRACKS (23, 28, OR 46)? ',NULL
;
;
;*********************************************************************
; DISK PARAMETER TABLES                                              *
;*********************************************************************
;
DPTABL:					;(0551H)
MINISD:	DB	0E7H,014H		;BUFFER END ADDRESS (COMPUTE THIS)
	DW	T5SD+11			;POINT TO 12TH BYTE IN FORMAT TABLE
	DB	012H,00AH,005H,0FFH	;SPT FOR (128,256,512,1024) BYTES/SECT
;
MINIDD:	DB	0D1H,021H		;BUFFER END ADDRESS
	DW	T5DD+11			;POINT TO 12TH BYTE IN FORMAT TABLE
	DB	0FFH,012H,00AH,005H	;SPT FOR (128,256,512,1024) BYTES/SECT
;
MAXISD:	DB	0E9H,01BH		;BUFFER END ADDRESS
	DW	T8SD+11			;POINT TO 12TH BYTE IN FORMAT TABLE
	DB	01AH,00FH,008H,0FFH	;SPT FOR (128,256,512,1024) BYTES/SECT
;
MAXIDD:	DB	09DH,030H		;BUFFER END ADDRESS
	DW	T8DD+11			;POINT TO 12TH BYTE IN FORMAT TABLE
	DB	0FFH,01AH,00FH,008H	;SPT FOR (128,256,512,1024) BYTES/SECT
;
;
;*********************************************************************
; DISK FORMAT TABLES                                                 *
;*********************************************************************
;
;====================
; 8" SINGLE DENSITY =
;====================
;					;(0571H)
T8SD:	DB	04DH			;MAX TRACK NO (GETS OVERWRITTEN)
;-----------------TRACK HEADER-------------------------
	DB	014H,0FFH,014H,0FFH	;40 BYTES OF 0FFH
	DB	006H,000H		;6 BYTES OF 0
	DB	001H,0FCH		;1 BYTE OF FCH (INDEX MARK)
	DB	01AH,0FFH		;26 BYTES OF FFH
;-------------END OF TRACK HEADER----------------------
;
	DB	01BH			;MAX SECTOR NUMBER (GETS OVERWRITTEN)
;
;--------------SECTOR PREAMBLE-------------------------
	DB	003H,000H,003H,000H	;6 BYTES OF 0
	DB	001H,0FEH		;1 BYTE OF FEH (ADDRESS MARK)
; TRACK NUMBER (0-77)
; SIDE NUMBER (0-1)
; SECTOR NUMBER (1-26)
; SECTOR SIZE (0-3)
	DB	001H,0F7H		;1 BYTE OF F7H
	DB	005H,0FFH,006H,0FFH	;11 BYTES OF FFH
	DB	006H,000H		;6 BYTES OF 0
	DB	001H,0FBH		;1 BYTE OF FBH (DATA ADDRESS MARK)
;-----------------SECTOR DATA---------------------------
;{128,256,512} BYTES OF DATA
	DB	0E5H			;FILL THE DATA FIELD WITH THIS
;--------------SECTOR POSTAMBLE-------------------------
	DB	001H,0F7H		;1 BYTE OF F7H (2 CRC'S WRITTEN)
	DB	01BH,0FFH		;27 BYTES OF FFH
;
;
;====================
;8" DOUBLE DENSITY  =
;====================
;					;(0592H)
T8DD:	DB	04DH			;MAX TRACK NO (GETS OVERWRITTEN)
;-----------------TRACK HEADER-------------------------
	DB	050H,04EH		;80 BYTES OF 4EH
	DB	0CH,000H		;12 BYTES OF 0 
	DB	003H,0F6H		;3 BYTES OF F6H
	DB	001H,0FCH		;1 BYTE OF FCH (INDEX MARK)
	DB	032H,04EH		;50 BYTES OF 4EH
;-------------END OF TRACK HEADER----------------------
;
	DB	01BH			;MAX SECTOR NUMBER (GETS OVERWRITTEN)
;
;--------------SECTOR PREAMBLE-------------------------
	DB	00CH,000H		;12 BYTES OF 0
	DB	003H,0F5H		;3 BYTES OF 5FH
	DB	001H,0FEH		;1 BYTE OF FEH (ADDRESS MARK)
; TRACK NUMBER (0-77)
; SIDE NUMBER (0-1)
; SECTOR NUMBER (1-26)
; SECTOR SIZE (0-3)
	DB	001H,0F7H		;1 BYTE OF F7
	DB	016H,04EH		;22 BYTES OF 4EH
	DB	00CH,000H		;12 BYTES OF 0
	DB	003H,0F5H		;3 BYTES OF F5H
	DB	001H,0FBH		;1 BYTE OF FBH (DATA ADDRESS MARK)
;-----------------SECTOR DATA---------------------------
;{256,512,1024} BYTES OF DATA
	DB	0E5H			;FILL THE DATA FIELD WITH THIS
;--------------SECTOR POSTAMBLE-------------------------
	DB	001H,0F7H		;1 BYTE OF F7 (2 CRC'S WRITTEN)
	DB	036H,04EH		;54 BYTES OF 4EH
;
;
;====================
;5" SINGLE DENSITY  =
;====================
;					;(05B3H)
T5SD:	DB	023H			;MAX TRACK NO (GETS OVERWRITTEN)
;-----------------TRACK HEADER-------------------------
	DB	003H,0FFH,003H,0FFH	;16 BYTES OF FFH
	DB	004H,0FFH,003H,0FFH
	DB	003H,0FFH
;-------------END OF TRACK HEADER----------------------
;
	DB	013H			;MAX SECTOR NUMBER (GETS OVERWRITTEN)
;
;--------------SECTOR PREAMBLE-------------------------
	DB	003H,000H,003H,000H	;6 BYTES OF 0
	DB	001H,0FEH		;1 BYTE OF FEH (ADDRESS MARK)
; TRACK NUMBER (0-77)
; SIDE NUMBER (0-1)
; SECTOR NUMBER (1-26)
; SECTOR SIZE (0-3)
	DB	001H,0F7H		;1 BYTE OF F7
	DB	005H,0FFH		;5 BYTES OF FFH
	DB	006H,0FFH		;6 BYTES OF FFH
	DB	006H,000H		;6 BYTES OF 0
	DB	001H,0FBH		;1 BYTE OF FBH (DATA ADDRESS MARK)
;-----------------SECTOR DATA---------------------------
;{128,256,512} BYTES OF DATA
	DB	0E5H			;FILL THE DATA FIELD WITH THIS
;--------------SECTOR POSTAMBLE-------------------------
	DB	001H,0F7H		;1 BYTE OF F7 (2 CRC'S WRITTEN)
	DB	00BH,0FFH		;11 BYTES OF FFH
;
;
;====================
;5" DOUBLE DENSITY  =
;====================
;					;(05D4H)
T5DD:	DB	023H			;MAX TRACK NO (GETS OVERWRITTEN)
;-----------------TRACK HEADER-------------------------
	DB	006H,04EH,006H,04EH	;32 BYTES OF 4EH
	DB	008H,04EH,006H,04EH
	DB	006H,04EH
;-------------END OF TRACK HEADER----------------------
;
	DB	013H			;MAX SECTOR NUMBER (GETS OVERWRITTEN)
;
;--------------SECTOR PREAMBLE-------------------------
	DB	008H,000H		;8 BYTES OF 0
	DB	003H,0F5H		;3 BYTES OF F5H
	DB	001H,0FEH		;1 BYTE OF FEH (ADDRESS MARK)
; TRACK NUMBER (0-77)
; SIDE NUMBER (0-1)
; SECTOR NUMBER (1-26)
; SECTOR SIZE (0-3)
	DB	001H,0F7H		;1 BYTE OF F7H
	DB	016H,04EH		;16 BYTES OF 4EH
	DB	00CH,000H		;12 BYTES OF 0
	DB	003H,0F5H		;3 BYTES OF F5H
	DB	001H,0FBH		;1 BYTE OF FBH (DATA ADDRESS MARK)
;-----------------SECTOR DATA---------------------------
;{256,512,1024} BYTES OF DATA
	DB	0E5H			;FILL THE DATA FIELD WITH THIS
;--------------SECTOR POSTAMBLE-------------------------
	DB	001H,0F7H		;1 BYTE OF F7 (2 CRC'S WRITTEN)
	DB	016H,04EH		;22 BYTES OF 4EH
;
;*********************************************************************
; MORE MESSAGES.                                                     *
;*********************************************************************
;				;(05F5H)
IF	MFEFIX
SEEKST:	DB	'SEEK',NULL	;NULL-TERMINATED
INITST:	DB	'INIT',NULL
ENDIF
IF NOT MFEFIX
SEEKST:	DB	'SEEK'		;GETS COPIED INTO ERRMSG
INITST:	DB	'INIT'		;GETS COPIED INTO ERRMSG
CRLFST:	DB	CR,LF		;FALLS INTO ERRMSG
ENDIF
ERRMSG:	DB	'    '		;THIS IS WHERE 'SEEK' OR 'INIT' GET COPIED
;
;*********************************************************************
; tHIS LONG MESSAGE INCLUDES VALUES TO PRINT. IF A BYTE IS 80H, THEN *
; THE FOLLOWING BYTE SHOULD BE CONVERTED FROM BINARY TO HEX BEFORE   *
; PRINTING. THE VALUES GET OVERWRITTEN BY THE PROGRAM.               *
;*********************************************************************
ERRMFE:	DB	' ERROR  DRIVE '
RQDISK:	DB	0		;(0612H) REQUESTED DISK NUMBER (IN ASCII)
	DB	'; SIDE '
	DB	80H		;MARK NEXT BYTE AS BINARY
;$$$BUG - THIS MESSAGE SHOULD HAVE THE CURRENT SIDE, NOT THE SIDED-NESS!
SIDED2:	DB	0		;(061BH) 1= 2-SIDED DISK WAS REQUESTED
	DB	'; TRACK '
	DB	80H		;MARK NEXT BYTE AS BINARY
CURTRK:	DB	0		;(0625H) CURRENT TRACK NUMBER
	DB	'; SECTOR '
	DB	80H		;MARK NEXT BYTE AS BINARY
CURSEC:	DB	0		;(0630H) CURRENT SECTOR NUMBER
	DB	'; STATUS-'
	DB	80H		;MARK NEXT BYTE AS BINARY
CURSTAT:	DB	0		;(063BH)
	DB	NULL		;STRING END
;
;*********************************************************************
; UNINITIALIZED DATA STORAGE                                         *
;*********************************************************************
		DS	1	;(063CH) SPARE LOCATION
CT1BITS:	DS	1	;(063DH) COMMAND TYPE 1 BITS - HD LD, STP RATE
BUFEND:		DS	2	;(063EH) BUFFER END ADDRESS FOR THIS TYOE OF DRIVE
DISKNO:		DS	1	;(0640H) SELECTED DISK NUMBER (0-3)
DENSITY:	DS	1	;(0641H) DENSITY: 0=DOUBLE, 1=SINGLE
TRACKNO:	DS	1	;(0642H) TRACK NUMBER		.
SECSIZE:	DS	1	;(0643H) SECTOR SIZE (0-3)
CRLFSTR:	DB	CR,LF,NULL	;(0644H)
ISMINI:		DS	1	;(0647H) 'Y'=FORMAT A MINI DISK, 'N' MEANS 8"
DCTSAV:		DS	1	;(0648H) SAVE ORIGINAL STATE FOR DCTRL
TRKSAV:		DS	1	;(0649H) SAVE ORIGINAL TRACK
		DS	1	;(064AH) SPARE LOCATION	
TRACKS:		DS	1	;(064BH) NUMBER OF TRACKS ON THE DISK
SIDE:		DS	1	;(0C4CH) CURRENT SIDE

STACKSPACE:	DS	21H	;PROGRAM STACK GROWS DOWN INTO THIS SPACE
;
STACK:	EQU	$		;(066DH)
TRKBUF:	EQU	$		;TRACK WRITE BUFFER FROM HERE ONWARD
;
	end
;