*------------------------------------------------------------------
*  PUTBOOT.ASM
*     Installs the FLEX loader for the Pertec 3712 onto sectors
*     1 & 2 of track 0. After running PUTBOOT, run "LINK DOS.SYS"
*     to point the loader to the FLEX system file.
*
*     Mike Douglas, 05/22/22
*------------------------------------------------------------------
BOOTLOC	equ	$2400		;FLEX boot loader runs here

* Flex equates

WARMST	equ	$7103		;FLEX warm start entry point
GETCHR	equ	$710F		;get and return character in A
PUTCHR	equ	$7112		;display character in A
INBUFF	equ	$7115		;input line to the line buffer
PSTRNG	equ	$7118		;display $04 terminated string
PRCRLF	equ	$711E		;display CR/LF
GETFIL	equ	$7127		;get file spec from line bufer
OUTDEC	equ	$7133		;display X as decimal value
OUTHEX	equ	$7139		;display X as hex value
GETHEX	equ	$713F		;get hex value in X from line buffer

DREAD	equ	$7F00		;disk read sector
DWRITE	equ	$7F03		;disk write sector
DDRVSEL	equ	$7F0C		;disk drive select

* Misc Equates

CR	equ	$0D		;carriage return
LF	equ	$0A		;line feed
EOT	equ	$04		;end of string

*--------------------------------------------------------------------
* The PUTBOOT program starts here ($2200)
*--------------------------------------------------------------------
	org	BOOTLOC-$200

	bra	putBoot		;skip by version number
version	fcb	1		;version 1	

putBoot	ldx	#mPrompt	;display confirmation prompt
	jsr	PSTRNG
	
	jsr	GETCHR		;get response
	anda	#$5F		;convert 'y' to 'Y'
	cmpa	#'Y'
	bne	abort		;don't do the update

	jsr	GETHEX		;get drive number from command line
	bcs	badDrv		;invalid or missing drive number
	tstb			;only a separator present?
	beq	badDrv		;yes, comma or similar found

	stx	drvNumX		;save number entered
	ldaa	drvNumX+1	;use just LSB of drvNumX
	cmpa	#2		;verify 0 or 1
	bcc	badDrv

	ldx	#flxFcb		;point X to the FCB
	jsr	DDRVSEL		;select the drive

	ldx	#boot		;X->boot loader
	clra			;track 0
	ldab	#1
	jsr	DWRITE
	bne	wrtFail

	ldx	#boot+SECLEN	;X->2nd 128 bytes of loader
	clra			;track 0
	ldab	#2		;sector 2
	jsr	DWRITE
	bne	wrtFail

	ldx	#mDone		;display "drive updated" message

dspExit	jsr	PSTRNG		;display message in (X)
	jsr	PRCRLF		;extra CR/LF
	jmp	WARMST		;return to FLEX

wrtFail	ldx	#mFail		;"write to disk failed" then exit
	bra	dspExit		

badDrv	ldx	#mBadDrv	;"invalid drive" then exit
	bra	dspExit

abort	ldx	#mAbort		;"no updates performed" then exit
	bra	dspExit

*------------------------------------------------------------------
* Data Area
*------------------------------------------------------------------
mPrompt	fcb	LF
	fcc	'THIS PROGRAM WRITES THE FLEX LOADER FOR THE'
	fcb	CR,LF
	fcc	'PERTEC FD3712 (OR ICOM FD360) TO TRACK 0.'
	fcb	CR,LF,LF
	fcc	'CONTINUE? '
	fcb	EOT

mBadDrv	fcc	'INVALID OR MISSING DRIVE NUMBER'
	fcb	EOT

mDone	fcc	'FLEX LOADER WRITTEN'
	fcb	CR,LF,LF
	fcc	'NOW RUN "LINK DOS.SYS" TO POINT'
	fcb	CR,LF
	fcc	'THE LOADER TO THE DOS.SYS file.'
	fcb	EOT

mFail	fcc	'WRITE TO DISK FAILED - '

