*------------------------------------------------------------------
*  PUTBOOT.ASM
*     Installs the FLEX 2/3 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 proper FLEX system file.
*
*     Mike Douglas, November 2022
*------------------------------------------------------------------

* Flex equates

WARMST	equ	$AD03		;FLEX warm start entry point
GETCHR	equ	$AD15		;get and return character in A
PUTCHR	equ	$AD18		;display character in A
INBUFF	equ	$AD1B		;input line to the line buffer
PSTRNG	equ	$AD1E		;display $04 terminated string
PRCRLF	equ	$AD24		;display CR/LF
GETFIL	equ	$AD2D		;get file spec from line bufer
OUTDEC	equ	$AD39		;display X as decimal value
OUTHEX	equ	$AD3C		;display X as hex value
GETHEX	equ	$AD42		;get hex value in X from line buffer

DREAD	equ	$BE80		;disk read sector
DWRITE	equ	$BE83		;disk write sector
DDRVSEL	equ	$BE8C		;disk drive select

* Misc Equates

NUMTRK	equ	77		;tracks on disk
SECLEN	equ	256		;logical sector length
CR	equ	$0D		;carriage return
LF	equ	$0A		;line feed
EOT	equ	$04		;end of string

*--------------------------------------------------------------------
* The PUTBOOT program starts here
*--------------------------------------------------------------------
	org	$A100

	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	#BOOTIMG-128	;X->boot loader offset by -128
	clra			;track 0
	ldab	#13		;logical sector 13 is physical 26,1		
	jsr	DWRITE
	bne	wrtFail

	ldx	#BOOTIMG+128	;X->2nd half of boot loader
	clra			;track 0
	ldab	#1		;logical sector 1 is physical 2,4		
	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
*   PUTBOOT routine. It is loaded into RAM at $2400 (BOOTLOC) by the
*   boot ROM to then load FLEX. As part of this PUTBOOT source code,
*   it is not at $2400 in this file, so a few equates are used to
*   allow assembly here but to run at $2400.
*
**************************************************************************
BOOTLOC	equ	$2400		;runtime address of the loader
BOOTIMG	equ	*		;location of the loader in NEWDISK

PROMLOC	equ	$FC00		;boot and I/O PROM
READSEC	equ	PROMLOC+9	;read sector routine
DOCMD	equ	PROMLOC+12	;execute 3712 command

* 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)

* Start of code

boot	lds	#BOOTLOC-1	;init stack
	bra	loadFlx		;jump to load entry point

bootDat	fcb	0,0,0,0,0,0	;see data section at end
	fcb	0,0,0,0,0  

*------------------------------------------------------------------
* loadFlx - Load FLEX entry point and main loop
*------------------------------------------------------------------
loadFlx	bsr	read1st		;fetch the 1st sector of FLEX.SYS

* recLoop - Record loop for reading an FMS binary file

recLoop	bsr	getByte		;get next byte
	cmpa	#$02		;data record header?
	beq	hdrRec		;yes

	cmpa	#$16		;transfer address header?
	bne	recLoop		;neither, get nextbyte

	bsr	getByte		;get transfer address
	staa	pFlex		;MSB
	bsr	getByte		;LSB
	staa	pFlex+1

	ldx	pFlex		;enter FLEX
	jmp	0,x					

* hdrRec - Record header found. Get load address and length
*   and begin transfer of data.

hdrRec	bsr	getByte		;A=MSB of load address
	psha
	bsr	getByte		;A=LSB of load address
	pulb			;B=MSB of load address
	staa	pDest+1		;save load address
	stab	pDest

	bsr	getByte		;A=byte count
	tab			;B=byte count
	beq	recLoop		;byte count was zero

* movLoop - Move number of bytes specified in B

movLoop pshb
	bsr	getByte		;get next data byte
	pulb
	ldx	pDest		;store in secBuf
	staa	0,x

	inx			;increment pointer
	stx	pDest
	decb			;decrement counter
	bne	movLoop 	;loop for byte count in B

	bra	recLoop		;get next record

*------------------------------------------------------------------
* getByte - Get next byte from sector buffer. Retrieve next
*    sector as needed.
*------------------------------------------------------------------
getByte	ldx	pSource		;X=pointer to sector data
	cpx	#secBuf+SECLEN	;at end of sector?
	beq	nextSec		;yes, go get another sector

	ldaa	0,x		;get next byte, update ptr
	inx
	stx	pSource
	rts

