/*****************************************************************************
   KSOS Level 0 Bootstrap for RP?? and RM??
   MODULE NAME:  System Startup -- RM/RP  Level 0 Bootstrap
   REFERENCES-
     A Specs:  
     B5 Specs:
   AUTHOR:
	Tom Perrine

   VERSION:
   	$Header: boot0.s,v 1.10 87/04/02 09:50:02 Perrine Stab $
   HISTORY:
	$Log:	boot0.s,v $
# Revision 1.10  87/04/02  09:50:02  Perrine
# Set IPL=0, use read-in-preset instead of pack-ack before first read...
# 
# Revision 1.9  87/03/31  14:30:09  tom
# add trace info, simplify some code
# 
# Revision 1.8  86/11/14  14:09:45  tom
# moved boot1 lower to allow larger boot1,
# pass drive no and mba base address in regs to boot1
# 
# Revision 1.7  86/09/18  15:44:04  tom
# added code to set a reasonable stack, ie. just below boot1
# 
# Revision 1.6  86/09/16  10:09:23  tom
# this version is capable of loading the primitive boot1 and starting
# execution. It has everything it needs except a way to pass the contoller/drive
# to the C version of boot1.
# 
# Revision 1.5  86/09/04  16:39:00  tom
# this version adds:
# more parameters and constants,
# find and init MBA for given TR
# find drive regs for given drive
# set up MBA mapping regs
# set volume valid and 22 sector format
# find size of and where to load level 1 bootloader
# set up MBA regs for the transfer
# 
# Revision 1.4  86/09/04  10:14:14  tom
# added Log line, this version can really find the R0-R5, PFNCOUNT,
# and the CPU type and loops if not 780. Also finds SCBB reg value
# ONWARD!
# 

   PRIVILEGES:	   None needed
   SPECIAL NOTES:
	Runs on Bare Machine
	Assumes that the CPU is a 780, with the boot disk
		attached to the MASSBUS at TR=8

   PURPOSE	loads level 1 bootstrap from drive 1 and transfers to it

   DESCRIPTION
	determine CPU type - die if not 11/780
	get some info from the Restart Parameter Block (RPB)
	find MBA for the given TR
	find the drive regs for the given controller/drive
	determine amount of phys mem present
	determine where to load the level 1 bootloader
	set up MBA mem map regs
	set up MBA var and bcr regs
	set up drive registers
	GO!
	jump to level 1 bootloader

*****************************************************************************/
/********************************************************
 *							*
 *	parameters and constants			*
 *							*
 ********************************************************/

/********************************************************
 *							*
 *	hardware specific constants			*
 *							*
 ********************************************************/
/*	SECTSZ	- the size of a device sector in bytes				*/
	.set	SECTSZ,		512
/*	PGSZ	- the size of a memory page in bytes				*/
	.set	PGSZ,		512


/*	Privileged Processor Registers */
	.set	SID,		0x3e			/* PR$_SID */
	.set	IPLR,		18			/* PR$_IPL */

/********************************************************
 *							*
 *	Level 1 bootloader information			*
 *							*
 ********************************************************/
/*	LEV1START	- sector number where the level 1 bootstrap starts on disk	*/
	.set	LEV1START,	20		/* block 20	*/
	.set	LEV1CYL,	00		/* cylinder 0	*/
	.set	LEV1TRK,	00		/* track 0	*/

/*	LEV1SECTORS	- the size of the level 1 bootstrap in SECTSZ sectors		*/
	.set	LEV1SECTORS,	64		/* 32 K bytes */
	.set	LEV1BYTES,	32768		/* (SECTSZ*LEV1SECTORS) */
	.set	LEV1PAGES,	64		/* (LEV1BYTES/PGSZ) */




/*	Offsets within the Restart Parameter Block in page 0 */
	.set	RPB_regbase,	0x1c		/* start of block of r0-r5 */
	.set	RPB_pfncnt,	0x4c		/* size of physical mem in pages */

