1: /* 2: * Copyright (c) 1980, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: /* "@(#)tuboot.s 7.1 (Berkeley) 6/5/86" */ 8: 9: /* 10: * VAX tu58 console cassette boot block 11: * 12: * Helge Skrivervik CSRG/UCB 18jun83 13: * 14: * Reads a program from a rt-11 directory on tape 15: * and executes it. Programs must be stripped of 16: * the header and is loaded ``bits as is''. 17: * You can return to this loader via ``ret'' as 18: * you are called ``calls $0,ent''. 19: * Error checking and recovery is almost nonexistant 20: * due to the severe space constraints. 21: * 22: * NOTE: Any changes to this program are likely to 23: * bring the size over 512 bytes .... 24: * 25: * Based on tp format bootstrap originally written by Thomas Ferrin. 26: * 27: */ 28: .set CTABLE,0x400 /* where to load the rad50 cnv table */ 29: .set RELOC,0x70000 30: /* rt-11 directory definitions */ 31: .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 32: .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 33: .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 34: .set BLKSIZ,512 /* tape block size, bytes */ 35: .set NUMDIR,2 /* no. of dir blocks on tape */ 36: .set FNSIZ,8 /* size of rad50 filename + 2 */ 37: .set NAME,2 /* direc entry offset for filename */ 38: .set STATUS,1 /* direc entry offset for entry status */ 39: /* rt-11 directory entry status */ 40: .set RT_ESEG,8 /* end of directory segment */ 41: .set RT_NULL,2 /* empty entry */ 42: .set RT_FILE,4 /* valid file entry */ 43: /* processor registers and bits */ 44: .set RXCS,32 45: .set RXDB,33 46: .set TXCS,34 47: .set TXDB,35 48: .set RXCS_DONE,0x80 49: .set TXCS_RDY,0x80 50: .set TXCS_pr,7 /* bit position of TXCS ready bit */ 51: .set RXCS_pd,7 /* bit position of RXCS done bit */ 52: /* console storage registers and bits */ 53: .set CSRS,0x1c 54: .set CSRD,0x1d 55: .set CSTS,0x1e 56: .set CSTD,0x1f 57: /* TU commands and bits */ 58: .set TU_BREAK,1 59: .set TU_INIT,4 60: .set TU_CONTINUE,16 61: .set TU_READY,7 /* bit position of CSRS ready bit */ 62: .set TU_PACKETLEN,8 /* length of readcom block */ 63: /* local stack variables */ 64: .set ext,-4 /* file ext. */ 65: .set name,-20 /* 12 bytes for full name */ 66: .set rt_name,-20-FNSIZ /* rad50 file name */ 67: /* reboot flags for boot */ 68: .set RB_ASK,3 /* ask name and come up single user */ 69: 70: /* 71: * Initialization. 72: */ 73: init: 74: .word 0 /* entry mask for dec monitor */ 75: nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 76: nop;nop;nop;nop;nop 77: movl $RELOC,fp /* core loc to which to move this program */ 78: addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 79: clrl r0 80: 1: 81: movc3 $end,(r0),(fp) /* move boot up to relocated position */ 82: jmp start+RELOC 83: 84: start: 85: mtpr $TU_BREAK,$CSTS /* set break condition */ 86: clrl r2 /* nulls */ 87: bsbw xmit2 /* wait 2 character times */ 88: mfpr $CSRD,r2 /* clear receive buffer */ 89: movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 90: bsbw xmit2 /* xmit 'em */ 91: 1: 92: mfpr $CSRD,r7 /* get recv data */ 93: cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 94: bneq 1b /* nope, look more */ 95: 96: movab name(fp),r4 /* start of filename storage */ 97: clrq (r4) /* init name field */ 98: clrq name+8(fp) 99: clrq rt_name(fp) /* init rad50 filename */ 100: movzbl $'=,r0 /* prompt character */ 101: bsbw putc /* output char to main console */ 102: 103: /* 104: * Read in a file name from console. 105: */ 106: movl r4,r1 /* loc at which to store file name */ 107: nxtc: 108: bsbw getc /* get input char's in file name */ 109: cmpb r0,$012 /* terminator ? */ 110: beql nullc 111: movb r0,(r1)+ 112: brb nxtc 113: nullc: 114: cmpl r4,r1 115: beql start /* restart if empty string */ 116: clrb (r1) /* add null byte at end */ 117: 118: /* 119: * User-specified filename has been stored at name(fp), 120: * read the entire directory contents into low core. 121: */ 122: dirred: 123: movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 124: movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 125: clrl r11 /* start address */ 126: bsbw taper /* read no. bytes indicated */ 127: /* 128: * Read in the character conversion table which reside in block 1 129: * (the second block) on the cassette. Place it after the directory 130: * on low core (from 0x400). 131: */ 132: movl $1,r10 /* block number */ 133: movl $BLKSIZ,r6 /* read one block */ 134: bsbw taper 135: 136: /* 137: * Convert the ascii filename to rad50. 138: * R4 still points to name(fp) 139: */ 140: movl $6,r3 /* max length of filename */ 141: 1: 142: cmpb $'.,(r4)+ /* look for '.' */ 143: beql 1f 144: sobgtr r3,1b 145: incl r4 /* point past '.' if ext is present */ 146: 1: 147: clrb -1(r4) /* end name with null */ 148: movl $3,r3 /* max length of extension */ 149: movab ext(fp),r5 /* place extension here */ 150: 1: 151: movb (r4)+,(r5)+ 152: beql 1f /* the string is null terminated */ 153: sobgtr r3,1b 154: 1: 155: movab name(fp),r4 156: movab rt_name(fp),r5 /* ptr to rad50 name */ 157: bsbw rad50 /* convert filename */ 158: movab ext(fp),r4 159: movab rt_name+4(fp),r5 160: bsbw rad50 /* convert extension */ 161: 162: /* 163: * Search entire directory for user-specified file name. 164: */ 165: 166: movab rt_name(fp),r4 /* search for this file */ 167: movl $10,r5 /* point to first file entry */ 168: movzwl -2(r5),r10 /* r10 = block # where files begin */ 169: 2: 170: cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 171: beql fndfil /* found match */ 172: 1: 173: addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 174: addl2 $ENTSIZ,r5 /* move to next entry */ 175: # cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 176: # beql 1b /* not really necessary since deleted entries will fail */ 177: /* to compare anyway */ 178: cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 179: bneq 2b 180: brw start /* entry not in directory; start over */ 181: 182: /* 183: * Found desired directory entry 184: */ 185: fndfil: 186: /* start block no., 2 bytes in r10 */ 187: movzwl FILSIZ(r5),r6 /* file size (blocks) */ 188: mull2 $BLKSIZ,r6 /* file size (bytes) */ 189: cmpl r6,$RELOC-512 /* check if file fits below stack */ 190: blss filok 191: brw start /* file too large */ 192: 193: /* 194: * Read in desired file from tape. 195: */ 196: filok: 197: movl r6,r5 /* start of bss space */ 198: clrl r11 /* start address */ 199: bsbb taper 200: 201: /* 202: * Clear core. 203: */ 204: subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 205: 1: 206: clrb (r5)+ 207: sobgtr r0,1b 208: 209: /* 210: * Jump to start of file & execute. 211: */ 212: addl3 $20,fp,ap /* ?? */ 213: clrl r5 214: movl $RB_ASK,r11 215: calls $0,(r5) 216: bad: 217: brw start 218: 219: /* 220: * Read (r6) bytes from block (r10) 221: * into loc (r11). 222: */ 223: taper: 224: clrl r8 /* initialize checksum */ 225: movab readcom,r0 /* read command packet addr */ 226: movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 227: 1: 228: movzwl (r0)+,r2 /* get 2 chars from block */ 229: bsbb xmit /* xmit and update ckecksum */ 230: sobgtr r1,1b /* loop if more */ 231: 232: /* 233: * Now do variable part of packet. 234: */ 235: movl r6,r2 /* byte count */ 236: bsbb xmit 237: movl r10,r2 /* starting block number */ 238: bsbb xmit 239: movzwl r8,r2 /* accumulated ckecksum */ 240: bsbb xmit 241: 242: /* 243: * Collect read packet from device. 244: */ 245: 1: 246: bsbb recv2 /* get 2 packet characters */ 247: decb r2 /* data packet? */ 248: bneq 1f /* branch on end of data */ 249: movzbl r1,r8 /* get byte count of packet */ 250: 251: /* 252: * Read data into memory. 253: */ 254: 2: 255: bsbb recv1 /* get a char */ 256: movb r1,(r11)+ /* stuff into memory */ 257: sobgtr r8,2b /* loop if more */ 258: bsbb recv2 /* skip checksum */ 259: brb 1b /* read next packet */ 260: 261: /* 262: * End of data xfer; check for errors. 263: */ 264: 1: 265: bsbb recv2 /* get success code */ 266: tstl r1 /* error in read? */ 267: blss 9f /* branch if status error */ 268: movl $5,r0 269: 1: 270: bsbb recv2 /* discard 10 bytes */ 271: sobgtr r0,1b 272: rsb 273: 274: /* Fatal error */ 275: 9: 276: movab ermsg,r1 277: 1: 278: movb (r1)+,r0 279: beql bad 280: bsbb putc 281: brb 1b 282: 283: /* 284: * Update checksum in r8 and xmit 2 characters. 285: */ 286: xmit: 287: addw2 r2,r8 /* update checksum */ 288: adwc $0,r8 /* add in carry */ 289: 290: /* send the 2 characters contained in r2 */ 291: xmit2: 292: bsbb 1f /* xmit one of 'em */ 293: ashl $-8,r2,r2 /* get next char */ 294: /* fall into... */ 295: 1: 296: mfpr $CSTS,r7 /* get xmit status */ 297: bbc $TU_READY,r7,1b /* loop until ready */ 298: mtpr r2,$CSTD /* send char */ 299: rsb 300: 301: /* 302: * Receive 2 characters, return in r2 and r1. 303: */ 304: recv2: 305: bsbb recv1 /* recv one of 'em */ 306: /* fall into... */ 307: 308: /* 309: * Receive 1 character. 310: */ 311: recv1: 312: movzbl r1,r2 /* save previous byte */ 313: 1: 314: mfpr $CSRS,r7 /* get recv status */ 315: bbc $TU_READY,r7,1b /* loop until ready */ 316: mfpr $CSRD,r1 /* get char */ 317: blss 9b /* branch on recv error */ 318: rsb 319: 320: getc: 321: mfpr $RXCS,r0 322: bbc $RXCS_pd,r0,getc /* receiver ready ? */ 323: mfpr $RXDB,r0 324: extzv $0,$7,r0,r0 325: cmpb r0,$015 326: bneq putc /* echo and return */ 327: bsbb putc /* carriage return */ 328: # movb $0,r0 329: # bsbb putc /* delay */ 330: movb $012,r0 /* send line feed and return */ 331: putc: 332: mfpr $TXCS,r2 333: bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 334: mtpr r0,$TXDB 335: rsb 336: 337: /* 338: * Convert the filename given from the console 339: * to radix 50 (rt-11) format. 340: */ 341: rad50: 342: clrw r1 343: bsbb getb50 /* get next ascii byte, exit if null */ 344: mull3 $03100,r0,r1 345: bsbb getb50 346: mull3 $050,r0,r2 347: addl2 r2,r1 348: bsbb getb50 349: addl2 r0,r1 /* last byte, just add it in */ 350: movw r1,(r5)+ /* save result */ 351: brb rad50 352: 353: getb50: 354: movzbl (r4)+,r0 /* get next ascii byte */ 355: beql 1f /* if zero: end of string */ 356: movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 357: rsb 358: 1: 359: tstl (sp)+ /* we're through, get back to where */ 360: /* rad50 was called */ 361: movw r1,(r5) /* but first save the result */ 362: rsb 363: 364: .align 2 365: readcom: 366: .byte 2 /* command packet flag */ 367: .byte 10 /* number of bytes in message */ 368: .byte 2 /* tu read opcode */ 369: .byte 0 /* modifier */ 370: .byte 0 /* unit number */ 371: .byte 0 /* switches */ 372: .word 0 /* sequence number */ 373: /* byte count and block number follow */ 374: 375: ermsg: 376: .asciz "tuerr\r\n" 377: end: 378: 379: /* 380: * Ascii to rad 50 conversion table, 381: * stored on the second block on the cassette 382: * 383: * NOTE: Always make sure this table ends up 384: * starting at byte 512!!!! 385: */ 386: .align 2 387: .data 2 388: .long 0x1d1d1d1d 389: .long 0x1d1d1d1d 390: .long 0x1d1d1d1d 391: .long 0x1d1d1d1d 392: .long 0x1d1d1d1d 393: .long 0x1d1d1d1d 394: .long 0x1d1d1d1d 395: .long 0x1d1d1d1d 396: .long 0x1d1d1d00 397: .long 0x1d1d1d1b 398: .long 0x1d1d1d1d 399: .long 0x1d1c1d1d 400: .long 0x21201f1e 401: .long 0x25242322 402: .long 0x1d1d2726 403: .long 0x1d1d1d1d 404: .long 0x302011d 405: .long 0x7060504 406: .long 0xb0a0908 407: .long 0xf0e0d0c 408: .long 0x13121110 409: .long 0x17161514 410: .long 0x1d1a1918 411: .long 0x1d1d1d1d 412: .long 0x302011d 413: .long 0x7060504 414: .long 0xb0a0908 415: .long 0xf0e0d0c 416: .long 0x13121110 417: .long 0x17161514 418: .long 0x1d1a1918 419: .long 0x1d1d1d1d 420: .long 0x1d1d1d1d 421: .long 0x1d1d1d1d 422: .long 0x1d1d1d1d 423: .long 0x1d1d1d1d 424: .long 0x1d1d1d1d 425: .long 0x1d1d1d1d 426: .long 0x1d1d1d1d 427: .long 0x1d1d1d1d 428: .long 0x1d1d1d00 429: .long 0x1d1d1d1b 430: .long 0x1d1d1d1d 431: .long 0x1d1c1d1d 432: .long 0x21201f1e 433: .long 0x25242322 434: .long 0x1d1d2726 435: .long 0x1d1d1d1d 436: .long 0x302011d 437: .long 0x7060504 438: .long 0xb0a0908 439: .long 0xf0e0d0c 440: .long 0x13121110 441: .long 0x17161514 442: .long 0x1d1a1918 443: .long 0x1d1d1d1d 444: .long 0x302011d 445: .long 0x7060504 446: .long 0xb0a0908 447: .long 0xf0e0d0c 448: .long 0x13121110 449: .long 0x17161514 450: .long 0x1d1a1918 451: .long 0x1d1d1d 452: .data