* Copyright (c) 1980, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
/* "@(#)tuboot.c 7.2 (Berkeley) 8/28/86" */
* VAX tu58 console cassette boot block
* Helge Skrivervik CSRG/UCB 18jun83
* Reads a program from a rt-11 directory on tape
* and executes it. Programs must be stripped of
* the header and is loaded ``bits as is''.
* You can return to this loader via ``ret'' as
* you are called ``calls $0,ent''.
* Error checking and recovery is almost nonexistant
* due to the severe space constraints.
* NOTE: Any changes to this program are likely to
* bring the size over 512 bytes ....
* Based on tp format bootstrap originally written by Thomas Ferrin.
.set CTABLE
,0x400 /* where to load the rad50 cnv table */
/* rt-11 directory definitions */
.set DIRBLK
,6 /* rt-11 directory starts at block 6 */
.set FILSIZ
,8 /* rt-11 direc entry offset for file size */
.set ENTSIZ
,14 /* size of 1 rt-11 dir entry, bytes */
.set BLKSIZ
,512 /* tape block size, bytes */
.set NUMDIR
,2 /* no. of dir blocks on tape */
.set FNSIZ
,8 /* size of rad50 filename + 2 */
.set NAME
,2 /* direc entry offset for filename */
.set STATUS
,1 /* direc entry offset for entry status */
/* rt-11 directory entry status */
.set RT_ESEG
,8 /* end of directory segment */
.set RT_NULL
,2 /* empty entry */
.set RT_FILE
,4 /* valid file entry */
/* processor registers and bits */
.set TXCS_pr
,7 /* bit position of TXCS ready bit */
.set RXCS_pd
,7 /* bit position of RXCS done bit */
/* console storage registers and bits */
/* TU commands and bits */
.set TU_READY
,7 /* bit position of CSRS ready bit */
.set TU_PACKETLEN
,8 /* length of readcom block */
/* local stack variables */
.set ext
,-4 /* file ext. */
.set name
,-20 /* 12 bytes for full name */
.set rt_name
,-20-FNSIZ
/* rad50 file name */
/* reboot flags for boot */
.set RB_ASK
,3 /* ask name and come up single user */
.word
0 /* entry mask for dec monitor */
nop
;nop
;nop
;nop
;nop
/* some no-ops for 750 boot rom to skip */
movl $RELOC
,fp
/* core loc to which to move this program */
addl3 $rt_name
,fp
,sp
/* set stack pointer; leave room for locals */
movc3 $end
,(r0
),(fp
) /* move boot up to relocated position */
mtpr $TU_BREAK
,$CSTS
/* set break condition */
bsbw xmit2
/* wait 2 character times */
mfpr $CSRD
,r2
/* clear receive buffer */
movzwl $TU_INIT
|(TU_INIT
<<8),r2
/* load 2 INIT opcodes */
bsbw xmit2
/* xmit 'em */
mfpr $CSRD
,r7
/* get recv data */
cmpb r7
,$TU_CONTINUE
/* is it a continue flag? */
bneq
1b
/* nope, look more */
movab
name(fp
),r4
/* start of filename storage */
clrq (r4
) /* init name field */
clrq
rt_name(fp
) /* init rad50 filename */
movzbl $
'=,r0 /* prompt character */
bsbw putc /* output char to main console */
* Read in a file name from console.
movl r4,r1 /* loc at which to store file name */
bsbw getc /* get input char's in file name */
cmpb r0
,$
012 /* terminator ? */
beql start
/* restart if empty string */
clrb (r1
) /* add null byte at end */
* User-specified filename has been stored at name(fp),
* read the entire directory contents into low core.
movl $DIRBLK
,r10
/* directory starts at block DIRBLK */
movl $
(NUMDIR
*BLKSIZ
),r6
/* no. bytes in total dir */
clrl r11
/* start address */
bsbw taper
/* read no. bytes indicated */
* Read in the character conversion table which reside in block 1
* (the second block) on the cassette. Place it after the directory
* on low core (from 0x400).
movl $
1,r10
/* block number */
movl $BLKSIZ
,r6
/* read one block */
* Convert the ascii filename to rad50.
* R4 still points to name(fp)
movl $
6,r3
/* max length of filename */
cmpb $
'.,(r4)+ /* look for '.' */
incl r4 /* point past '.' if ext is present */
clrb -1(r4) /* end name with null */
movl $3,r3 /* max length of extension */
movab ext(fp),r5 /* place extension here */
beql 1f /* the string is null terminated */
movab rt_name(fp),r5 /* ptr to rad50 name */
bsbw rad50 /* convert filename */
bsbw rad50 /* convert extension */
* Search entire directory for user-specified file name.
movab rt_name(fp),r4 /* search for this file */
movl $10,r5 /* point to first file entry */
movzwl -2(r5),r10 /* r10 = block # where files begin */
cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */
beql fndfil /* found match */
addw2 FILSIZ(r5),r10 /* add file length to block pointer */
addl2 $ENTSIZ,r5 /* move to next entry */
/* cpmb STATUS(r5),$RT_NULL /* check if deleted file */
/* beql 1b /* not really necessary since deleted entries will fail */
cmpb STATUS(r5),$RT_ESEG /* check if end of segment */
brw start /* entry not in directory; start over */
* Found desired directory entry
/* start block no., 2 bytes in r10 */
movzwl FILSIZ(r5),r6 /* file size (blocks) */
mull2 $BLKSIZ,r6 /* file size (bytes) */
cmpl r6,$RELOC-512 /* check if file fits below stack */
brw start /* file too large */
* Read in desired file from tape.
movl r6,r5 /* start of bss space */
clrl r11 /* start address */
subl3 r5,$RELOC-4,r0 /* no. bytes to clear */
* Jump to start of file & execute.
* Read (r6) bytes from block (r10)
clrl r8 /* initialize checksum */
movab readcom,r0 /* read command packet addr */
movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */
movzwl (r0)+,r2 /* get 2 chars from block */
bsbb xmit /* xmit and update ckecksum */
sobgtr r1,1b /* loop if more */
* Now do variable part of packet.
movl r6,r2 /* byte count */
movl r10,r2 /* starting block number */
movzwl r8,r2 /* accumulated ckecksum */
* Collect read packet from device.
bsbb recv2 /* get 2 packet characters */
decb r2 /* data packet? */
bneq 1f /* branch on end of data */
movzbl r1,r8 /* get byte count of packet */
bsbb recv1 /* get a char */
movb r1,(r11)+ /* stuff into memory */
sobgtr r8,2b /* loop if more */
bsbb recv2 /* skip checksum */
brb 1b /* read next packet */
* End of data xfer; check for errors.
bsbb recv2 /* get success code */
tstl r1 /* error in read? */
blss 9f /* branch if status error */
bsbb recv2 /* discard 10 bytes */
* Update checksum in r8 and xmit 2 characters.
addw2 r2,r8 /* update checksum */
adwc $0,r8 /* add in carry */
/* send the 2 characters contained in r2 */
bsbb 1f /* xmit one of 'em */
ashl $
-8,r2
,r2
/* get next char */
mfpr $CSTS
,r7
/* get xmit status */
bbc $TU_READY
,r7
,1b
/* loop until ready */
mtpr r2
,$CSTD
/* send char */
* Receive 2 characters, return in r2 and r1.
bsbb recv1
/* recv one of 'em */
movzbl r1
,r2
/* save previous byte */
mfpr $CSRS
,r7
/* get recv status */
bbc $TU_READY
,r7
,1b
/* loop until ready */
mfpr $CSRD
,r1
/* get char */
blss
9b
/* branch on recv error */
bbc $RXCS_pd
,r0
,getc
/* receiver ready ? */
bneq putc
/* echo and return */
bsbb putc
/* carriage return */
/* bsbb putc */ /* delay */
movb $
012,r0
/* send line feed and return */
bbc $TXCS_pr
,r2
,putc
/* transmitter ready ? */
* Convert the filename given from the console
* to radix 50 (rt-11) format.
bsbb getb50
/* get next ascii byte, exit if null */
addl2 r0
,r1
/* last byte, just add it in */
movw r1
,(r5
)+ /* save result */
movzbl (r4
)+,r0
/* get next ascii byte */
beql
1f
/* if zero: end of string */
movzbl
CTABLE(r0
),r0
/* and get the r50 byte from the table*/
tstl (sp
)+ /* we're through, get back to where */
movw r1
,(r5
) /* but first save the result */
.byte
2 /* command packet flag */
.byte
10 /* number of bytes in message */
.byte
2 /* tu read opcode */
.byte
0 /* unit number */
.word
0 /* sequence number */
/* byte count and block number follow */
* Ascii to rad 50 conversion table,
* stored on the second block on the cassette
* NOTE: Always make sure this table ends up
* starting at byte 512!!!!