mAbort	fcc	'NO UPDATES PERFORMED'
	fcb	EOT
		
flxFcb	equ	*		;FLEX FCB structure
	fcb	0,0		;drive number at offset 3
drvNumX	rmb	2		;16 bit drive number from X

**************************************************************************
*
* FLEX cold boot loader
*   The following code is written to track 0, sectors 1 and 2 by the
*   NEWDISK routine. It is loaded into RAM at $2400 (BOOTLOC) by the
*   SWTBUG boot ROM to then load FLEX (DOS.SYS). This is a stand alone
*   version for testing.
*
**************************************************************************

* FD3712 controller commands

cREAD	equ	$03		;read sector
cSEEK	equ	$09		;seek to track
cCLRERR	equ	$0B		;clear error flags
cSETTRK	equ	$11		;set track to seek
cDRVSEC	equ	$21		;set unit and sector
cRDBUF	equ	$40		;read buffer

* FD3712 controller status bits

sBUSY	equ	$01		;1=busy
sCRCERR	equ	$08		;1=CRC error
sWRTPRT	equ	$10		;1=write protected
sNOTRDY	equ	$20		;1=drive not ready
sERROR	equ	$29		;any error bit except write protect

* UIO interface board
*   PIA #1 (IC-C) port A is status/data in
*   PIA #1 (IC-C) port B is command out
*   PIA #2 (IC-B) port A is not used
*   PIA #2 (IC-B) port B is data out
*
*   Command bit 0 (the execute bit) comes from the OR of
*   the data-out and data-in handshake lines from the PIAs.
*   CA2 from PIA #1 is the data-in handshake and CB2 from
*   PIA #2 is the data-out handshake.

UIOBASE	equ	$F000	 	;base address of UIO board

P1ACSR	equ	UIOBASE+$08	;control/status for FDC data in
CMDOUT	equ	UIOBASE+$0B	;FDC command out (IC-C port B)
DATAIN	equ	UIOBASE+$09	;FDC data/status in (IC-C port A)
DATAOUT	equ	UIOBASE+$0F	;FDC data out (IC-B port B)

HSOFF	equ	$3C		;auto handshake off
HSAUTO	equ	$2C		;auto handshake on

SECLEN	equ	128		;sector length
NUMTRK	equ	77		;number of tracks

* Start of code

	org	BOOTLOC

boot	lds	#BOOTLOC-1	;init stack pointer
	bra	bLdFlex		;jump to load entry point

dosTrk	fcb	1		;DOS.SYS track and sector
dosSec	fcb	17		;  (filled in by LINK)

curTrk	fcb	0		;current track drive is on
pFlex	fcb	0,0		;FLEX entry address
pDest	fcb	0,0		;pointer to destination in memory
pSource	fcb	0,0		;pointer to data in secBuf

*------------------------------------------------------------------
* bLdFlex - Load FLEX entry point and main loop
*------------------------------------------------------------------
bLdFlex	bsr	bRd1st		;fetch the 1st sector of DOS.SYS

* bRecLp - Record loop for reading an FMS binary file

bRecLp	bsr	bGetByt		;get next byte
	cmpa	#$02		;data record header?
	beq	bHeader		;yes

	cmpa	#$16		;transfer address header?
	bne	bRecLp		;neither, get nextbyte

	bsr	bGetByt		;get transfer address
	staa	pFlex		;MSB
	bsr	bGetByt		;LSB
	staa	pFlex+1

	ldx	pFlex		;enter FLEX
	jmp	0,x					

* bHeader - Record header found. Get load address and length
*   and begin transfer of data.

bHeader	bsr	bGetByt		;A=MSB of load address
	psha
	bsr	bGetByt		;A=LSB of load address
	pulb			;B=MSB of load address
	staa	pDest+1		;save load address
	stab	pDest

	bsr	bGetByt		;A=byte count
	tab			;B=byte count
	beq	bRecLp		;byte count was zero

* bMoveLp - Move number of bytes specified in B