nextSec	ldaa	secBuf		;A=next track num
	ldab	secBuf+1	;B=next sector num
	bsr	readSec		;get next sector
	bra	getByte		;and continue
	
*------------------------------------------------------------------
* Sector read routines
*------------------------------------------------------------------

* diskErr - Clear the error and start over
 
diskErr	ldaa	#cCLRERR	;clear error in the controller
	jsr	DOCMD
	ldaa	#$FF		;force re-seek
	staa	curTrk
	bra	boot		;start over

* read1st - Read first sector of the FLEX system file

read1st	ldaa	dosTrk		;read 1st sector of DOS.SYS
	ldab	dosSec		;fall into bRdSec

* readSec - Read a 256 byte sector with track in A, sector in B

readSec	bsr	seek		;seek to track in A
	bne	diskErr
			
	ldx	#secBuf		;X->sector buffer
	jsr	READSEC		;read 1st physical sector (1-128)
	bne	diskErr 	;error

	ldab	pSec2		;B=second sector to read
	ldaa	#cDRVSEC	;select drive 0 and set sector
	jsr	DOCMD
	jsr	READSEC		;read 2nd physical sector (129-256)
	bne	diskErr 	;error
		
	ldx	#secBuf+4	;data starts at offset 4
	stx	pSource		;pSource->data in secBuf
return	rts

*------------------------------------------------------------------
* seek - Seek to track in A, set sector to hunt from B
*------------------------------------------------------------------
seek	ldx	#secTbl		;X->sector translation table
	decb			;zero index the sector number
	aslb			;two bytes per entry
	stab	TBLOFF		;modify offset in ldx instruction

TBLOFF	equ	*-boot+BOOTLOC+1	;location of offset in ldx 0,x

	ldx	0,x		;X=the two physical sectors
	stx	pSecs		;set pSec1 and pSec2

	psha			;save track
	ldab	pSec1		;B=1st sector to read
	ldaa	#cDRVSEC	;select drive 0 and set sector
	jsr	DOCMD
	pulb			;B=track
	
	cmpb	curTrk		;on correct track already?
	beq	return		;yes

	cmpb	#NUMTRK		;valid track?
	bhs	diskErr		;no

	stab	curTrk		;save new current track
	ldaa	#cSETTRK	;set track in controller
	jsr	DOCMD
	ldaa	#cSEEK		;seek to track
	jmp	DOCMD		;issue command and exit

*--------------------------------------------------------------
* secTbl - Two 128 byte physical sectors make up a 256 byte
*    logical sector. Consecutive sectors cannot be read without
*    an extra disk revolutuon, so the two physical sectors have
*    a sector between them. The sector 26-1 pair is technically
*    consecutive, but there is enough space after sector 26
*    that sector 1 can be read without a revolution slip.
*--------------------------------------------------------------
secTbl 	equ	*-boot+BOOTLOC
	fcb	2,4		;logical sector 1
	fcb	3,5		;logical sector 2
	fcb	6,8
	fcb	7,9
	fcb	10,12
	fcb	11,13
	fcb	14,16
	fcb	15,17
	fcb	18,20
	fcb	19,21
	fcb	22,24
	fcb	23,25		;logical sector 12
	fcb	26,1		;logical sector 13

*------------------------------------------------------------------
* secBuf - The sector buffer immediately follows the boot code.
*   The label is used as an immediate argument for LDX so it needs
*   to be the actual address relative to BOOTLOC ($2400)
*------------------------------------------------------------------
secBuf 	equ	*-boot+BOOTLOC


*------------------------------------------------------------------
* References to boot data items must be at the actual location
*   relative to BOOTLOC ($2400). These data items are present
*   near the start of the boot code (see bData above).
*------------------------------------------------------------------
	org	bootDat-boot+BOOTLOC
dosTrk	rmb	1		;DOS.SYS track and sector
dosSec	rmb	1		;  (filled in by LINK)

curTrk	rmb	1		;current track drive is on
pFlex	rmb	2		;FLEX entry address
pDest	rmb	2		;pointer to destination in memory
pSource	rmb	2		;pointer to data in secBuf

pSecs	equ	*		;physical sector numbers
pSec1	rmb	1		;1st 128 bytes of 256 byte sector
pSec2	rmb	1		;2nd 128 bytes

	end	putBoot