/*	Offsets of register R0-R5 contents within rpbreg	*/
	.set	TR,	4			/* TR number */
	.set	CNTR,	8			/* controller number == drive number for disk drives */

/********************************************************
 *							*
 *	MASSBUS registers and bits			*
 *							*
 ********************************************************/
	.set	MBA_base0,	0x20000000	/* MBA at TR=0 */

	.set	MBA_csr,	0x0		/* offset to SBI control and status register */

	.set	MBA_cr,		0x4		/* offset to MBA control register */
	.set		MBA_INIT,	0x1		/* INIT bit in MBA_cr */

	.set	MBA_sr,		0x8		/* offset to MBA status register */
	.set		MBA_DTBUSY,	0x80000000	/* DTBUSY bit in MBA_sr */
	.set		MBA_DTABORT,	0x1000		/* DTABORT bit in MBA_sr */

	.set	MBA_var,	0xC		/* offset to MBA var register */

	.set	MBA_bcr,	0x10		/* offset to MBA byte count register */

	.set	MBA_map0,	0x800		/* offset to MBA mapping register 0 */
	.set		MBA_MAPVALID,	0x80000000
						/* MBA map entry valid bit */




/********************************************************
 *							*
 *	Drive registers and bits			*
 *							*
 ********************************************************/
	.set	RP,		0x400		/* start of drive registers */
	.set	RP_DROFFSET,	0x80		/* offset between sets of drive registers */

	.set	RP_csr,		0		/* offset of CSR  */
	.set		RP_RIP,		0x11		/* read-in preset */
	.set		RP_READ,	0x39		/* read	*/
	.set	RP_sr,		4
	.set	RP_da,		0x14		/* offset of desired address (track/sector) register */
	.set	RP_of,		0x24		/* offset of OF register */
	.set		RP_16BFORMAT,	0x1000	/* 16-bit (22 sector) format */
	.set	RP_dc,		0x28		/* offset of desired cylinder register */


/********************************************************
 *							*
 *	PROGRAM STARTS HERE				*
 *							*
 ********************************************************/


init:
	.word	0		/* for DEC monitor */

start:
/* padding for various uninteresting reasons */
	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;

nop1:	nop			/* make this a HALT for debugging ! */
	clrl	trace		/* set up for debug/trace */
	mtpr	$0,$IPLR	/* IPL=0 */

/* determine CPU type */
	mfpr	$SID,r0		/* get SID contents */
	extzv	$24,$8,r0,r0	/* extract CPU type into low order and zero extend */
	cmpl	$1,r0		/* 1 = 11/780 */
	beql	1f		/* die if not a 11/780 */
not780:
	halt
1:

/*********
 * NOTE: According to VAX/VMS Internals book, r11 -> Restart Parameter Block
 *********/
	incl trace

/********************************************************
 *							*
 *	find MBA base for the TR # given in R1 from	*
 *	the RPB and init the MBA			*
 *							*
 ********************************************************/
nop2:	nop
	ashl	$13,RPB_regbase+TR(r11),r1  /* get TR # * 0x2000 (8Kbytes) */
	bisl2	$MBA_base0,r1		/* r1 -> MBA_baseN		*/
nop3:	nop
	movl	$MBA_INIT,MBA_cr(r1)	/* init MBA */
nop4:	nop

/********************************************************
 *							*
 *	find base of RP/RM drive registers from the	*
 *	  drive # in R2 from RPB			*
 *	set volume valid and 22 sector mode		*
 *							*
 ********************************************************/
nop5:	nop
	movl	r1,r2			/* copy of MBA_base	*/
	addl2	$RP,r2			/* find drive 0 reg base */
	movl	RPB_regbase+CNTR(r11),r3	/* which controller (== drive) */
	beql	2f			/* drive 0, done */
