1*d8ef8008Ssam /* tuboot.c 4.6 83/08/01 */ 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 */ 61*d8ef8008Ssam /* reboot flags for boot */ 62*d8ef8008Ssam .set RB_ASK,3 /* ask name and come up single user */ 63f202c1a4Ssam 649b655491Shelge /* 659b655491Shelge * Initialization. 669b655491Shelge */ 67f202c1a4Ssam init: 68f202c1a4Ssam .word 0 /* entry mask for dec monitor */ 69f202c1a4Ssam nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 70f202c1a4Ssam nop;nop;nop;nop;nop 71f202c1a4Ssam movl $RELOC,fp /* core loc to which to move this program */ 72b088da7bShelge addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 73f202c1a4Ssam clrl r0 74f202c1a4Ssam 1: 75f202c1a4Ssam movc3 $end,(r0),(fp) /* move boot up to relocated position */ 76f202c1a4Ssam jmp start+RELOC 77f202c1a4Ssam 78f202c1a4Ssam start: 79f202c1a4Ssam mtpr $TU_BREAK,$CSTS /* set break condition */ 80f202c1a4Ssam clrl r2 /* nulls */ 81f202c1a4Ssam bsbw xmit2 /* wait 2 character times */ 82f202c1a4Ssam mfpr $CSRD,r2 /* clear receive buffer */ 83f202c1a4Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 84f202c1a4Ssam bsbw xmit2 /* xmit 'em */ 85f202c1a4Ssam 1: 86f202c1a4Ssam mfpr $CSRD,r7 /* get recv data */ 87f202c1a4Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 88f202c1a4Ssam bneq 1b /* nope, look more */ 89f202c1a4Ssam 90f202c1a4Ssam movab name(fp),r4 /* start of filename storage */ 91b088da7bShelge clrq (r4) /* init name field */ 92b088da7bShelge clrq name+8(fp) 93b088da7bShelge clrq rt_name(fp) /* init rad50 filename */ 94f202c1a4Ssam movzbl $'=,r0 /* prompt character */ 95f202c1a4Ssam bsbw putc /* output char to main console */ 96f202c1a4Ssam 97b088da7bShelge /* 98b088da7bShelge * Read in a file name from console. 99b088da7bShelge */ 100f202c1a4Ssam movl r4,r1 /* loc at which to store file name */ 101f202c1a4Ssam nxtc: 102f202c1a4Ssam bsbw getc /* get input char's in file name */ 103f202c1a4Ssam cmpb r0,$012 /* terminator ? */ 104f202c1a4Ssam beql nullc 105f202c1a4Ssam movb r0,(r1)+ 106f202c1a4Ssam brb nxtc 107f202c1a4Ssam nullc: 108b088da7bShelge cmpl r4,r1 1099b655491Shelge beql start /* restart if empty string */ 1109b655491Shelge clrb (r1) /* add null byte at end */ 111f202c1a4Ssam 1129b655491Shelge /* 113b088da7bShelge * User-specified filename has been stored at name(fp), 114b088da7bShelge * read the entire directory contents into low core. 1159b655491Shelge */ 116f202c1a4Ssam dirred: 1179b655491Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 118f202c1a4Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 1199b655491Shelge clrl r11 /* start address */ 120f202c1a4Ssam bsbw taper /* read no. bytes indicated */ 1219b655491Shelge /* 1229b655491Shelge * Read in the character conversion table which reside in block 1 123b088da7bShelge * (the second block) on the cassette. Place it after the directory 124b088da7bShelge * on low core (from 0x400). 1259b655491Shelge */ 126b088da7bShelge movl $1,r10 /* block number */ 1279b655491Shelge movl $BLKSIZ,r6 /* read one block */ 1289b655491Shelge bsbw taper 129f202c1a4Ssam 1309b655491Shelge /* 1319b655491Shelge * Convert the ascii filename to rad50. 132b088da7bShelge * R4 still points to name(fp) 1339b655491Shelge */ 1349b655491Shelge movl $6,r3 /* max length of filename */ 1359b655491Shelge 1: 1369b655491Shelge cmpb $'.,(r4)+ /* look for '.' */ 137b088da7bShelge beql 1f 1389b655491Shelge sobgtr r3,1b 139b088da7bShelge incl r4 /* point past '.' if ext is present */ 140b088da7bShelge 1: 1419b655491Shelge clrb -1(r4) /* end name with null */ 1429b655491Shelge movl $3,r3 /* max length of extension */ 1439b655491Shelge movab ext(fp),r5 /* place extension here */ 1449b655491Shelge 1: 1459b655491Shelge movb (r4)+,(r5)+ 1469b655491Shelge beql 1f /* the string is null terminated */ 1479b655491Shelge sobgtr r3,1b 1489b655491Shelge 1: 1499b655491Shelge movab name(fp),r4 1509b655491Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 1519b655491Shelge bsbw rad50 /* convert filename */ 1529b655491Shelge movab ext(fp),r4 1539b655491Shelge movab rt_name+4(fp),r5 1549b655491Shelge bsbw rad50 /* convert extension */ 1559b655491Shelge 1569b655491Shelge /* 1579b655491Shelge * Search entire directory for user-specified file name. 1589b655491Shelge */ 1599b655491Shelge 1609b655491Shelge movab rt_name(fp),r4 /* search for this file */ 161b088da7bShelge movl $10,r5 /* point to first file entry */ 162b088da7bShelge movzwl -2(r5),r10 /* r10 = block # where files begin */ 1639b655491Shelge 2: 1649b655491Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 165f202c1a4Ssam beql fndfil /* found match */ 1669b655491Shelge 1: 167b088da7bShelge addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 1689b655491Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 169b088da7bShelge # cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 170b088da7bShelge # beql 1b /* not really necessary since deleted entries will fail */ 171b088da7bShelge /* to compare anyway */ 172b088da7bShelge cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 1739b655491Shelge bneq 2b 174f202c1a4Ssam brw start /* entry not in directory; start over */ 175f202c1a4Ssam 1769b655491Shelge /* 1779b655491Shelge * Found desired directory entry 1789b655491Shelge */ 179f202c1a4Ssam fndfil: 180b088da7bShelge /* start block no., 2 bytes in r10 */ 1819b655491Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 1829b655491Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 183b088da7bShelge cmpl r6,$RELOC-512 /* check if file fits below stack */ 184b088da7bShelge blss filok 185b088da7bShelge brw start /* file too large */ 186f202c1a4Ssam 1879b655491Shelge /* 1889b655491Shelge * Read in desired file from tape. 1899b655491Shelge */ 190f202c1a4Ssam filok: 191f202c1a4Ssam movl r6,r5 /* start of bss space */ 1929b655491Shelge clrl r11 /* start address */ 193f202c1a4Ssam bsbb taper 194f202c1a4Ssam 1959b655491Shelge /* 1969b655491Shelge * Clear core. 1979b655491Shelge */ 198f202c1a4Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 199f202c1a4Ssam 1: 200f202c1a4Ssam clrb (r5)+ 201f202c1a4Ssam sobgtr r0,1b 202f202c1a4Ssam 2039b655491Shelge /* 2049b655491Shelge * Jump to start of file & execute. 2059b655491Shelge */ 206b088da7bShelge addl3 $20,fp,ap /* ?? */ 207f202c1a4Ssam clrl r5 208*d8ef8008Ssam movl $RB_ASK,r11 209f202c1a4Ssam calls $0,(r5) 210f202c1a4Ssam bad: 211f202c1a4Ssam brw start 212f202c1a4Ssam 213b088da7bShelge /* 214b088da7bShelge * Read (r6) bytes from block (r10) 215b088da7bShelge * into loc (r11). 216b088da7bShelge */ 217f202c1a4Ssam taper: 218f202c1a4Ssam clrl r8 /* initialize checksum */ 219f202c1a4Ssam movab readcom,r0 /* read command packet addr */ 220f202c1a4Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 221f202c1a4Ssam 1: 222f202c1a4Ssam movzwl (r0)+,r2 /* get 2 chars from block */ 223f202c1a4Ssam bsbb xmit /* xmit and update ckecksum */ 224f202c1a4Ssam sobgtr r1,1b /* loop if more */ 225f202c1a4Ssam 226b088da7bShelge /* 227b088da7bShelge * Now do variable part of packet. 228b088da7bShelge */ 229f202c1a4Ssam movl r6,r2 /* byte count */ 230f202c1a4Ssam bsbb xmit 2319b655491Shelge movl r10,r2 /* starting block number */ 232f202c1a4Ssam bsbb xmit 233f202c1a4Ssam movzwl r8,r2 /* accumulated ckecksum */ 234f202c1a4Ssam bsbb xmit 235f202c1a4Ssam 236b088da7bShelge /* 237b088da7bShelge * Collect read packet from device. 238b088da7bShelge */ 239f202c1a4Ssam 1: 240f202c1a4Ssam bsbb recv2 /* get 2 packet characters */ 241f202c1a4Ssam decb r2 /* data packet? */ 242f202c1a4Ssam bneq 1f /* branch on end of data */ 243f202c1a4Ssam movzbl r1,r8 /* get byte count of packet */ 244f202c1a4Ssam 245b088da7bShelge /* 246b088da7bShelge * Read data into memory. 247b088da7bShelge */ 248f202c1a4Ssam 2: 249f202c1a4Ssam bsbb recv1 /* get a char */ 250b088da7bShelge movb r1,(r11)+ /* stuff into memory */ 251f202c1a4Ssam sobgtr r8,2b /* loop if more */ 252f202c1a4Ssam bsbb recv2 /* skip checksum */ 253f202c1a4Ssam brb 1b /* read next packet */ 254f202c1a4Ssam 255b088da7bShelge /* 256b088da7bShelge * End of data xfer; check for errors. 257b088da7bShelge */ 258f202c1a4Ssam 1: 259f202c1a4Ssam bsbb recv2 /* get success code */ 260f202c1a4Ssam tstl r1 /* error in read? */ 261f202c1a4Ssam blss 9f /* branch if status error */ 262f202c1a4Ssam movl $5,r0 263f202c1a4Ssam 1: 264f202c1a4Ssam bsbb recv2 /* discard 10 bytes */ 265f202c1a4Ssam sobgtr r0,1b 266f202c1a4Ssam rsb 267f202c1a4Ssam 268b088da7bShelge /* Fatal error */ 269f202c1a4Ssam 9: 270f202c1a4Ssam movab ermsg,r1 271f202c1a4Ssam 1: 272f202c1a4Ssam movb (r1)+,r0 273f202c1a4Ssam beql bad 274f202c1a4Ssam bsbb putc 275f202c1a4Ssam brb 1b 276f202c1a4Ssam 277b088da7bShelge /* 278b088da7bShelge * Update checksum in r8 and xmit 2 characters. 279b088da7bShelge */ 280f202c1a4Ssam xmit: 281f202c1a4Ssam addw2 r2,r8 /* update checksum */ 282b088da7bShelge adwc $0,r8 /* add in carry */ 283f202c1a4Ssam 284f202c1a4Ssam /* send the 2 characters contained in r2 */ 285f202c1a4Ssam xmit2: 286f202c1a4Ssam bsbb 1f /* xmit one of 'em */ 287f202c1a4Ssam ashl $-8,r2,r2 /* get next char */ 288f202c1a4Ssam /* fall into... */ 289f202c1a4Ssam 1: 290f202c1a4Ssam mfpr $CSTS,r7 /* get xmit status */ 291f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 292f202c1a4Ssam mtpr r2,$CSTD /* send char */ 293f202c1a4Ssam rsb 294f202c1a4Ssam 295b088da7bShelge /* 296b088da7bShelge * Receive 2 characters, return in r2 and r1. 297b088da7bShelge */ 298f202c1a4Ssam recv2: 299f202c1a4Ssam bsbb recv1 /* recv one of 'em */ 300f202c1a4Ssam /* fall into... */ 301f202c1a4Ssam 302b088da7bShelge /* 303b088da7bShelge * Receive 1 character. 304b088da7bShelge */ 305f202c1a4Ssam recv1: 306f202c1a4Ssam movzbl r1,r2 /* save previous byte */ 307f202c1a4Ssam 1: 308f202c1a4Ssam mfpr $CSRS,r7 /* get recv status */ 309f202c1a4Ssam bbc $TU_READY,r7,1b /* loop until ready */ 310f202c1a4Ssam mfpr $CSRD,r1 /* get char */ 3117a58f13fShelge blss 9b /* branch on recv error */ 312f202c1a4Ssam rsb 313f202c1a4Ssam 314f202c1a4Ssam getc: 315f202c1a4Ssam mfpr $RXCS,r0 316f202c1a4Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 317f202c1a4Ssam mfpr $RXDB,r0 318d770ed91Ssam extzv $0,$7,r0,r0 319f202c1a4Ssam cmpb r0,$015 320f202c1a4Ssam bneq putc /* echo and return */ 321f202c1a4Ssam bsbb putc /* carriage return */ 3229b655491Shelge # movb $0,r0 3239b655491Shelge # bsbb putc /* delay */ 324f202c1a4Ssam movb $012,r0 /* send line feed and return */ 325f202c1a4Ssam putc: 326f202c1a4Ssam mfpr $TXCS,r2 327f202c1a4Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 328f202c1a4Ssam mtpr r0,$TXDB 329f202c1a4Ssam rsb 330f202c1a4Ssam 3319b655491Shelge /* 3329b655491Shelge * Convert the filename given from the console 3339b655491Shelge * to radix 50 (rt-11) format. 3349b655491Shelge */ 3359b655491Shelge rad50: 336b088da7bShelge clrw r1 3379b655491Shelge bsbb getb50 /* get next ascii byte, exit if null */ 3389b655491Shelge mull3 $03100,r0,r1 3399b655491Shelge bsbb getb50 3409b655491Shelge mull3 $050,r0,r2 3419b655491Shelge addl2 r2,r1 3429b655491Shelge bsbb getb50 3439b655491Shelge addl2 r0,r1 /* last byte, just add it in */ 3449b655491Shelge movw r1,(r5)+ /* save result */ 345b088da7bShelge brb rad50 3469b655491Shelge 3479b655491Shelge getb50: 3489b655491Shelge movzbl (r4)+,r0 /* get next ascii byte */ 3499b655491Shelge beql 1f /* if zero: end of string */ 350b088da7bShelge movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 3519b655491Shelge rsb 3529b655491Shelge 1: 3539b655491Shelge tstl (sp)+ /* we're through, get back to where */ 3549b655491Shelge /* rad50 was called */ 3559b655491Shelge movw r1,(r5) /* but first save the result */ 3569b655491Shelge rsb 3579b655491Shelge 358f202c1a4Ssam .align 2 359f202c1a4Ssam readcom: 360f202c1a4Ssam .byte 2 /* command packet flag */ 361f202c1a4Ssam .byte 10 /* number of bytes in message */ 362f202c1a4Ssam .byte 2 /* tu read opcode */ 363f202c1a4Ssam .byte 0 /* modifier */ 364f202c1a4Ssam .byte 0 /* unit number */ 365f202c1a4Ssam .byte 0 /* switches */ 366f202c1a4Ssam .word 0 /* sequence number */ 367f202c1a4Ssam /* byte count and block number follow */ 368f202c1a4Ssam 369f202c1a4Ssam ermsg: 370b088da7bShelge .asciz "tuerr\r\n" 371f202c1a4Ssam end: 3727a58f13fShelge 3737a58f13fShelge /* 3747a58f13fShelge * Ascii to rad 50 conversion table, 3757a58f13fShelge * stored on the second block on the cassette 3767a58f13fShelge * 3777a58f13fShelge * NOTE: Always make sure this table ends up 3787a58f13fShelge * starting at byte 512!!!! 3797a58f13fShelge */ 3807a58f13fShelge .align 2 3817a58f13fShelge .data 2 3827a58f13fShelge .long 0x1d1d1d1d 3837a58f13fShelge .long 0x1d1d1d1d 3847a58f13fShelge .long 0x1d1d1d1d 3857a58f13fShelge .long 0x1d1d1d1d 3867a58f13fShelge .long 0x1d1d1d1d 3877a58f13fShelge .long 0x1d1d1d1d 3887a58f13fShelge .long 0x1d1d1d1d 3897a58f13fShelge .long 0x1d1d1d1d 3907a58f13fShelge .long 0x1d1d1d00 3917a58f13fShelge .long 0x1d1d1d1b 3927a58f13fShelge .long 0x1d1d1d1d 3937a58f13fShelge .long 0x1d1c1d1d 3947a58f13fShelge .long 0x21201f1e 3957a58f13fShelge .long 0x25242322 3967a58f13fShelge .long 0x1d1d2726 3977a58f13fShelge .long 0x1d1d1d1d 3987a58f13fShelge .long 0x302011d 3997a58f13fShelge .long 0x7060504 4007a58f13fShelge .long 0xb0a0908 4017a58f13fShelge .long 0xf0e0d0c 4027a58f13fShelge .long 0x13121110 4037a58f13fShelge .long 0x17161514 4047a58f13fShelge .long 0x1d1a1918 4057a58f13fShelge .long 0x1d1d1d1d 4067a58f13fShelge .long 0x302011d 4077a58f13fShelge .long 0x7060504 4087a58f13fShelge .long 0xb0a0908 4097a58f13fShelge .long 0xf0e0d0c 4107a58f13fShelge .long 0x13121110 4117a58f13fShelge .long 0x17161514 4127a58f13fShelge .long 0x1d1a1918 4137a58f13fShelge .long 0x1d1d1d1d 4147a58f13fShelge .long 0x1d1d1d1d 4157a58f13fShelge .long 0x1d1d1d1d 4167a58f13fShelge .long 0x1d1d1d1d 4177a58f13fShelge .long 0x1d1d1d1d 4187a58f13fShelge .long 0x1d1d1d1d 4197a58f13fShelge .long 0x1d1d1d1d 4207a58f13fShelge .long 0x1d1d1d1d 4217a58f13fShelge .long 0x1d1d1d1d 4227a58f13fShelge .long 0x1d1d1d00 4237a58f13fShelge .long 0x1d1d1d1b 4247a58f13fShelge .long 0x1d1d1d1d 4257a58f13fShelge .long 0x1d1c1d1d 4267a58f13fShelge .long 0x21201f1e 4277a58f13fShelge .long 0x25242322 4287a58f13fShelge .long 0x1d1d2726 4297a58f13fShelge .long 0x1d1d1d1d 4307a58f13fShelge .long 0x302011d 4317a58f13fShelge .long 0x7060504 4327a58f13fShelge .long 0xb0a0908 4337a58f13fShelge .long 0xf0e0d0c 4347a58f13fShelge .long 0x13121110 4357a58f13fShelge .long 0x17161514 4367a58f13fShelge .long 0x1d1a1918 4377a58f13fShelge .long 0x1d1d1d1d 4387a58f13fShelge .long 0x302011d 4397a58f13fShelge .long 0x7060504 4407a58f13fShelge .long 0xb0a0908 4417a58f13fShelge .long 0xf0e0d0c 4427a58f13fShelge .long 0x13121110 4437a58f13fShelge .long 0x17161514 4447a58f13fShelge .long 0x1d1a1918 4457a58f13fShelge .long 0x1d1d1d 4467a58f13fShelge .data 447