*
* Unix bootstrap loader -- 40-megabyte disc
*
*	N.B.	Must be assembled with SQUEZ to make it relocatable
*
bootaddr	equ	y'20000'	must be >top of loaded program
*
i.addr	equ	x'78'	10	console input address
i.cmd2	equ	x'79'	a3	console init cmd
d.addr	equ	x'7a'	c7	disc address
*		x'7b'		unused
c.addr	equ	x'7c'	b6	disc controller
s.addr	equ	x'7d'	f0	selch address
os.ext	equ	x'7e'	0000	OS file extension (for LSU) or console def'n
*
LARGE	equ	19	large file bit in inode flags
MAGIC	equ	x'107'	a.out magic number
EOL	equ	x'0d'	carriage return
PROMPT	equ	c'?'
PAUSE	equ	c'-'	flag to go into wait state after loading
WAITPSW	equ	x'8000'	wait-state psw
*
ret	equ	15
ret1	equ	14
work	equ	13
offset	equ	12
count	equ	11
bno	equ	10
inode	equ	09
char	equ	08
cyl	equ	07
head	equ	06
dev	equ	05
disc	equ	04
cntrl	equ	03
selch	equ	02
core	equ	01
*
low	equ	*	loaded into low core by LSU
	org	low+x'60'
	b	start(0,0)
	org	low+x'80'
*
start	equ	*
	li	1,bootaddr		relocation address
	lis	2,0			start at low core
rloop	lm	8,0(2)			move 8 words
	stm	8,0(1,2)
	ahi	2,8*adc			increment core address
	cli	2,high			all moved?
	bl	rloop			no - continue
	b	go-low(1)		execute relocated code
*
go	equ	*
	lh	work,os.ext		OS file extension 0?
	bz	lsu			yes - assume loaded by LSU
	sth	work,i.addr		no - OS extension is really console def
lsu	equ	*
	lm	14,i.addr	save lowcore data
	stm	14,lowsave
	lb	selch,s.addr
	lb	cntrl,c.addr
	lb	disc,d.addr
	la	work,buf	set up disc read buffer addresses
	st	work,bufs
	ahi	work,511
	st	work,bufe
	lis	char,0
	lhi	count,names-ind+12
zeroout	st	char,ind(count)	clear indirect blocks & filename
	sis	count,4
	bnm	zeroout
*
	lhi	char,PROMPT	ask user for filename
	bal	ret1,putc
	lis	count,0
nxtchr1	bal	ret,getc	read a character from console
	bz	lookup		returns 0 at end of line
	chi	char,PAUSE	flag to pause after loading?
	bne	nopause		no - continue
	li	work,WAITPSW	set wait bit
	st	work,ps.start		in start psw
	b	nxtchr1
nopause	equ	*
	stb	char,names(count)	set in filename
	ais	count,1
	b	nxtchr1		note no test for overflow
*
lookup	equ	*
	lis	inode,1		read inode for root directory
	bal	ret,iget
nxtdblk	bal	ret1,rblk	read directory block
	bz	start		start over if end of directory
	la	count,buf
cmpnext	lis	offset,12
	lh	inode,0(count)	directory entry used?
	bz	nextent		no - look at next
nxtchr2	lh	char,2(offset,count)	compare names
	clh	char,names(offset)
	bne	nextent		not equal - look at next entry
	sis	offset,2
	bnm	nxtchr2
	b	gotinod		right name - go read it in
nextent	ahi	count,16	next directory entry
	la	work,buf+512
	cr	count,work
	bl	cmpnext
	b	nxtdblk
*
gotinod	equ	*
	bal	ret,iget	read inode for file
	lis	core,0
nxtsblk	st	core,bufs	read block into core
	ai	core,511
	st	core,bufe
	bal	ret1,rblk
	bz	reloc
	ais	core,1
	b	nxtsblk
*
reloc	equ	*
	l	char,x'0'	check first word
	clhi	char,MAGIC	a.out file?
	bne	finish		no - done
	lis	count,0	yes - relocate to get rid of header
mvsys	l	char,32(count)
	st	char,0(count)
	ais	count,4
	cr	count,core
	bl	mvsys
finish	equ	*
	lm	14,lowsave	restore lowcore data
	stm	14,i.addr
	lpsw	ps.start	go to start address in loaded file
