;BOOT4/ASM - LS-DOS 6.3
;	SUBTTL	'<Bootstrap Loader>'
	PAGE
*MOD
;
KEYIN	EQU	40H
NMIVECT	EQU	66H
DSPLY	EQU	21BH
BUFFER	EQU	1200H
BOOTBUF	EQU	43FFH-9
;
;       Boot loader routine read in by ROM, along with
;	 the lowcore I/O drivers.
;	This section loads in SYSRES
;
LBOOT	LD	IY,DCT$		;Set IY for FDCDVR use
	LD	A,(IY+9)	;Directory track is
	LD	(IY+5),A	;  the current track
	LD	A,4
	LD	(FLGTAB$+'R'-'A'),A	;Set retries
	LD	A,0C9H
	LD	(FDDINT$),A	;Return for disk driver
	LD	A,18		;5" sectors/track, dden
	BIT	5,(IY+4)	;Dbl sided?
	JR	Z,NOTDBL
	ADD	A,A		;Adjust to 36 sect/cyl
NOTDBL	LD	(SECTRK),A
;
;	Set up for a fragmented file
;
	EXX
	LD	C,6		;Sectors/gran
	CALL	GETEXT		;Pick up extent 1
	EXX
;
	CALL	LOAD		;Read in sysres
	LD	A,0FBH		;EI instruction
	LD	(DISKEI),A	;  stuffed into FDCDVR
	JP	(HL)		;Continue system init
;
LOAD	CALL	RDBYTE		;Get type code
	DEC	A
	JR	NZ,LOAD2	;Bypass if not type 1
	CALL	GETADR		;Get blk len & load adr
LOAD1	CALL	RDBYTE		;Start reading the block
	LD	(HL),A		;Stuff into memory
	INC	HL		;Bump memory pointer
	DJNZ	LOAD1		;Loop for entire block
	JR	LOAD		;Restart the process
;
LOAD2	DEC	A		;Test if type 2 (traadr)
	JR	Z,GETADR	;Ah, go if transfer addr
	CALL	RDBYTE		;Assume comment,
	LD	B,A		;  get comment length
LOAD3	CALL	RDBYTE		;  & ignore it
	DJNZ	LOAD3
	JR	LOAD		;Continue to read
;
;       got the transfer address type code
;
GETADR	CALL	RDBYTE		;Get block length
	LD	B,A
	CALL	RDBYTE		;Get lo-order load addr
	LD	L,A
	DEC	B		;Adj length for this byte
	CALL	RDBYTE		;Get hi-order load addr
	LD	H,A
	DEC	B		;Adj length for this byte
	RET
;
;       routine to read a byte
;
RDBYTE	EXX			;Switch memory/buf ptrs
	INC	L		;Bump buf pointer
	JR	NZ,RDB2		;Bypass disk i/o if more
	PUSH	BC
	LD	B,9		;Read sector function #
	CALL	DCT$		;Get another sector
	POP	BC
	INC	E		;Bump sector counter
	LD	A,E
	SUB	$-$		;Is this the last sector
SECTRK	EQU	$-1
	JR	NZ,RDB1		;  on the cylinder?
	LD	E,A		;Yes, restart at 0
	INC	D		;  & bump the cylinder up
RDB1	DEC	B		;Dec sectors this extent
	CALL	Z,GETEXT	;Get next extent if 0
RDB2	LD	A,(HL)		;P/u a byte
	EXX			;Exc mem/buf pointers
	RET
;
;	Load DE track,sector, B sectors this extent
;
GETEXT
	INC	IX		;Index directory entry
	INC	IX		;Pt at grans this ext.
	LD	A,(IX)
	PUSH	AF		;Save for later
	RLCA
	RLCA			;Normalize start gran
	RLCA
	AND	7
	CALL	MULTCA		;Start gran * grans/sec
	LD	E,A		;This is start sector
	POP	AF
	AND	00011111B	;Get total grans
	INC	A		;  this extent
	CALL	MULTCA		;  * sect/gran
	LD	B,A		;Sectors this extent
	LD	D,(IX-1)	;Cyl this extent
	RET
;
;	Short multiply C * A
;
MULTCA	PUSH	BC		;Save sect/gran in C
	LD	D,A
	XOR	A
	LD	B,8
MLTCA	ADD	A,A
	SLA	C
	JR	NC,MLTCA1
	ADD	A,D
MLTCA1	DJNZ	MLTCA
	POP	BC
	RET
;
;	Initialize the CRTC
;
INITCRTC
	LD	BC,15<8!88H	;Count, CRTC address reg
	LD	HL,CRTCTAB
$?1	LD	A,(HL)
	OUT	(C),B		;Pass reg # to CRTC
	OUT	(89H),A		;Pass value to CRTC reg
	DEC	HL		;Backup to next value
	DEC	B		;To next lower reg
	JP	P,$?1
	RET
	DB	99		;Horiz total MD
	DB	80		;Horiz displayed MD
	DB	85		;Horiz sync position MD
	DB	10		;Horiz sync width
	DB	25		;Vertical total
	DB	4		;Vertical total adjust
	DB	24		;Vertical displayed
	DB	24		;Vertical sync position
	DB	0		;Interlace mode
	DB	9		;Maximum scan line addr
	DB	65H		;Cursor start
	DB	9		;Cursor end
	DB	0		;Start address (H)
	DB	0		;Start address (L)
	DB	0		;Cursor (H)
