1*7a58f13fShelge /* tuboot.c 4.4 83/06/22 */ 2f202c1a4Ssam 3f202c1a4Ssam /* 4f202c1a4Ssam * VAX tu58 console cassette boot block 5f202c1a4Ssam * 6b088da7bShelge * Helge Skrivervik CSRG/UCB 18jun83 7f202c1a4Ssam * 8b088da7bShelge * Reads a program from a rt-11 directory on tape 9b088da7bShelge * and executes it. Programs must be stripped of 10f202c1a4Ssam * the header and is loaded ``bits as is''. 11f202c1a4Ssam * You can return to this loader via ``ret'' as 12f202c1a4Ssam * you are called ``calls $0,ent''. 13b088da7bShelge * Error checking and recovery is almost nonexistant 14b088da7bShelge * due to the severe space constraints. 159b655491Shelge * 16b088da7bShelge * NOTE: Any changes to this program are likely to 17b088da7bShelge * bring the size over 512 bytes .... 18b088da7bShelge * 19b088da7bShelge * Based on tp format bootstrap originally written by Thomas Ferrin. 20b088da7bShelge * 21f202c1a4Ssam */ 22b088da7bShelge .set CTABLE,0x400 /* where to load the rad50 cnv table */ 23f202c1a4Ssam .set RELOC,0x70000 249b655491Shelge /* rt-11 directory definitions */ 259b655491Shelge .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 269b655491Shelge .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 279b655491Shelge .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 28f202c1a4Ssam .set BLKSIZ,512 /* tape block size, bytes */ 299b655491Shelge .set NUMDIR,2 /* no. of dir blocks on tape */ 30b088da7bShelge .set FNSIZ,8 /* size of rad50 filename + 2 */ 319b655491Shelge .set NAME,2 /* direc entry offset for filename */ 32b088da7bShelge .set STATUS,1 /* direc entry offset for entry status */ 339b655491Shelge /* rt-11 directory entry status */ 349b655491Shelge .set RT_ESEG,8 /* end of directory segment */ 359b655491Shelge .set RT_NULL,2 /* empty entry */ 369b655491Shelge .set RT_FILE,4 /* valid file entry */ 37f202c1a4Ssam /* processor registers and bits */ 38f202c1a4Ssam .set RXCS,32 39f202c1a4Ssam .set RXDB,33 40f202c1a4Ssam .set TXCS,34 41f202c1a4Ssam .set TXDB,35 42f202c1a4Ssam .set RXCS_DONE,0x80 43f202c1a4Ssam .set TXCS_RDY,0x80 44f202c1a4Ssam .set TXCS_pr,7 /* bit position of TXCS ready bit */ 45f202c1a4Ssam .set RXCS_pd,7 /* bit position of RXCS done bit */ 46f202c1a4Ssam /* console storage registers and bits */ 47f202c1a4Ssam .set CSRS,0x1c 48f202c1a4Ssam .set CSRD,0x1d 49f202c1a4Ssam .set CSTS,0x1e 50f202c1a4Ssam .set CSTD,0x1f 51f202c1a4Ssam /* TU commands and bits */ 52f202c1a4Ssam .set TU_BREAK,1 53f202c1a4Ssam .set TU_INIT,4 54f202c1a4Ssam .set TU_CONTINUE,16 55f202c1a4Ssam .set TU_READY,7 /* bit position of CSRS ready bit */ 56f202c1a4Ssam .set TU_PACKETLEN,8 /* length of readcom block */ 57f202c1a4Ssam /* local stack variables */ 589b655491Shelge .set ext,-4 /* file ext. */ 599b655491Shelge .set name,-20 /* 12 bytes for full name */ 60b088da7bShelge .set rt_name,-20-FNSIZ /* rad50 file name */ 61f202c1a4Ssam 629b655491Shelge /* 639b655491Shelge * Initialization. 649b655491Shelge */ 65f202c1a4Ssam init: 66f202c1a4Ssam .word 0 /* entry mask for dec monitor */ 67f202c1a4Ssam nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 68f202c1a4Ssam nop;nop;nop;nop;nop 69f202c1a4Ssam movl $RELOC,fp /* core loc to which to move this program */ 70b088da7bShelge addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 71f202c1a4Ssam clrl r0 72f202c1a4Ssam 1: 73f202c1a4Ssam movc3 $end,(r0),(fp) /* move boot up to relocated position */ 74f202c1a4Ssam jmp start+RELOC 75f202c1a4Ssam 76f202c1a4Ssam start: 77f202c1a4Ssam mtpr $TU_BREAK,$CSTS /* set break condition */ 78f202c1a4Ssam clrl r2 /* nulls */ 79f202c1a4Ssam bsbw xmit2 /* wait 2 character times */ 80f202c1a4Ssam mfpr $CSRD,r2 /* clear receive buffer */ 81f202c1a4Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 82f202c1a4Ssam bsbw xmit2 /* xmit 'em */ 83f202c1a4Ssam 1: 84f202c1a4Ssam mfpr $CSRD,r7 /* get recv data */ 85f202c1a4Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 86f202c1a4Ssam bneq 1b /* nope, look more */ 87f202c1a4Ssam 88f202c1a4Ssam movab name(fp),r4 /* start of filename storage */ 89b088da7bShelge clrq (r4) /* init name field */ 90b088da7bShelge clrq name+8(fp) 91b088da7bShelge clrq rt_name(fp) /* init rad50 filename */ 92f202c1a4Ssam movzbl $'=,r0 /* prompt character */ 93f202c1a4Ssam bsbw putc /* output char to main console */ 94f202c1a4Ssam 95b088da7bShelge /* 96b088da7bShelge * Read in a file name from console. 97b088da7bShelge */ 98f202c1a4Ssam movl r4,r1 /* loc at which to store file name */ 99f202c1a4Ssam nxtc: 100f202c1a4Ssam bsbw getc /* get input char's in file name */ 101f202c1a4Ssam cmpb r0,$012 /* terminator ? */ 102f202c1a4Ssam beql nullc 103f202c1a4Ssam movb r0,(r1)+ 104f202c1a4Ssam brb nxtc 105f202c1a4Ssam nullc: 106b088da7bShelge cmpl r4,r1 1079b655491Shelge beql start /* restart if empty string */ 1089b655491Shelge clrb (r1) /* add null byte at end */ 109f202c1a4Ssam 1109b655491Shelge /* 111b088da7bShelge * User-specified filename has been stored at name(fp), 112b088da7bShelge * read the entire directory contents into low core. 1139b655491Shelge */ 114f202c1a4Ssam dirred: 1159b655491Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 116f202c1a4Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 1179b655491Shelge clrl r11 /* start address */ 118f202c1a4Ssam bsbw taper /* read no. bytes indicated */ 1199b655491Shelge /* 1209b655491Shelge * Read in the character conversion table which reside in block 1 121b088da7bShelge * (the second block) on the cassette. Place it after the directory 122b088da7bShelge * on low core (from 0x400). 1239b655491Shelge */ 124b088da7bShelge movl $1,r10 /* block number */ 1259b655491Shelge movl $BLKSIZ,r6 /* read one block */ 1269b655491Shelge bsbw taper 127f202c1a4Ssam 1289b655491Shelge /* 1299b655491Shelge * Convert the ascii filename to rad50. 130b088da7bShelge * R4 still points to name(fp) 1319b655491Shelge */ 1329b655491Shelge movl $6,r3 /* max length of filename */ 1339b655491Shelge 1: 1349b655491Shelge cmpb $'.,(r4)+ /* look for '.' */ 135b088da7bShelge beql 1f 1369b655491Shelge sobgtr r3,1b 137b088da7bShelge incl r4 /* point past '.' if ext is present */ 138b088da7bShelge 1: 1399b655491Shelge clrb -1(r4) /* end name with null */ 1409b655491Shelge movl $3,r3 /* max length of extension */ 1419b655491Shelge movab ext(fp),r5 /* place extension here */ 1429b655491Shelge 1: 1439b655491Shelge movb (r4)+,(r5)+ 1449b655491Shelge beql 1f /* the string is null terminated */ 1459b655491Shelge sobgtr r3,1b 1469b655491Shelge 1: 1479b655491Shelge movab name(fp),r4 1489b655491Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 1499b655491Shelge bsbw rad50 /* convert filename */ 1509b655491Shelge movab ext(fp),r4 1519b655491Shelge movab rt_name+4(fp),r5 1529b655491Shelge bsbw rad50 /* convert extension */ 1539b655491Shelge 1549b655491Shelge /* 1559b655491Shelge * Search entire directory for user-specified file name. 1569b655491Shelge */ 1579b655491Shelge 1589b655491Shelge movab rt_name(fp),r4 /* search for this file */ 159b088da7bShelge movl $10,r5 /* point to first file entry */ 160b088da7bShelge movzwl -2(r5),r10 /* r10 = block # where files begin */ 1619b655491Shelge 2: 1629b655491Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 163f202c1a4Ssam beql fndfil /* found match */ 1649b655491Shelge 1: 165b088da7bShelge addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 1669b655491Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 167b088da7bShelge # cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 168b088da7bShelge # beql 1b /* not really necessary since deleted entries will fail */ 169b088da7bShelge /* to compare anyway */ 170b088da7bShelge cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 1719b655491Shelge bneq 2b 172f202c1a4Ssam brw start /* entry not in directory; start over */ 173f202c1a4Ssam 1749b655491Shelge /* 1759b655491Shelge * Found desired directory entry 1769b655491Shelge */ 177f202c1a4Ssam fndfil: 178b088da7bShelge /* start block no., 2 bytes in r10 */ 1799b655491Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 1809b655491Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 181b088da7bShelge cmpl r6,$RELOC-512 /* check if file fits below stack */ 182b088da7bShelge blss filok 183b088da7bShelge brw start /* file too large */ 184f202c1a4Ssam 1859b655491Shelge /* 1869b655491Shelge * Read in desired file from tape. 1879b655491Shelge */ 188f202c1a4Ssam filok: 189f202c1a4Ssam movl r6,r5 /* start of bss space */ 1909b655491Shelge clrl r11 /* start address */ 191f202c1a4Ssam bsbb taper 192f202c1a4Ssam 1939b655491Shelge /* 1949b655491Shelge * Clear core. 1959b655491Shelge */ 196f202c1a4Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 197f202c1a4Ssam 1: 198f202c1a4Ssam clrb (r5)+ 199f202c1a4Ssam sobgtr r0,1b 200f202c1a4Ssam 2019b655491Shelge /* 2029b655491Shelge * Jump to start of file & execute. 2039b655491Shelge */ 204b088da7bShelge addl3 $20,fp,ap /* ?? */ 205f202c1a4Ssam clrl r5 206f202c1a4Ssam calls $0,(r5) 207f202c1a4Ssam bad: 208f202c1a4Ssam brw start 209f202c1a4Ssam 210b088da7bShelge /* 211b088da7bShelge * Read (r6) bytes from block (r10) 212b088da7bShelge * into loc (r11). 213b088da7bShelge */ 214f202c1a4Ssam taper: 215f202c1a4Ssam clrl r8 /* initialize checksum */ 216f202c1a4Ssam movab readcom,r0 /* read command packet addr */ 217f202c1a4Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 218f202c1a4Ssam 1: 219f202c1a4Ssam movzwl (r0)+,r2 /* get 2 chars from block */ 220f202c1a4Ssam bsbb xmit /* xmit and update ckecksum */ 221f202c1a4Ssam sobgtr r1,1b /* loop if more */ 222f202c1a4Ssam 223b088da7bShelge /* 224b088da7bShelge * Now do variable part of packet. 225b088da7bShelge */ 226f202c1a4Ssam movl r6,r2 /* byte count */ 227f202c1a4Ssam bsbb xmit 2289b655491Shelge movl r10,r2 /* starting block number */ 229f202c1a4Ssam bsbb xmit 230f202c1a4Ssam movzwl r8,r2 /* accumulated ckecksum */ 231f202c1a4Ssam bsbb xmit 232f202c1a4Ssam 233b088da7bShelge /* 234b088da7bShelge * Collect read packet from device. 235b088da7bShelge */ 236f202c1a4Ssam 1: 237f202c1a4Ssam bsbb recv2 /* get 2 packet characters */ 238f202c1a4Ssam decb r2 /* data packet? */ 239f202c1a4Ssam bneq 1f /* branch on end of data */ 240f202c1a4Ssam movzbl r1,r8 /* get byte count of packet */ 241f202c1a4Ssam 242b088da7bShelge /* 243b088da7bShelge * Read data into memory. 244b088da7bShelge */ 245f202c1a4Ssam 2: 246f202c1a4Ssam bsbb recv1 /* get a char */ 247b088da7bShelge movb r1,(r11)+ /* stuff into memory */ 248f202c1a4Ssam sobgtr r8,2b /* loop if more */ 249f202c1a4Ssam bsbb recv2 /* skip checksum */ 250f202c1a4Ssam brb 1b /* read next packet */ 251f202c1a4Ssam 252b088da7bShelge /* 253b088da7bShelge * End of data xfer; check for errors. 254b088da7bShelge */ 255f202c1a4Ssam 1: 256f202c1a4Ssam bsbb recv2 /* get success code */ 257f202c1a4Ssam tstl r1 /* error in read? */ 258f202c1a4Ssam blss 9f /* branch if status error */ 259f202c1a4Ssam movl $5,r0 260f202c1a4Ssam 1: 261f202c1a4Ssam bsbb recv2 /* discard 10 bytes */ 262f202c1a4Ssam sobgtr r0,1b 263f202c1a4Ssam rsb 264f202c1a4Ssam 265b088da7bShelge /* Fatal error */ 266f202c1a4Ssam 9: 267f202c1a4Ssam movab ermsg,r1 268f202c1a4Ssam 1: 269f202c1a4Ssam movb (r1)+,r0 270f202c1a4Ssam beql bad 271f202c1a4Ssam bsbb putc 272f202c1a4Ssam brb 1b 273f202c1a4Ssam 274b088da7bShelge /* 275b088da7bShelge * Update checksum in r8 and xmit 2 characters. 276b088da7bShelge */ 277f202c1a4Ssam xmit: 278f202c1a4Ssam addw2 r2,r8 /* update checksum */ 279b088da7bShelge adwc $0,r8 /* add in carry */ 280f202c1a4Ssam 281f202c1a4Ssam /* send the 2 characters contained in r2 */ 282f202c1a4Ssam xmit2: 283f202c1a4Ssam bsbb 1f /* xmit one of 'em */ 284f202c1a4Ssam ashl $-8,r2,r2 /* get next char */ 285f202c1a4Ssam /* fall into... */ 286f202c1a4Ssam 1: 287f202c1a4Ssam mfpr $CSTS,r7 /* get xmit status */ 288f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 289f202c1a4Ssam mtpr r2,$CSTD /* send char */ 290f202c1a4Ssam rsb 291f202c1a4Ssam 292b088da7bShelge /* 293b088da7bShelge * Receive 2 characters, return in r2 and r1. 294b088da7bShelge */ 295f202c1a4Ssam recv2: 296f202c1a4Ssam bsbb recv1 /* recv one of 'em */ 297f202c1a4Ssam /* fall into... */ 298f202c1a4Ssam 299b088da7bShelge /* 300b088da7bShelge * Receive 1 character. 301b088da7bShelge */ 302f202c1a4Ssam recv1: 303f202c1a4Ssam movzbl r1,r2 /* save previous byte */ 304f202c1a4Ssam 1: 305f202c1a4Ssam mfpr $CSRS,r7 /* get recv status */ 306f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 307f202c1a4Ssam mfpr $CSRD,r1 /* get char */ 308*7a58f13fShelge blss 9b /* branch on recv error */ 309f202c1a4Ssam rsb 310f202c1a4Ssam 311f202c1a4Ssam getc: 312f202c1a4Ssam mfpr $RXCS,r0 313f202c1a4Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 314f202c1a4Ssam mfpr $RXDB,r0 3159b655491Shelge movzbl r0,r0 316f202c1a4Ssam cmpb r0,$015 317f202c1a4Ssam bneq putc /* echo and return */ 318f202c1a4Ssam bsbb putc /* carriage return */ 3199b655491Shelge # movb $0,r0 3209b655491Shelge # bsbb putc /* delay */ 321f202c1a4Ssam movb $012,r0 /* send line feed and return */ 322f202c1a4Ssam putc: 323f202c1a4Ssam mfpr $TXCS,r2 324f202c1a4Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 325f202c1a4Ssam mtpr r0,$TXDB 326f202c1a4Ssam rsb 327f202c1a4Ssam 3289b655491Shelge /* 3299b655491Shelge * Convert the filename given from the console 3309b655491Shelge * to radix 50 (rt-11) format. 3319b655491Shelge */ 3329b655491Shelge rad50: 333b088da7bShelge clrw r1 3349b655491Shelge bsbb getb50 /* get next ascii byte, exit if null */ 3359b655491Shelge mull3 $03100,r0,r1 3369b655491Shelge bsbb getb50 3379b655491Shelge mull3 $050,r0,r2 3389b655491Shelge addl2 r2,r1 3399b655491Shelge bsbb getb50 3409b655491Shelge addl2 r0,r1 /* last byte, just add it in */ 3419b655491Shelge movw r1,(r5)+ /* save result */ 342b088da7bShelge brb rad50 3439b655491Shelge 3449b655491Shelge getb50: 3459b655491Shelge movzbl (r4)+,r0 /* get next ascii byte */ 3469b655491Shelge beql 1f /* if zero: end of string */ 347b088da7bShelge movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 3489b655491Shelge rsb 3499b655491Shelge 1: 3509b655491Shelge tstl (sp)+ /* we're through, get back to where */ 3519b655491Shelge /* rad50 was called */ 3529b655491Shelge movw r1,(r5) /* but first save the result */ 3539b655491Shelge rsb 3549b655491Shelge 355f202c1a4Ssam .align 2 356f202c1a4Ssam readcom: 357f202c1a4Ssam .byte 2 /* command packet flag */ 358f202c1a4Ssam .byte 10 /* number of bytes in message */ 359f202c1a4Ssam .byte 2 /* tu read opcode */ 360f202c1a4Ssam .byte 0 /* modifier */ 361f202c1a4Ssam .byte 0 /* unit number */ 362f202c1a4Ssam .byte 0 /* switches */ 363f202c1a4Ssam .word 0 /* sequence number */ 364f202c1a4Ssam /* byte count and block number follow */ 365f202c1a4Ssam 366f202c1a4Ssam ermsg: 367b088da7bShelge .asciz "tu err\r\n" 368f202c1a4Ssam end: 369*7a58f13fShelge 370*7a58f13fShelge /* 371*7a58f13fShelge * Ascii to rad 50 conversion table, 372*7a58f13fShelge * stored on the second block on the cassette 373*7a58f13fShelge * 374*7a58f13fShelge * NOTE: Always make sure this table ends up 375*7a58f13fShelge * starting at byte 512!!!! 376*7a58f13fShelge */ 377*7a58f13fShelge .align 2 378*7a58f13fShelge .data 2 379*7a58f13fShelge .long 0x1d1d1d1d 380*7a58f13fShelge .long 0x1d1d1d1d 381*7a58f13fShelge .long 0x1d1d1d1d 382*7a58f13fShelge .long 0x1d1d1d1d 383*7a58f13fShelge .long 0x1d1d1d1d 384*7a58f13fShelge .long 0x1d1d1d1d 385*7a58f13fShelge .long 0x1d1d1d1d 386*7a58f13fShelge .long 0x1d1d1d1d 387*7a58f13fShelge .long 0x1d1d1d00 388*7a58f13fShelge .long 0x1d1d1d1b 389*7a58f13fShelge .long 0x1d1d1d1d 390*7a58f13fShelge .long 0x1d1c1d1d 391*7a58f13fShelge .long 0x21201f1e 392*7a58f13fShelge .long 0x25242322 393*7a58f13fShelge .long 0x1d1d2726 394*7a58f13fShelge .long 0x1d1d1d1d 395*7a58f13fShelge .long 0x302011d 396*7a58f13fShelge .long 0x7060504 397*7a58f13fShelge .long 0xb0a0908 398*7a58f13fShelge .long 0xf0e0d0c 399*7a58f13fShelge .long 0x13121110 400*7a58f13fShelge .long 0x17161514 401*7a58f13fShelge .long 0x1d1a1918 402*7a58f13fShelge .long 0x1d1d1d1d 403*7a58f13fShelge .long 0x302011d 404*7a58f13fShelge .long 0x7060504 405*7a58f13fShelge .long 0xb0a0908 406*7a58f13fShelge .long 0xf0e0d0c 407*7a58f13fShelge .long 0x13121110 408*7a58f13fShelge .long 0x17161514 409*7a58f13fShelge .long 0x1d1a1918 410*7a58f13fShelge .long 0x1d1d1d1d 411*7a58f13fShelge .long 0x1d1d1d1d 412*7a58f13fShelge .long 0x1d1d1d1d 413*7a58f13fShelge .long 0x1d1d1d1d 414*7a58f13fShelge .long 0x1d1d1d1d 415*7a58f13fShelge .long 0x1d1d1d1d 416*7a58f13fShelge .long 0x1d1d1d1d 417*7a58f13fShelge .long 0x1d1d1d1d 418*7a58f13fShelge .long 0x1d1d1d1d 419*7a58f13fShelge .long 0x1d1d1d00 420*7a58f13fShelge .long 0x1d1d1d1b 421*7a58f13fShelge .long 0x1d1d1d1d 422*7a58f13fShelge .long 0x1d1c1d1d 423*7a58f13fShelge .long 0x21201f1e 424*7a58f13fShelge .long 0x25242322 425*7a58f13fShelge .long 0x1d1d2726 426*7a58f13fShelge .long 0x1d1d1d1d 427*7a58f13fShelge .long 0x302011d 428*7a58f13fShelge .long 0x7060504 429*7a58f13fShelge .long 0xb0a0908 430*7a58f13fShelge .long 0xf0e0d0c 431*7a58f13fShelge .long 0x13121110 432*7a58f13fShelge .long 0x17161514 433*7a58f13fShelge .long 0x1d1a1918 434*7a58f13fShelge .long 0x1d1d1d1d 435*7a58f13fShelge .long 0x302011d 436*7a58f13fShelge .long 0x7060504 437*7a58f13fShelge .long 0xb0a0908 438*7a58f13fShelge .long 0xf0e0d0c 439*7a58f13fShelge .long 0x13121110 440*7a58f13fShelge .long 0x17161514 441*7a58f13fShelge .long 0x1d1a1918 442*7a58f13fShelge .long 0x1d1d1d 443*7a58f13fShelge .data 444