*--------------------------------------------------------------
*
* Boot and console I/O PROM for an Altair 680 connected to a 
*    Pertec FD3712 through a UIO interface board. Loads the 
*    first two sectors (256 bytes) from the disk into RAM at
*    $2400 and then jumps to it.
* 
*    This PROM also contains console input and output routines
*    for FLEX to call instead of routines in SWTBUG. The
*    addresses of these routines are patched into the FLEX
*    jump table in the the file DSKDRV.ASM.
*
*    Ver      Date		     Description
*    ---   ----------   ---------------------------------------
*    1.0   05/21/2022	Mike Douglas, Original
*
*    1.1   06/04/2022   Mike Douglas, Add read sector, doCmd,
*			and initPia to the jump table so they
*			can be used by the other programs.
*
*--------------------------------------------------------------
PROMLOC	equ	$FC00		;location of this PROM
LOADLOC	equ	$2400		;where to load boot sectors

* FD3712 controller commands

cREAD	equ	$03		;read sector
cRESTOR	equ	$0D		;seek to track 0
cDRVSEC	equ	$21		;set unit and sector
cRDBUF	equ	$41		;read buffer
cRESET	equ	$81		;reset the controller

* FD3712 controller status bits

sBUSY	equ	$01		;1=busy
sCRCERR	equ	$08		;1=CRC error
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 (inverted)
*   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
P1ADR	equ	UIOBASE+$09	;data/direction P1A

P1BCSR	equ	UIOBASE+$0A	;control/status for FDC cmd out
P1BDR	equ	UIOBASE+$0B	;data/direction P1B

P2ACSR	equ	UIOBASE+$0C	;not connected/used
P2ADR	equ	UIOBASE+$0D	;data/direction P1A

P2BCSR	equ	UIOBASE+$0E	;control/status for FDC data out
P2BDR	equ	UIOBASE+$0F	;data/direction P1A

CMDOUT	equ	P1BDR		;FDC command out (IC-C port B)
DATAIN	equ	P1ADR		;FDC data/status in (IC-C port A)
DATAOUT	equ	P2BDR		;FDC data out (IC-B port B)

HSOFF	equ	$3C		;auto handshake off
HSAUTO	equ	$2C		;auto handshake on
DDRENA	equ	$38		;access data direction register
	
* ACIA equates

SIOCSR	equ	$F000		;control/status register
SIODR	equ	$F001		;data register
UIOCSR	equ	UIOBASE+6	;control/status on ACIA on UIO
UIODR	equ	UIOBASE+7	;data register on ACIA on UIO

RDRF	equ	$01		;receive data available
TDRE	equ	$02		;ready to transmit

*--------------------------------------------------------------
* Jump Table
*--------------------------------------------------------------
	org	PROMLOC
	jmp	boot		;$xx00 boot the disk
	jmp	inChar		;$xx03 read from console
	jmp	outChar		;$xx06 output to console
	jmp	readSec		;$xx09 read sector
	jmp	doCmd		;$xx0C execute FD3712 command
	jmp	initPia		;$xx0F init PIAs on the UIO

*--------------------------------------------------------------
* boot - Initialize UIO, then loop attempting to read
*   track 0 sectors 1 and 2 into RAM at LOADLOC.
*--------------------------------------------------------------
boot	sei			;ensure interrupts are disabled
	lds	#LOADLOC-1	;put stack below load area
	jsr	initSio		;initialize serial port
	jsr	initPia		;initialize the PIAs

* Load 1st two sectors on track 0

retry	ldaa	#cRESET		;reset the 3712 controller
	bsr	doCmd

	ldab	#1		;select drive 0, sector 1
	ldaa	#cDRVSEC
	bsr	doCmd
	
	ldaa	#cRESTOR	;issue restore to track 0 command
	bsr	doCmd
	bne	retry		;drive not ready, try again
	
	ldx	#LOADLOC	;load into RAM at $2400
	bsr	readSec		;read sector 1
	bne	retry		;failed

	ldab	#2		;load sector 2
	ldaa	#cDRVSEC
	bsr	doCmd	
	bsr	readSec
	bne	retry		;failed

	jmp	LOADLOC		;jump to loaded code		

