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