1:
	addl2	$RP_DROFFSET,r2		/* add offset to skip a set */
	sobgtr	r3,1b
2:		/* r2-> RP_csr of drive N */

nop6:	nop
	movl	$RP_RIP,RP_csr(r2)
	movl	$RP_16BFORMAT,RP_of(r2)	/* 22 sector format */


/********************************************************
 *							*
 *	find the top of physical mem			*
 *	it is left in RPB by VMB.EXE			*
 *							*
 ********************************************************/
	movl	RPB_pfncnt(r11),r7
	movl	r7,pgcount
nop7:	nop

/********************************************************
 *							*
 *	decide where to load level 1 bootloader:	*
 *	  at (top of mem - size of bootloader)		*
 *							*
 ********************************************************/
	movl	$LEV1PAGES,r3
	subl3	r3,r7,r4	/* r4-> page # to load at	*/
	decl	r4		/* 1 page of slop */
	movl	r4,lev1at	/* save the info		*/
nop8:	nop

/********************************************************
 *							*
 *	load MBA registers				*
 *							*
 ********************************************************/
	moval	MBA_map0(r1),r5			/* r5-> first MBA map reg */
1:
	bisl3	$MBA_MAPVALID,r4,(r5)+		/* set valid bit, load page # and continue into map */
	incl	r4				/* bump page address */
	subl2	$1,r3				/* dec page count */
	bgtr	1b				/* set up next map */

	clrl	(r5)				/* set up one more map as a firewall */
						/* WITHOUT a VALID BIT */
nop9:	nop

	clrl	MBA_var(r1)			/* set VAR -> map reg 0, byte 0 */
	mnegl	$LEV1BYTES,MBA_bcr(r1)	/* 2's complement of byte size */

/********************************************************
 *							*
 *	load drive registers				*
 *							*
 ********************************************************/
	movl	$LEV1CYL,RP_dc(r2)	/* cylinder */
	movl	$LEV1START,r7
	insv	$LEV1TRK,$8,$8,r7	/* assemble track and sector */
	movl	r7,RP_da(r2)		/* send to drive */
nop10:	nop

/********************************************************
 *							*
 *	GO!						*
 *							*
 ********************************************************/
	movl	$RP_READ,RP_csr(r2)

1:
	bitl	$MBA_DTBUSY,MBA_sr(r1)	/* still busy?	*/
	bneq	1b			/* yes		*/

		/* transfer completed */
nop11:	nop
	bitl	$MBA_DTABORT,MBA_sr(r1)	/* aborted ?	*/
	beql	1f			/* no - continue*/
abort:
	movl	$MBA_DTABORT,r7
	movl	MBA_sr(r1),r8
abort1:
	halt		/* ABORTED */

1:
	
/********************************************************
 *							*
 *	jump to the level 1 bootloader			*
 *							*
 ********************************************************/
	ashl	$9,lev1at,r7	/* physical page # of lev1 boot, convert to byte address */
	subl3	$0x200,r7,sp	/* establish a stack, below the level 1 boot */
	movl	r11,r9				/* &RPB -> r9 for level 1 bootloader */
	movl	RPB_regbase+CNTR(r11),r11	/* drive # -> r11 for level 1 boot */
	movl	r1,r10				/* &MBA_base -> r10 for level 1 boot */

	addl2	$2,r7		/* skip entry mask */
nop12:	nop
	jmp	(r7)		/* jump to level 1 bootloader */

	/* should never reach here, so pad with some nops to move address
	 * of _end farther away...
	*/
	nop;nop;nop;nop;nop;nop;nop
_end:
	halt


	.align	2		/* word align */
trace:	.long	0		/* trace/debug counter */
pgcount:.long	0		/* mem size from RPB (in pages) */
lev1at:	.long	0		/* page # where lev 1 loaded at */

ident:	.asciz	"$Header: boot0.s,v 1.10 87/04/02 09:50:02 Perrine Stab $\0"	/* for ident */