*----------------------------------------------------------------
* readSec - Read sector into RAM as pointed to by X. The drive 
*    should already be on the correct track and the drive:sector
*    register properly set for the sector number to be read.
*----------------------------------------------------------------
readSec	ldaa	#cREAD		;issue read command
	bsr	doCmd
	bne	rsExit		;error
	
	ldaa	#HSAUTO		;enable automatic handshake
	staa	P1ACSR
	ldaa	#cRDBUF		;set controller to read buffer mode
	staa	CMDOUT
	ldab	#128		;B=num bytes to transfer
	
rsLoop	ldaa	DATAIN		;get next byte from fifo
	coma			;data in is inverted
	staa	0,x		;store in sector buffer
	inx
	decb
	bne	rsLoop

	ldaa	#HSOFF		;disable automatic handshake
	staa	P1ACSR
	clr	CMDOUT		;restore normal status mode
rsExit	rts			;exit with status

*--------------------------------------------------------------
* 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. On exit, the status byte is pre-
*   tested with all error bits other than write protect.
*--------------------------------------------------------------
doCmd	staa	CMDOUT		;give command byte to controller
	stab	DATAOUT		;write data, toggle cmd handshake

wtCmd	ldab	#3		;verify not busy 3 times in a row
wtCmd2	ldaa	DATAIN		;wait for not busy
	anda	#sBUSY
	beq	wtCmd		;restart if busy
	decb			;verify not busy 3 times in a row
	bne	wtCmd2

	ldaa	DATAIN		;return status in A
	coma			;data in is inverted
	bita	#sERROR		;test error bits
	rts

*--------------------------------------------------------------
* initPia - Init the 6820s on the UIO board for disk I/O
*    with the FD3712.
*--------------------------------------------------------------
initPia	ldaa	#DDRENA		;A=access data direction register
	staa	P1ACSR
	clr	P1ADR		;0=all bits are inputs
	ldab	#HSOFF		;handshake off for now
	stab	P1ACSR

	stab	P2ACSR		;enable access to the data register
	stab	P1BCSR		;command port	 
	stab	P2BCSR		;data out port
	clr	P2ADR		;data reg to 0 before enabling as output
	clr	P1BDR		;command port
	clr	P2BDR		;data out port

	staa	P2ACSR		;access data direction registers
	staa	P1BCSR		;command port
	staa	P2BCSR		;data out port
	ldaa	#$FF		;$FF=all bits are outputs
	staa	P2ADR		;not used
	staa	P1BDR		;command port
	staa	P2BDR		;data out port
	
	stab	P2ACSR		;this port not used (handshake off)
	stab	P1BCSR		;command port (handshake off)
	
	ldab	#HSAUTO		;handshake always on for data port
	stab	P2BCSR

	ldaa	P1ADR		;read all data registers to clear
	ldaa	P1BDR		;  any spurious interrups
	ldaa	P2ADR
	ldaa	P2BDR
	
	ldaa	#cRESET		;reset the 3712 controller
	bsr	doCmd
	rts
	
*--------------------------------------------------------------
* inChar, outChar
*   The FLEX jump table entries for INCH, OUTCH and OUTCH2
*   are patched to call these routines instead of pointing
*   to SWTBUG routines.
*--------------------------------------------------------------

* initSio - Init ACIA with receive interrupts off (the 680
*   monitor leaves receive interrupts enabled)

initSio	ldaa	#3		;initialize ACIA on the UIO
	staa	UIOCSR

	ldaa	#$11		;init ACIA for 8N2, interrupts off
	staa	UIOCSR		;UIO ACIA
	staa	SIOCSR		;and system ACIA
	rts

* inChar - Return character from console in A

inChar	ldaa	SIOCSR		;wait for character
	lsra
	bcc	inChar

	ldaa	SIODR		;return character
	anda	#$7F
	rts

* outChar - Output character from A to console

outChar	psha			;preserve character to send

ocWait	ldaa	SIOCSR		;wait for OK to xmit
	bita	#TDRE
	beq	ocWait

	pula			;output character
	staa	SIODR
	rts

	end