CRTCTAB	DB	0		;Cursor (L)
	DC	-$&0FFH,0
;
;	System BOOT entry point, loaded by ROM
;
CORE$	DEFL	$
	ORG	4300H
BOOT	NOP
	CP	14H		;Directory track location
DIRTRK	EQU	$-1
	DI
	LD	A,86H		;Bring up the RAM
	OUT	(@OPREG),A
	LD	(OPREG$),A
	LD	HL,CRTBGN$	;Clear video RAM
	LD	DE,CRTBGN$+1
	LD	BC,CRTSIZE-1
	LD	(HL),' '
	LDIR
	LD	HL,NMIRET	;Set NMI vector
	LD	(NMIVECT+1),HL
	LD	A,0C3H
	LD	(NMIVECT),A
	LD	A,0C9H		;Stuff return for ints
	LD	(38H),A
;
;	Read the first 16 sectors of track 0
;
	LD	HL,START$+200H	;Pt to page 2
	LD	D,L		;Init to track 0, sec 0
	LD	E,L
RDBOOT	CALL	RDSEQ		;Read a sector
	INC	H		;Bump to next page
	INC	E		;Bump to next
	LD	A,16
	CP	E		;Loop if more
	JR	NZ,RDBOOT
	CALL	INITCRTC	;Initialize the CRTC
;
;	Now set up to load SYSRES
;
	LD	A,(DIRTRK)	;P/u dir cyl
	LD	(DCT$+9),A	;Update DCT to show DIR
	LD	D,A		;Set starting track and
	LD	E,0		;  init to read the GAT
	CALL	RDSECT		;  into BUFFER
	LD	A,(BUFFER+0CDH)	;Update DCT$ to show
	AND	20H		;  the # of sides
	LD	HL,DCT$+4
	OR	(HL)
	LD	(HL),A
	LD	E,4		;Pt to SYS0 dir sector
	CALL	RDSECT		;Read the SYS0 dir sec
	LD	A,(BUFFER)	;Test if system disk
	AND	10H
	JR	Z,NOTSYS	;Go if not
	LD	HL,BUFFER+21+8	;SYS0 extent info
	LD	DE,BOOTBUF	;Use 43FF-8
	LD	BC,8
	LDDR			;Store 1st four extents
	PUSH	DE		;Pt IX to 1 byte
	POP	IX		;  before extent info
	EXX
	LD	HL,BUFFER+255	;Init to buffer end
	EXX
	JP	LBOOT		;Load SYSRES
	DB	0,0		;Padding for posn
;
;       routine to read a sector
;
RDSECT	LD	HL,BUFFER	;Set buffer
RDSEQ	LD	B,5		;Init retry counter
RDS1	PUSH	BC		;Save counter
	PUSH	HL		;Save for retries
	CALL	READ		;Attempt read
	POP	HL
	POP	BC
	AND	1CH		;Mask status
	RET	Z		;Return if no error
	DJNZ	RDS1		;Loop for retry
GOTERR	LD	HL,DISKERR	;"Disk error"
	DB	0DDH		;Hide next instruction
NOTSYS	LD	HL,NOSYS	;"No system"
	LD	BC,ERRLEN
	LD	DE,80*11+CRTBGN$+35	;Middle of screen
	LDIR
HALTS	JR	HALTS		;Wait for RESET
;
READ	LD	BC,81F4H	;Set DDEN, DS1, d.s. port
	OUT	(C),B		;Select it
	DEC	C		;Point C to data reg
	LD	A,18H		;Seek command (6 ms)
BOOTST$	EQU	$-1		;Set for boot step rate
	IFNE	BOOTST$,439DH
	ERR	'Boot step out of position'
	ENDIF
	OUT	(C),D		;Set desired track
	CALL	FDCMD		;Pass command & delay
SEEK1	IN	A,(0F0H)	;Get status
	BIT	0,A		;Busy?
	JR	NZ,SEEK1
	LD	A,E		;Set sector register
	OUT	(0F2H),A
	LD	A,81H		;Set DDEN & DS1
	OUT	(0F4H),A
	PUSH	DE
	LD	DE,81H!40H<8!2	;D=DS1 + DDEN + WSGEN
				;E=Mask to see DRQ
	LD	A,80H		;FDC READ command
	CALL	FDCMD		;Pass to ctrlr & set B=0
	LD	A,0C0H		;Enable INTRQ & timeout
	OUT	(0E4H),A
READLP1	IN	A,(0F0H)	;Grab status
	AND	E		;Test bit 1
	JR	Z,READLP1
	INI
	LD	A,D		;Set DDEN & DS1 & WSGEN
READLP2	OUT	(0F4H),A	;Continue to select
	INI			;  while inputting
	JR	NZ,READLP2
	JR	$		;Wait for NMI
NMIRET	POP	DE		;Pop interrupt ret
	POP	DE		;Restore DE
	XOR	A		;Disable INTRQ & timeout
	OUT	(0E4H),A
	LD	A,81H		;Reselect drive
	OUT	(0F4H),A
	IN	A,(0F0H)	;Get status
	RET
FDCMD	OUT	(0F0H),A	;Give cmd to ctrlr
	LD	B,24		;Time delay
	DJNZ	$
	RET
DISKERR	DB	'Disk error'
NOSYS	DB	'No system '
ERRLEN	EQU	$-NOSYS		;Length of error msg
	DC	-$&0FFH,0
	ORG	CORE$+256
	END
