11de60267Smckusick /* 2a81f7f72Smckusick * Copyright (c) 1980, 1986 Regents of the University of California. 31de60267Smckusick * All rights reserved. The Berkeley software License Agreement 41de60267Smckusick * specifies the terms and conditions for redistribution. 51de60267Smckusick */ 61de60267Smckusick 7*8f26171aSkarels /* "@(#)tuboot.c 7.2 (Berkeley) 08/28/86" */ 8f202c1a4Ssam 9f202c1a4Ssam /* 10f202c1a4Ssam * VAX tu58 console cassette boot block 11f202c1a4Ssam * 12b088da7bShelge * Helge Skrivervik CSRG/UCB 18jun83 13f202c1a4Ssam * 14b088da7bShelge * Reads a program from a rt-11 directory on tape 15b088da7bShelge * and executes it. Programs must be stripped of 16f202c1a4Ssam * the header and is loaded ``bits as is''. 17f202c1a4Ssam * You can return to this loader via ``ret'' as 18f202c1a4Ssam * you are called ``calls $0,ent''. 19b088da7bShelge * Error checking and recovery is almost nonexistant 20b088da7bShelge * due to the severe space constraints. 219b655491Shelge * 22b088da7bShelge * NOTE: Any changes to this program are likely to 23b088da7bShelge * bring the size over 512 bytes .... 24b088da7bShelge * 25b088da7bShelge * Based on tp format bootstrap originally written by Thomas Ferrin. 26b088da7bShelge * 27f202c1a4Ssam */ 28b088da7bShelge .set CTABLE,0x400 /* where to load the rad50 cnv table */ 29f202c1a4Ssam .set RELOC,0x70000 309b655491Shelge /* rt-11 directory definitions */ 319b655491Shelge .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 329b655491Shelge .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 339b655491Shelge .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 34f202c1a4Ssam .set BLKSIZ,512 /* tape block size, bytes */ 359b655491Shelge .set NUMDIR,2 /* no. of dir blocks on tape */ 36b088da7bShelge .set FNSIZ,8 /* size of rad50 filename + 2 */ 379b655491Shelge .set NAME,2 /* direc entry offset for filename */ 38b088da7bShelge .set STATUS,1 /* direc entry offset for entry status */ 399b655491Shelge /* rt-11 directory entry status */ 409b655491Shelge .set RT_ESEG,8 /* end of directory segment */ 419b655491Shelge .set RT_NULL,2 /* empty entry */ 429b655491Shelge .set RT_FILE,4 /* valid file entry */ 43f202c1a4Ssam /* processor registers and bits */ 44f202c1a4Ssam .set RXCS,32 45f202c1a4Ssam .set RXDB,33 46f202c1a4Ssam .set TXCS,34 47f202c1a4Ssam .set TXDB,35 48f202c1a4Ssam .set RXCS_DONE,0x80 49f202c1a4Ssam .set TXCS_RDY,0x80 50f202c1a4Ssam .set TXCS_pr,7 /* bit position of TXCS ready bit */ 51f202c1a4Ssam .set RXCS_pd,7 /* bit position of RXCS done bit */ 52f202c1a4Ssam /* console storage registers and bits */ 53f202c1a4Ssam .set CSRS,0x1c 54f202c1a4Ssam .set CSRD,0x1d 55f202c1a4Ssam .set CSTS,0x1e 56f202c1a4Ssam .set CSTD,0x1f 57f202c1a4Ssam /* TU commands and bits */ 58f202c1a4Ssam .set TU_BREAK,1 59f202c1a4Ssam .set TU_INIT,4 60f202c1a4Ssam .set TU_CONTINUE,16 61f202c1a4Ssam .set TU_READY,7 /* bit position of CSRS ready bit */ 62f202c1a4Ssam .set TU_PACKETLEN,8 /* length of readcom block */ 63f202c1a4Ssam /* local stack variables */ 649b655491Shelge .set ext,-4 /* file ext. */ 659b655491Shelge .set name,-20 /* 12 bytes for full name */ 66b088da7bShelge .set rt_name,-20-FNSIZ /* rad50 file name */ 67d8ef8008Ssam /* reboot flags for boot */ 68d8ef8008Ssam .set RB_ASK,3 /* ask name and come up single user */ 69f202c1a4Ssam 709b655491Shelge /* 719b655491Shelge * Initialization. 729b655491Shelge */ 73f202c1a4Ssam init: 74f202c1a4Ssam .word 0 /* entry mask for dec monitor */ 75f202c1a4Ssam nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 76f202c1a4Ssam nop;nop;nop;nop;nop 77f202c1a4Ssam movl $RELOC,fp /* core loc to which to move this program */ 78b088da7bShelge addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 79f202c1a4Ssam clrl r0 80f202c1a4Ssam 1: 81f202c1a4Ssam movc3 $end,(r0),(fp) /* move boot up to relocated position */ 82f202c1a4Ssam jmp start+RELOC 83f202c1a4Ssam 84f202c1a4Ssam start: 85f202c1a4Ssam mtpr $TU_BREAK,$CSTS /* set break condition */ 86f202c1a4Ssam clrl r2 /* nulls */ 87f202c1a4Ssam bsbw xmit2 /* wait 2 character times */ 88f202c1a4Ssam mfpr $CSRD,r2 /* clear receive buffer */ 89f202c1a4Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 90f202c1a4Ssam bsbw xmit2 /* xmit 'em */ 91f202c1a4Ssam 1: 92f202c1a4Ssam mfpr $CSRD,r7 /* get recv data */ 93f202c1a4Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 94f202c1a4Ssam bneq 1b /* nope, look more */ 95f202c1a4Ssam 96f202c1a4Ssam movab name(fp),r4 /* start of filename storage */ 97b088da7bShelge clrq (r4) /* init name field */ 98b088da7bShelge clrq name+8(fp) 99b088da7bShelge clrq rt_name(fp) /* init rad50 filename */ 100f202c1a4Ssam movzbl $'=,r0 /* prompt character */ 101f202c1a4Ssam bsbw putc /* output char to main console */ 102f202c1a4Ssam 103b088da7bShelge /* 104b088da7bShelge * Read in a file name from console. 105b088da7bShelge */ 106f202c1a4Ssam movl r4,r1 /* loc at which to store file name */ 107f202c1a4Ssam nxtc: 108f202c1a4Ssam bsbw getc /* get input char's in file name */ 109f202c1a4Ssam cmpb r0,$012 /* terminator ? */ 110f202c1a4Ssam beql nullc 111f202c1a4Ssam movb r0,(r1)+ 112f202c1a4Ssam brb nxtc 113f202c1a4Ssam nullc: 114b088da7bShelge cmpl r4,r1 1159b655491Shelge beql start /* restart if empty string */ 1169b655491Shelge clrb (r1) /* add null byte at end */ 117f202c1a4Ssam 1189b655491Shelge /* 119b088da7bShelge * User-specified filename has been stored at name(fp), 120b088da7bShelge * read the entire directory contents into low core. 1219b655491Shelge */ 122f202c1a4Ssam dirred: 1239b655491Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 124f202c1a4Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 1259b655491Shelge clrl r11 /* start address */ 126f202c1a4Ssam bsbw taper /* read no. bytes indicated */ 1279b655491Shelge /* 1289b655491Shelge * Read in the character conversion table which reside in block 1 129b088da7bShelge * (the second block) on the cassette. Place it after the directory 130b088da7bShelge * on low core (from 0x400). 1319b655491Shelge */ 132b088da7bShelge movl $1,r10 /* block number */ 1339b655491Shelge movl $BLKSIZ,r6 /* read one block */ 1349b655491Shelge bsbw taper 135f202c1a4Ssam 1369b655491Shelge /* 1379b655491Shelge * Convert the ascii filename to rad50. 138b088da7bShelge * R4 still points to name(fp) 1399b655491Shelge */ 1409b655491Shelge movl $6,r3 /* max length of filename */ 1419b655491Shelge 1: 1429b655491Shelge cmpb $'.,(r4)+ /* look for '.' */ 143b088da7bShelge beql 1f 1449b655491Shelge sobgtr r3,1b 145b088da7bShelge incl r4 /* point past '.' if ext is present */ 146b088da7bShelge 1: 1479b655491Shelge clrb -1(r4) /* end name with null */ 1489b655491Shelge movl $3,r3 /* max length of extension */ 1499b655491Shelge movab ext(fp),r5 /* place extension here */ 1509b655491Shelge 1: 1519b655491Shelge movb (r4)+,(r5)+ 1529b655491Shelge beql 1f /* the string is null terminated */ 1539b655491Shelge sobgtr r3,1b 1549b655491Shelge 1: 1559b655491Shelge movab name(fp),r4 1569b655491Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 1579b655491Shelge bsbw rad50 /* convert filename */ 1589b655491Shelge movab ext(fp),r4 1599b655491Shelge movab rt_name+4(fp),r5 1609b655491Shelge bsbw rad50 /* convert extension */ 1619b655491Shelge 1629b655491Shelge /* 1639b655491Shelge * Search entire directory for user-specified file name. 1649b655491Shelge */ 1659b655491Shelge 1669b655491Shelge movab rt_name(fp),r4 /* search for this file */ 167b088da7bShelge movl $10,r5 /* point to first file entry */ 168b088da7bShelge movzwl -2(r5),r10 /* r10 = block # where files begin */ 1699b655491Shelge 2: 1709b655491Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 171f202c1a4Ssam beql fndfil /* found match */ 1729b655491Shelge 1: 173b088da7bShelge addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 1749b655491Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 175*8f26171aSkarels /* cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 176*8f26171aSkarels /* beql 1b /* not really necessary since deleted entries will fail */ 177b088da7bShelge /* to compare anyway */ 178b088da7bShelge cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 1799b655491Shelge bneq 2b 180f202c1a4Ssam brw start /* entry not in directory; start over */ 181f202c1a4Ssam 1829b655491Shelge /* 1839b655491Shelge * Found desired directory entry 1849b655491Shelge */ 185f202c1a4Ssam fndfil: 186b088da7bShelge /* start block no., 2 bytes in r10 */ 1879b655491Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 1889b655491Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 189b088da7bShelge cmpl r6,$RELOC-512 /* check if file fits below stack */ 190b088da7bShelge blss filok 191b088da7bShelge brw start /* file too large */ 192f202c1a4Ssam 1939b655491Shelge /* 1949b655491Shelge * Read in desired file from tape. 1959b655491Shelge */ 196f202c1a4Ssam filok: 197f202c1a4Ssam movl r6,r5 /* start of bss space */ 1989b655491Shelge clrl r11 /* start address */ 199f202c1a4Ssam bsbb taper 200f202c1a4Ssam 2019b655491Shelge /* 2029b655491Shelge * Clear core. 2039b655491Shelge */ 204f202c1a4Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 205f202c1a4Ssam 1: 206f202c1a4Ssam clrb (r5)+ 207f202c1a4Ssam sobgtr r0,1b 208f202c1a4Ssam 2099b655491Shelge /* 2109b655491Shelge * Jump to start of file & execute. 2119b655491Shelge */ 212b088da7bShelge addl3 $20,fp,ap /* ?? */ 213f202c1a4Ssam clrl r5 214d8ef8008Ssam movl $RB_ASK,r11 215f202c1a4Ssam calls $0,(r5) 216f202c1a4Ssam bad: 217f202c1a4Ssam brw start 218f202c1a4Ssam 219b088da7bShelge /* 220b088da7bShelge * Read (r6) bytes from block (r10) 221b088da7bShelge * into loc (r11). 222b088da7bShelge */ 223f202c1a4Ssam taper: 224f202c1a4Ssam clrl r8 /* initialize checksum */ 225f202c1a4Ssam movab readcom,r0 /* read command packet addr */ 226f202c1a4Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 227f202c1a4Ssam 1: 228f202c1a4Ssam movzwl (r0)+,r2 /* get 2 chars from block */ 229f202c1a4Ssam bsbb xmit /* xmit and update ckecksum */ 230f202c1a4Ssam sobgtr r1,1b /* loop if more */ 231f202c1a4Ssam 232b088da7bShelge /* 233b088da7bShelge * Now do variable part of packet. 234b088da7bShelge */ 235f202c1a4Ssam movl r6,r2 /* byte count */ 236f202c1a4Ssam bsbb xmit 2379b655491Shelge movl r10,r2 /* starting block number */ 238f202c1a4Ssam bsbb xmit 239f202c1a4Ssam movzwl r8,r2 /* accumulated ckecksum */ 240f202c1a4Ssam bsbb xmit 241f202c1a4Ssam 242b088da7bShelge /* 243b088da7bShelge * Collect read packet from device. 244b088da7bShelge */ 245f202c1a4Ssam 1: 246f202c1a4Ssam bsbb recv2 /* get 2 packet characters */ 247f202c1a4Ssam decb r2 /* data packet? */ 248f202c1a4Ssam bneq 1f /* branch on end of data */ 249f202c1a4Ssam movzbl r1,r8 /* get byte count of packet */ 250f202c1a4Ssam 251b088da7bShelge /* 252b088da7bShelge * Read data into memory. 253b088da7bShelge */ 254f202c1a4Ssam 2: 255f202c1a4Ssam bsbb recv1 /* get a char */ 256b088da7bShelge movb r1,(r11)+ /* stuff into memory */ 257f202c1a4Ssam sobgtr r8,2b /* loop if more */ 258f202c1a4Ssam bsbb recv2 /* skip checksum */ 259f202c1a4Ssam brb 1b /* read next packet */ 260f202c1a4Ssam 261b088da7bShelge /* 262b088da7bShelge * End of data xfer; check for errors. 263b088da7bShelge */ 264f202c1a4Ssam 1: 265f202c1a4Ssam bsbb recv2 /* get success code */ 266f202c1a4Ssam tstl r1 /* error in read? */ 267f202c1a4Ssam blss 9f /* branch if status error */ 268f202c1a4Ssam movl $5,r0 269f202c1a4Ssam 1: 270f202c1a4Ssam bsbb recv2 /* discard 10 bytes */ 271f202c1a4Ssam sobgtr r0,1b 272f202c1a4Ssam rsb 273f202c1a4Ssam 274b088da7bShelge /* Fatal error */ 275f202c1a4Ssam 9: 276f202c1a4Ssam movab ermsg,r1 277f202c1a4Ssam 1: 278f202c1a4Ssam movb (r1)+,r0 279f202c1a4Ssam beql bad 280f202c1a4Ssam bsbb putc 281f202c1a4Ssam brb 1b 282f202c1a4Ssam 283b088da7bShelge /* 284b088da7bShelge * Update checksum in r8 and xmit 2 characters. 285b088da7bShelge */ 286f202c1a4Ssam xmit: 287f202c1a4Ssam addw2 r2,r8 /* update checksum */ 288b088da7bShelge adwc $0,r8 /* add in carry */ 289f202c1a4Ssam 290f202c1a4Ssam /* send the 2 characters contained in r2 */ 291f202c1a4Ssam xmit2: 292f202c1a4Ssam bsbb 1f /* xmit one of 'em */ 293f202c1a4Ssam ashl $-8,r2,r2 /* get next char */ 294f202c1a4Ssam /* fall into... */ 295f202c1a4Ssam 1: 296f202c1a4Ssam mfpr $CSTS,r7 /* get xmit status */ 297f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 298f202c1a4Ssam mtpr r2,$CSTD /* send char */ 299f202c1a4Ssam rsb 300f202c1a4Ssam 301b088da7bShelge /* 302b088da7bShelge * Receive 2 characters, return in r2 and r1. 303b088da7bShelge */ 304f202c1a4Ssam recv2: 305f202c1a4Ssam bsbb recv1 /* recv one of 'em */ 306f202c1a4Ssam /* fall into... */ 307f202c1a4Ssam 308b088da7bShelge /* 309b088da7bShelge * Receive 1 character. 310b088da7bShelge */ 311f202c1a4Ssam recv1: 312f202c1a4Ssam movzbl r1,r2 /* save previous byte */ 313f202c1a4Ssam 1: 314f202c1a4Ssam mfpr $CSRS,r7 /* get recv status */ 315f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 316f202c1a4Ssam mfpr $CSRD,r1 /* get char */ 3177a58f13fShelge blss 9b /* branch on recv error */ 318f202c1a4Ssam rsb 319f202c1a4Ssam 320f202c1a4Ssam getc: 321f202c1a4Ssam mfpr $RXCS,r0 322f202c1a4Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 323f202c1a4Ssam mfpr $RXDB,r0 324d770ed91Ssam extzv $0,$7,r0,r0 325f202c1a4Ssam cmpb r0,$015 326f202c1a4Ssam bneq putc /* echo and return */ 327f202c1a4Ssam bsbb putc /* carriage return */ 328*8f26171aSkarels /* movb $0,r0 */ 329*8f26171aSkarels /* bsbb putc */ /* delay */ 330f202c1a4Ssam movb $012,r0 /* send line feed and return */ 331f202c1a4Ssam putc: 332f202c1a4Ssam mfpr $TXCS,r2 333f202c1a4Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 334f202c1a4Ssam mtpr r0,$TXDB 335f202c1a4Ssam rsb 336f202c1a4Ssam 3379b655491Shelge /* 3389b655491Shelge * Convert the filename given from the console 3399b655491Shelge * to radix 50 (rt-11) format. 3409b655491Shelge */ 3419b655491Shelge rad50: 342b088da7bShelge clrw r1 3439b655491Shelge bsbb getb50 /* get next ascii byte, exit if null */ 3449b655491Shelge mull3 $03100,r0,r1 3459b655491Shelge bsbb getb50 3469b655491Shelge mull3 $050,r0,r2 3479b655491Shelge addl2 r2,r1 3489b655491Shelge bsbb getb50 3499b655491Shelge addl2 r0,r1 /* last byte, just add it in */ 3509b655491Shelge movw r1,(r5)+ /* save result */ 351b088da7bShelge brb rad50 3529b655491Shelge 3539b655491Shelge getb50: 3549b655491Shelge movzbl (r4)+,r0 /* get next ascii byte */ 3559b655491Shelge beql 1f /* if zero: end of string */ 356b088da7bShelge movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 3579b655491Shelge rsb 3589b655491Shelge 1: 3599b655491Shelge tstl (sp)+ /* we're through, get back to where */ 3609b655491Shelge /* rad50 was called */ 3619b655491Shelge movw r1,(r5) /* but first save the result */ 3629b655491Shelge rsb 3639b655491Shelge 364f202c1a4Ssam .align 2 365f202c1a4Ssam readcom: 366f202c1a4Ssam .byte 2 /* command packet flag */ 367f202c1a4Ssam .byte 10 /* number of bytes in message */ 368f202c1a4Ssam .byte 2 /* tu read opcode */ 369f202c1a4Ssam .byte 0 /* modifier */ 370f202c1a4Ssam .byte 0 /* unit number */ 371f202c1a4Ssam .byte 0 /* switches */ 372f202c1a4Ssam .word 0 /* sequence number */ 373f202c1a4Ssam /* byte count and block number follow */ 374f202c1a4Ssam 375f202c1a4Ssam ermsg: 376b088da7bShelge .asciz "tuerr\r\n" 377f202c1a4Ssam end: 3787a58f13fShelge 3797a58f13fShelge /* 3807a58f13fShelge * Ascii to rad 50 conversion table, 3817a58f13fShelge * stored on the second block on the cassette 3827a58f13fShelge * 3837a58f13fShelge * NOTE: Always make sure this table ends up 3847a58f13fShelge * starting at byte 512!!!! 3857a58f13fShelge */ 3867a58f13fShelge .align 2 3877a58f13fShelge .data 2 3887a58f13fShelge .long 0x1d1d1d1d 3897a58f13fShelge .long 0x1d1d1d1d 3907a58f13fShelge .long 0x1d1d1d1d 3917a58f13fShelge .long 0x1d1d1d1d 3927a58f13fShelge .long 0x1d1d1d1d 3937a58f13fShelge .long 0x1d1d1d1d 3947a58f13fShelge .long 0x1d1d1d1d 3957a58f13fShelge .long 0x1d1d1d1d 3967a58f13fShelge .long 0x1d1d1d00 3977a58f13fShelge .long 0x1d1d1d1b 3987a58f13fShelge .long 0x1d1d1d1d 3997a58f13fShelge .long 0x1d1c1d1d 4007a58f13fShelge .long 0x21201f1e 4017a58f13fShelge .long 0x25242322 4027a58f13fShelge .long 0x1d1d2726 4037a58f13fShelge .long 0x1d1d1d1d 4047a58f13fShelge .long 0x302011d 4057a58f13fShelge .long 0x7060504 4067a58f13fShelge .long 0xb0a0908 4077a58f13fShelge .long 0xf0e0d0c 4087a58f13fShelge .long 0x13121110 4097a58f13fShelge .long 0x17161514 4107a58f13fShelge .long 0x1d1a1918 4117a58f13fShelge .long 0x1d1d1d1d 4127a58f13fShelge .long 0x302011d 4137a58f13fShelge .long 0x7060504 4147a58f13fShelge .long 0xb0a0908 4157a58f13fShelge .long 0xf0e0d0c 4167a58f13fShelge .long 0x13121110 4177a58f13fShelge .long 0x17161514 4187a58f13fShelge .long 0x1d1a1918 4197a58f13fShelge .long 0x1d1d1d1d 4207a58f13fShelge .long 0x1d1d1d1d 4217a58f13fShelge .long 0x1d1d1d1d 4227a58f13fShelge .long 0x1d1d1d1d 4237a58f13fShelge .long 0x1d1d1d1d 4247a58f13fShelge .long 0x1d1d1d1d 4257a58f13fShelge .long 0x1d1d1d1d 4267a58f13fShelge .long 0x1d1d1d1d 4277a58f13fShelge .long 0x1d1d1d1d 4287a58f13fShelge .long 0x1d1d1d00 4297a58f13fShelge .long 0x1d1d1d1b 4307a58f13fShelge .long 0x1d1d1d1d 4317a58f13fShelge .long 0x1d1c1d1d 4327a58f13fShelge .long 0x21201f1e 4337a58f13fShelge .long 0x25242322 4347a58f13fShelge .long 0x1d1d2726 4357a58f13fShelge .long 0x1d1d1d1d 4367a58f13fShelge .long 0x302011d 4377a58f13fShelge .long 0x7060504 4387a58f13fShelge .long 0xb0a0908 4397a58f13fShelge .long 0xf0e0d0c 4407a58f13fShelge .long 0x13121110 4417a58f13fShelge .long 0x17161514 4427a58f13fShelge .long 0x1d1a1918 4437a58f13fShelge .long 0x1d1d1d1d 4447a58f13fShelge .long 0x302011d 4457a58f13fShelge .long 0x7060504 4467a58f13fShelge .long 0xb0a0908 4477a58f13fShelge .long 0xf0e0d0c 4487a58f13fShelge .long 0x13121110 4497a58f13fShelge .long 0x17161514 4507a58f13fShelge .long 0x1d1a1918 4517a58f13fShelge .long 0x1d1d1d 4527a58f13fShelge .data 453