1*13194Shelge /* tuboot.s 4.1 83/02/16 */ 211099Ssam 311099Ssam /* 411099Ssam * VAX tu58 console cassette boot block 511099Ssam * 611099Ssam * Thomas Ferrin 27oct82 711099Ssam * 811099Ssam * Reads a program from a tp directory on tape 911099Ssam * and executes it. Program must be stripped of 1011099Ssam * the header and is loaded ``bits as is''. 1111099Ssam * You can return to this loader via ``ret'' as 1211099Ssam * you are called ``calls $0,ent''. 13*13194Shelge * 14*13194Shelge * Helge Skrivervik CSRG/UCB 18jun83 15*13194Shelge * Changed to use rt-11 format directory & files 16*13194Shelge * instead of tp format 1711099Ssam */ 1811099Ssam .set RELOC,0x70000 1911099Ssam /* a.out defines */ 2011099Ssam .set HDRSIZ,040 /* size of file header for VAX */ 2111099Ssam .set MAGIC,0410 /* file type id in header */ 2211099Ssam .set TSIZ,4 /* text size */ 2311099Ssam .set DSIZ,8 /* data size */ 2411099Ssam .set BSIZ,12 /* bss size */ 2511099Ssam .set TENT,024 /* task header entry loc */ 26*13194Shelge /* rt-11 directory definitions */ 27*13194Shelge .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 28*13194Shelge .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 29*13194Shelge .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 3011099Ssam .set BLKSIZ,512 /* tape block size, bytes */ 31*13194Shelge .set NUMDIR,2 /* no. of dir blocks on tape */ 32*13194Shelge .set RT_FNSIZ,8 /* size of rad50 filename + 2 */ 33*13194Shelge .set NAME,2 /* direc entry offset for filename */ 34*13194Shelge .set RT_STAT,1 /* direc entry offset for entry status */ 35*13194Shelge /* rt-11 directory entry status */ 36*13194Shelge .set RT_ESEG,8 /* end of directory segment */ 37*13194Shelge .set RT_NULL,2 /* empty entry */ 38*13194Shelge .set RT_FILE,4 /* valid file entry */ 3911099Ssam /* processor registers and bits */ 4011099Ssam .set RXCS,32 4111099Ssam .set RXDB,33 4211099Ssam .set TXCS,34 4311099Ssam .set TXDB,35 4411099Ssam .set RXCS_DONE,0x80 4511099Ssam .set TXCS_RDY,0x80 4611099Ssam .set TXCS_pr,7 /* bit position of TXCS ready bit */ 4711099Ssam .set RXCS_pd,7 /* bit position of RXCS done bit */ 4811099Ssam /* console storage registers and bits */ 4911099Ssam .set CSRS,0x1c 5011099Ssam .set CSRD,0x1d 5111099Ssam .set CSTS,0x1e 5211099Ssam .set CSTD,0x1f 5311099Ssam /* TU commands and bits */ 5411099Ssam .set TU_BREAK,1 5511099Ssam .set TU_INIT,4 5611099Ssam .set TU_CONTINUE,16 5711099Ssam .set TU_READY,7 /* bit position of CSRS ready bit */ 5811099Ssam .set TU_PACKETLEN,8 /* length of readcom block */ 5911099Ssam /* local stack variables */ 60*13194Shelge .set ext,-4 /* file ext. */ 61*13194Shelge .set name,-20 /* 12 bytes for full name */ 62*13194Shelge .set rt_name,-20-RT_FNSIZ /* rad50 file name */ 6311099Ssam 64*13194Shelge /* 65*13194Shelge * Initialization. 66*13194Shelge */ 6711099Ssam init: 6811099Ssam .word 0 /* entry mask for dec monitor */ 6911099Ssam nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 7011099Ssam nop;nop;nop;nop;nop 7111099Ssam movl $RELOC,fp /* core loc to which to move this program */ 7211099Ssam addl3 $name,fp,sp /* set stack pointer; leave room for locals */ 7311099Ssam clrl r0 7411099Ssam 1: 7511099Ssam movc3 $end,(r0),(fp) /* move boot up to relocated position */ 7611099Ssam jmp start+RELOC 7711099Ssam 7811099Ssam start: 7911099Ssam /* init tu58 */ 8011099Ssam mtpr $TU_BREAK,$CSTS /* set break condition */ 81*13194Shelge clrl r2 /* nulls */ 82*13194Shelge bsbw xmit2 /* wait 2 character times */ 83*13194Shelge mfpr $CSRD,r2 /* clear receive buffer */ 8411099Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 85*13194Shelge bsbw xmit2 /* xmit 'em */ 8611099Ssam 1: 87*13194Shelge mfpr $CSRD,r7 /* get recv data */ 8811099Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 89*13194Shelge bneq 1b /* nope, look more */ 9011099Ssam 91*13194Shelge clrq rt_name(fp) /* init rad50 filename */ 9211099Ssam movab name(fp),r4 /* start of filename storage */ 9311099Ssam movzbl $'=,r0 /* prompt character */ 9411099Ssam bsbw putc /* output char to main console */ 9511099Ssam 9611099Ssam /* read in a file name */ 9711099Ssam movl r4,r1 /* loc at which to store file name */ 9811099Ssam nxtc: 9911099Ssam bsbw getc /* get input char's in file name */ 10011099Ssam cmpb r0,$012 /* terminator ? */ 10111099Ssam beql nullc 10211099Ssam movb r0,(r1)+ 10311099Ssam brb nxtc 10411099Ssam nullc: 10511099Ssam subl3 r4,r1,r9 /* size of path name */ 106*13194Shelge beql start /* restart if empty string */ 107*13194Shelge clrb (r1) /* add null byte at end */ 108*13194Shelge incl r9 /* and fix length */ 10911099Ssam 110*13194Shelge /* 111*13194Shelge * user-specified filename has been stored at name(fp) 112*13194Shelge * read in entire directory contents into low core 113*13194Shelge */ 11411099Ssam dirred: 115*13194Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 11611099Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 117*13194Shelge clrl r11 /* start address */ 11811099Ssam bsbw taper /* read no. bytes indicated */ 119*13194Shelge /* 120*13194Shelge * Read in the character conversion table which reside in block 1 121*13194Shelge * (the second block) on the cassette. 122*13194Shelge */ 123*13194Shelge movl $1,r10 /* start block */ 124*13194Shelge movl $BLKSIZ,r6 /* read one block */ 125*13194Shelge movl 0x400,r11 /* place it after the directory */ 126*13194Shelge bsbw taper 12711099Ssam 128*13194Shelge /* 129*13194Shelge * Convert the ascii filename to rad50. 130*13194Shelge */ 131*13194Shelge movab name(fp),r4 /* ptr to ascii name */ 132*13194Shelge movl $6,r3 /* max length of filename */ 133*13194Shelge 1: 134*13194Shelge cmpb $'.,(r4)+ /* look for '.' */ 135*13194Shelge sobgtr r3,1b 136*13194Shelge clrb -1(r4) /* end name with null */ 137*13194Shelge movl $3,r3 /* max length of extension */ 138*13194Shelge movab ext(fp),r5 /* place extension here */ 139*13194Shelge 1: 140*13194Shelge movb (r4)+,(r5)+ 141*13194Shelge beql 1f /* the string is null terminated */ 142*13194Shelge sobgtr r3,1b 143*13194Shelge 1: 144*13194Shelge movab name(fp),r4 145*13194Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 146*13194Shelge bsbw rad50 /* convert filename */ 147*13194Shelge movab ext(fp),r4 148*13194Shelge movab rt_name+4(fp),r5 149*13194Shelge bsbw rad50 /* convert extension */ 150*13194Shelge 151*13194Shelge /* 152*13194Shelge * Search entire directory for user-specified file name. 153*13194Shelge */ 154*13194Shelge 155*13194Shelge movab rt_name(fp),r4 /* search for this file */ 156*13194Shelge movl $10,r5 /* dir buff loc = 0, point to first */ 157*13194Shelge /* file entry */ 158*13194Shelge movzwl -2(r5),r3 /* r3 = block # where files begin */ 159*13194Shelge 2: 160*13194Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 16111099Ssam beql fndfil /* found match */ 162*13194Shelge 1: 163*13194Shelge addw2 FILSIZ(r5),r3 /* add file length to block pointer */ 164*13194Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 165*13194Shelge # cpmb RT_STAT(r5),$RT_NULL /* check if deleted file */ 166*13194Shelge # beql 1b 167*13194Shelge cmpb RT_STAT(r5),$RT_ESEG /* check if end of segment */ 168*13194Shelge bneq 2b 16911099Ssam brw start /* entry not in directory; start over */ 17011099Ssam 171*13194Shelge /* 172*13194Shelge * Found desired directory entry 173*13194Shelge */ 17411099Ssam fndfil: 175*13194Shelge movl r3,r10 /* start block no., 2 bytes */ 176*13194Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 177*13194Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 178*13194Shelge # cmpl r6,$RELOC-512 /* check if file fits below stack */ 179*13194Shelge # blss filok 180*13194Shelge # brw start /* file too large */ 18111099Ssam 182*13194Shelge /* 183*13194Shelge * Read in desired file from tape. 184*13194Shelge */ 18511099Ssam filok: 18611099Ssam movl r6,r5 /* start of bss space */ 187*13194Shelge clrl r11 /* start address */ 18811099Ssam bsbb taper 189*13194Shelge # bsbb rew 19011099Ssam 191*13194Shelge /* 192*13194Shelge * Clear core. 193*13194Shelge */ 19411099Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 19511099Ssam 1: 19611099Ssam clrb (r5)+ 19711099Ssam sobgtr r0,1b 19811099Ssam 199*13194Shelge /* 200*13194Shelge * Jump to start of file & execute. 201*13194Shelge */ 20211099Ssam addl3 $20,fp,ap 20311099Ssam clrl r5 20411099Ssam calls $0,(r5) 20511099Ssam bad: 20611099Ssam brw start 20711099Ssam 20811099Ssam /* rewind tape */ 209*13194Shelge #ifdef notdef 21011099Ssam rew: 211*13194Shelge movb $5,readcom+2 /* position opcode */ 212*13194Shelge clrl r10 /* block 0 */ 213*13194Shelge clrl r6 /* 0 bytes */ 21411099Ssam bsbb taper 215*13194Shelge movb $2,readcom+2 /* read opcode */ 21611099Ssam rsb 217*13194Shelge #endif 21811099Ssam 219*13194Shelge /* read (r6) bytes from (r10) into loc (r11) */ 22011099Ssam taper: 221*13194Shelge clrl r8 /* initialize checksum */ 222*13194Shelge movab readcom,r0 /* read command packet addr */ 22311099Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 22411099Ssam 1: 225*13194Shelge movzwl (r0)+,r2 /* get 2 chars from block */ 226*13194Shelge bsbb xmit /* xmit and update ckecksum */ 227*13194Shelge sobgtr r1,1b /* loop if more */ 22811099Ssam 22911099Ssam /* now do variable part of packet */ 230*13194Shelge movl r6,r2 /* byte count */ 23111099Ssam bsbb xmit 232*13194Shelge movl r10,r2 /* starting block number */ 23311099Ssam bsbb xmit 234*13194Shelge movzwl r8,r2 /* accumulated ckecksum */ 23511099Ssam bsbb xmit 23611099Ssam 23711099Ssam /* collect read packet from device */ 238*13194Shelge movl r11,r0 /* starting addr */ 23911099Ssam 1: 240*13194Shelge bsbb recv2 /* get 2 packet characters */ 241*13194Shelge decb r2 /* data packet? */ 242*13194Shelge bneq 1f /* branch on end of data */ 243*13194Shelge movzbl r1,r8 /* get byte count of packet */ 24411099Ssam 24511099Ssam /* read data into memory */ 24611099Ssam 2: 247*13194Shelge bsbb recv1 /* get a char */ 248*13194Shelge movb r1,(r0)+ /* stuff into memory */ 249*13194Shelge sobgtr r8,2b /* loop if more */ 250*13194Shelge bsbb recv2 /* skip checksum */ 251*13194Shelge brb 1b /* read next packet */ 25211099Ssam 25311099Ssam /* end of data xfer; check for errors */ 25411099Ssam 1: 255*13194Shelge subl2 r6,r0 /* all bytes xfered? */ 256*13194Shelge bneq 9f /* nope, error */ 257*13194Shelge bsbb recv2 /* get success code */ 258*13194Shelge tstl r1 /* error in read? */ 259*13194Shelge blss 9f /* branch if status error */ 26011099Ssam movl $5,r0 26111099Ssam 1: 262*13194Shelge bsbb recv2 /* discard 10 bytes */ 26311099Ssam sobgtr r0,1b 26411099Ssam rsb 26511099Ssam 26611099Ssam /* fatal error */ 26711099Ssam 9: 26811099Ssam movab ermsg,r1 26911099Ssam 1: 27011099Ssam movb (r1)+,r0 27111099Ssam beql bad 27211099Ssam bsbb putc 27311099Ssam brb 1b 27411099Ssam 27511099Ssam /* update checksum in r8 and xmit 2 characters */ 27611099Ssam xmit: 277*13194Shelge addw2 r2,r8 /* update checksum */ 278*13194Shelge bcc xmit2 /* branch if no overflow */ 279*13194Shelge incw r8 /* add in carry */ 28011099Ssam 28111099Ssam /* send the 2 characters contained in r2 */ 28211099Ssam xmit2: 283*13194Shelge bsbb 1f /* xmit one of 'em */ 284*13194Shelge ashl $-8,r2,r2 /* get next char */ 285*13194Shelge /* fall into... */ 28611099Ssam 1: 287*13194Shelge mfpr $CSTS,r7 /* get xmit status */ 288*13194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 289*13194Shelge mtpr r2,$CSTD /* send char */ 29011099Ssam rsb 29111099Ssam 29211099Ssam /* receive 2 characters, return in r2 and r1 */ 29311099Ssam recv2: 294*13194Shelge bsbb recv1 /* recv one of 'em */ 295*13194Shelge /* fall into... */ 29611099Ssam 29711099Ssam /* receive 1 character */ 29811099Ssam recv1: 299*13194Shelge movzbl r1,r2 /* save previous byte */ 30011099Ssam 1: 301*13194Shelge mfpr $CSRS,r7 /* get recv status */ 302*13194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 303*13194Shelge mfpr $CSRD,r1 /* get char */ 304*13194Shelge # blss 9b /* branch on recv error */ 30511099Ssam rsb 30611099Ssam 30711099Ssam getc: 30811099Ssam mfpr $RXCS,r0 30911099Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 31011099Ssam mfpr $RXDB,r0 311*13194Shelge movzbl r0,r0 31211099Ssam cmpb r0,$015 31311099Ssam bneq putc /* echo and return */ 31411099Ssam bsbb putc /* carriage return */ 315*13194Shelge # movb $0,r0 316*13194Shelge # bsbb putc /* delay */ 31711099Ssam movb $012,r0 /* send line feed and return */ 31811099Ssam putc: 31911099Ssam mfpr $TXCS,r2 32011099Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 32111099Ssam mtpr r0,$TXDB 32211099Ssam rsb 32311099Ssam 324*13194Shelge /* 325*13194Shelge * Convert the filename given from the console 326*13194Shelge * to radix 50 (rt-11) format. 327*13194Shelge */ 328*13194Shelge rad50: 329*13194Shelge movl $0x400,r6 /* address of conversion table */ 330*13194Shelge 1: 331*13194Shelge bsbb getb50 /* get next ascii byte, exit if null */ 332*13194Shelge mull3 $03100,r0,r1 333*13194Shelge bsbb getb50 334*13194Shelge mull3 $050,r0,r2 335*13194Shelge addl2 r2,r1 336*13194Shelge bsbb getb50 337*13194Shelge addl2 r0,r1 /* last byte, just add it in */ 338*13194Shelge movw r1,(r5)+ /* save result */ 339*13194Shelge brb 1b 340*13194Shelge 341*13194Shelge getb50: 342*13194Shelge movzbl (r4)+,r0 /* get next ascii byte */ 343*13194Shelge beql 1f /* if zero: end of string */ 344*13194Shelge addl2 r6,r0 /* calculate conversion table address */ 345*13194Shelge movzbl (r0),r0 /* and get the r50 byte from the table*/ 346*13194Shelge rsb 347*13194Shelge 1: 348*13194Shelge tstl (sp)+ /* we're through, get back to where */ 349*13194Shelge /* rad50 was called */ 350*13194Shelge movw r1,(r5) /* but first save the result */ 351*13194Shelge rsb 352*13194Shelge 35311099Ssam .align 2 35411099Ssam readcom: 355*13194Shelge .byte 2 /* command packet flag */ 356*13194Shelge .byte 10 /* number of bytes in message */ 357*13194Shelge .byte 2 /* tu read opcode */ 358*13194Shelge .byte 0 /* modifier */ 359*13194Shelge .byte 0 /* unit number */ 360*13194Shelge .byte 0 /* switches */ 361*13194Shelge .word 0 /* sequence number */ 362*13194Shelge /* byte count and block number follow */ 36311099Ssam 36411099Ssam ermsg: 36511099Ssam .asciz "tu58 err\r\n" 36611099Ssam end: 367