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