*
* Read inode and indirect blocks
*
iget	equ	*
	ahi	inode,15	find block containing inode
	lr	cyl,inode
	srls	cyl,3	(inode+15)/8
	bal	ret1,rblka	read block
	ni	inode,7		find offset of inode in block
	slls	inode,6		(inode+15) mod 8
	stm	6,regsave	save work regs
	lm	6,buf(inode)	copy inode info from buffer
	stm	6,inod		(up to addr[7])
	lm	6,regsave	restore work regs
*
	la	bno,addr	small file: block addresses in addr
	li	work,LARGE	test for large file
	tbt	work,inod
	bzr	ret
	la	core,ind	large file - read indirect blocks
nxtind	bal	ret1,rblk
	bz	finind
	li	count,508	move indirect block
mvind	l	char,buf(count)
	st	char,0(core,count)
	sis	count,4
	bnm	mvind
	ahi	core,512
	b	nxtind
finind	la	bno,ind		large file: block addresses in ind
	br	ret
*
* Console read and write routines
*
getc	equ	*
	lb	dev,i.addr	console input address
	oc	dev,i.cmd2	initialize
	oc	dev,t.read	start terminal read
getwait	ssr	dev,work	wait for busy == 0
	bc	getwait
	rdr	dev,char	read char from terminal buffer
	nhi	char,x'7f'	clear parity bit
	clhi	char,c'A'	check for alpha
	bl	notran
	clhi	char,c'Z'
	bp	notran
	ohi	char,x'20'	alpha - translate to lowercase
notran	bal	ret1,putc	echo character back
	clhi	char,EOL	end of line?
	bner	ret		no - return (cond. code nonzero)
	lr	ret1,ret
	lis	char,x'0a'	echo extra linefeed
*
putc	equ	*
	lb	dev,i.addr	console output address
	ais	dev,1
	oc	dev,t.write	start terminal writing
	wdr	dev,char	write the character
putwait	ssr	dev,work	wait for busy == 0
	bc	putwait
	br	ret1
*
* Read a disc block
*
rblk	equ	*
	l	cyl,0(bno)	next block number
	bzr	ret1
	ais	bno,4
rblka	equ	*
	xar	head,head
	slls	cyl,1		sector on disc
	d	head,f20	divide by sectors per track
	stb	head,sector	rem is sectorin track
	xar	head,head	quotient is track on disc
	d	head,f20	divide by tracks per disc
	bal	0,cidle
*
	whr	disc,cyl
	oc	disc,d.setcyl
	bal	0,cidle
	oc	disc,d.rstatn
	bal	0,cidle
	oc	disc,d.rsthd
	bal	0,cidle
	whr	disc,head
	oc	disc,d.sethd
	bal	0,cidle
	oc	disc,d.seek
*
	bal	0,cidle
wdisc	equ	*
	ssr	disc,work
	btc	d.nready,wdisc
*
	oc	selch,s.stop	stop selch
	wd	selch,bufs+1	start address to selch
	wh	selch,bufs+2
	wd	selch,bufe+1	end address to selch
	wh	selch,bufe+2
	wd	cntrl,sector	sector to controller
	slls	head,10
	or	cyl,head
	whr	cntrl,cyl
	oc	cntrl,c.read	start controller reading
	oc	selch,s.read	start selch reading
wselch2	ssr	selch,work	sense selch status
	btc	s.busy,wselch2	wait for busy == 0
	oc	selch,s.stop	stop selch
	bal	0,cidle
	br	ret1		(cond code must be nonzero)
*
* wait for controller idle
*
cidle	equ	*
	ssr	cntrl,work
	bfc	c.idle,cidle
	br	0
*
s.busy	equ	8	selector channel busy
c.idle	equ	2	disc controller idle
c.err	equ	5	disc controller error
d.nready	equ	8	disc not-ready-to-seek-read-or-write
d.err	equ	7	disc error
*
	align	8
ps.start dc	0,y'60'		psw to start loaded program
f20	dc	f'20'	sectors per track
d.seek	db	x'c2'	disarm+seek
c.read	db	x'01'	read
s.stop	db	x'48'	stop + extended address read
s.read	db	x'70'	extended address read + read + go
t.write	db	x'a3'
t.read	db	x'a1'
d.sethd	db	x'20'
d.setcyl	db	x'10'
d.rstatn	db	x'08'
d.rsthd	db	x'04'
sector	db	0
	align	adc
high	equ	*	highest location for relocate
*
bufs	equ	*
bufe	equ	bufs+4
lowsave	equ	bufe+4
regsave	equ	8+lowsave
buf	equ	10*adc+regsave
inod	equ	buf+512
mode	equ	inod
addr	equ	3*adc+inod
ind	equ	11*adc+inod
names	equ	8*512+ind
	end