bMoveLp	pshb
	bsr	bGetByt		;get next data byte
	pulb
	ldx	pDest		;store in secBuf
	staa	0,x

	inx			;increment pointer
	stx	pDest
	decb			;decrement counter
	bne	bMoveLp		;loop for byte count in B

	bra	bRecLp		;get next record

*------------------------------------------------------------------
* bGetByt - Get next byte from sector buffer. Retrieve next
*    sector as needed.
*------------------------------------------------------------------
bGetByt	ldx	pSource		;X=pointer to sector data
	cpx	#secBuf+SECLEN	;at end of sector?
	beq	bNxtSec		;yes, go get another sector

	ldaa	0,x		;get next byte, update ptr
	inx
	stx	pSource
	rts

bNxtSec	ldx	#secBuf		;X->where to read sector
	ldaa	0,x		;A=next track num
	ldab	1,x		;B=next sector num
	bsr	bRdSec		;get next sector
	bra	bGetByt		;and continue
	
*------------------------------------------------------------------
* Sector read routines
*------------------------------------------------------------------
* bRdErr - Clear a read error and start over
 
bRdErr	ldaa	#cCLRERR	;clear error in the controller
	bsr	bDoCmd
bSkErr	ldaa	#$FF		;force re-seek
	staa	curTrk
	bra	boot		;start over
	
* bRd1st - Read first sector of the FLEX system file

bRd1st	ldaa	dosTrk		;read 1st sector of DOS.SYS
	ldab	dosSec		;fall into bRdSec
	ldx	#secBuf

* bRdSec - Read a sector specified by track in A, sector in B

bRdSec	bsr	bSeek		;seek to track in A
	ldaa	#cREAD		;issue read command
	bsr	bDoCmd
	bne	bRdErr		;error
	
	ldaa	#HSAUTO		;enable automatic handshake
	staa	P1ACSR
	ldaa	#cRDBUF		;set controller to read buffer mode
	staa	CMDOUT
	ldab	#SECLEN		;B=num bytes to transfer
	
bRdLoop	ldaa	DATAIN		;get next byte from fifo
	coma			;data in is inverted
	staa	0,x		;store in sector buffer
	inx
	decb
	bne	bRdLoop
	
	ldaa	#HSOFF		;disable automatic handshake
	staa	P1ACSR
	clr	CMDOUT		;restore normal status mode
		
	ldx	#secBuf+4	;data starts at offset 4
	stx	pSource		;pSource->data in secBuf
	rts

*------------------------------------------------------------------
* bSeek - seek to track in A, set sector to hunt from B
*------------------------------------------------------------------
bSeek	psha			;save track
	ldaa	#cDRVSEC	;set sector to read from B
	bsr	bDoCmd
	pulb
	
	cmpb	curTrk		;on correct track already?
	beq	bReturn		;yes

	cmpb	#NUMTRK		;valid track?
	bhs	bSkErr		;no

	stab	curTrk		;save new current track
	ldaa	#cSETTRK	;set track in controller
	bsr	bDoCmd
	ldaa	#cSEEK		;seek to track
	bsr	bDoCmd
bReturn	rts

*--------------------------------------------------------------
* doCmd - Write A to the FDC command register and B to the
*   FDC data register. Wait for the command to complete and
*   return the status register in A. The status is pre-tested
*   with all error bits (other than write protect).
*--------------------------------------------------------------
bDoCmd	staa	CMDOUT		;give command byte to controller
	stab	DATAOUT		;write data, toggle cmd handshake

bWtCmd	ldab	#3		;verify not busy 3 times in a row
bWtCm2	ldaa	DATAIN		;wait for not busy
	anda	#sBUSY
	beq	bWtCmd		;restart if busy
	decb			;verify not busy 3 times in a row
	bne	bWtCm2

	ldaa	DATAIN		;return status in A
	coma			;data in is inverted 
	bita	#sERROR		;test error bits
	rts

*------------------------------------------------------------------
* secBuf - The sector buffer immediately follows the boot code.
*------------------------------------------------------------------
secBuf 	equ	*

	end

