;******************************************************************
;
;  Position independent boot PROM for Tarbell single density disk
;
;	Loads sector 1, track 0 into RAM at zero and jumps to it
;	at address 007Dh. The PROM performs no console I/O, so
;	this code will work on any 8080/Z80 machine. The code is
;	position independent so the same PROM will run most 
;	anywhere in memory.
;
;       Mike Douglas 6/15/21
;
;******************************************************************

BOOTVEC	equ	007Dh		;entry address of loaded boot code

; Tarbell Disk Drive Controller Equates

FDCBASE	equ	0F8H		;controller base address

FDCCMD	equ	FDCBASE		;1771 command register
FDCSTAT	equ	FDCBASE		;1771 status register
FDCSEC	equ	FDCBASE+2	;1771 sector register
FDCDATA	equ	FDCBASE+3	;1771 data in/out register
FDCWAIT	equ	FDCBASE+4	;FDC stall/wait port
FDCSEL	equ	FDCBASE+4	;FDC drive select port

; Commands for 1771.

STPRATE	equ	2		;10ms step rate
cRESTOR	equ	008h+STPRATE	;restore, head load, no verify
cREAD	equ	08Ch		;read, wait head settle
cRESET	equ	0D0h		;reset 1771 to idle

; Status bits from 1771

sTRACK0	equ	04h		;1=on track zero
sBUSY	equ	01h		;1=1771 busy


;--------------------------------------------------------------
; Copy the PROM content to RAM for execution. This copy routine 
;   is position independent so the boot PROM can be at most any
;   address (256 byte boundary assumed).
;--------------------------------------------------------------
	org	1000h		;use RAM address for assembly, the
				;PROM itself can go most anywhere

	lxi	sp,STACK
	lxi	d,moveLp	;DE->moveLp in RAM
	lxi	h,0E9E1h	;H=PCHL,L=POP H
	push	h		;POP H, PCHL at STACK-2, STACK-1
	call	STACK-2		;ROM addr of moveLp in HL and stack
	
moveLp	dcx	sp		;point SP to moveLp address
	dcx	sp		;    in stack memory
	mov	a,m		;get next EPROM byte
	stax	d		;store it in RAM
	inr	e		;bump pointers
	inr	l
	rnz			;copy to end of 256 byte page
	
	jmp	start		;jump to code now in RAM

;---------------------------------------------------------------
; The loader once in RAM starts here
;---------------------------------------------------------------
start	mvi	a,0F2h		;select drive 0 (inverted in MSN)
	out	FDCSEL
	mvi	a,cRESET	;reset 1771
	out	FDCCMD
	xthl			;delay before checking status
	xthl
	
waitIni	in	FDCSTAT		;wait for not busy
	ani	sBUSY
	jnz	waitIni

	mvi	a,cRESTOR	;restore to track 0
	out	FDCCMD
	xthl			;delay
	xthl

	in	FDCWAIT		;wait for restore to complete
	ora	a
	jm	start		;failed, DRQ instead of INTRQ	

	in	FDCSTAT		;make sure we're on track 0
	ani	sTRACK0
	jz	start		;failed

	lxi	h,0		;load into address zero
	mvi	a,1		;read sector one
	out	FDCSEC
	mvi	a,cREAD		;issue read command
	out	FDCCMD
	xthl			;delay
	xthl
	
rdLoop	in	FDCWAIT		;wait for byte
	ora	a
	jp	rdDone		;sector complete

	in	FDCDATA		;get byte from disk
	mov	m,a		;store it
	inx	h
	jmp	rdLoop		;get next byte

rdDone	in	FDCSTAT		;check read status
	ora	a
	jnz	start		;read error

	jmp	BOOTVEC		;enter the loaded code

; Stack space

	ds	32		;stack space
STACK	equ	$
	
	end

