1*13237Shelge /* tuboot.c 4.4 83/06/22 */ 211099Ssam 311099Ssam /* 411099Ssam * VAX tu58 console cassette boot block 511099Ssam * 613210Shelge * Helge Skrivervik CSRG/UCB 18jun83 711099Ssam * 813210Shelge * Reads a program from a rt-11 directory on tape 913210Shelge * and executes it. Programs 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''. 1313210Shelge * Error checking and recovery is almost nonexistant 1413210Shelge * due to the severe space constraints. 1513210Shelge * 1613210Shelge * NOTE: Any changes to this program are likely to 1713210Shelge * bring the size over 512 bytes .... 1813210Shelge * 1913210Shelge * Based on tp format bootstrap originally written by Thomas Ferrin. 2013210Shelge * 2111099Ssam */ 2213210Shelge .set CTABLE,0x400 /* where to load the rad50 cnv table */ 2311099Ssam .set RELOC,0x70000 2413194Shelge /* rt-11 directory definitions */ 2513194Shelge .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 2613194Shelge .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 2713194Shelge .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 2811099Ssam .set BLKSIZ,512 /* tape block size, bytes */ 2913194Shelge .set NUMDIR,2 /* no. of dir blocks on tape */ 3013210Shelge .set FNSIZ,8 /* size of rad50 filename + 2 */ 3113194Shelge .set NAME,2 /* direc entry offset for filename */ 3213210Shelge .set STATUS,1 /* direc entry offset for entry status */ 3313194Shelge /* rt-11 directory entry status */ 3413194Shelge .set RT_ESEG,8 /* end of directory segment */ 3513194Shelge .set RT_NULL,2 /* empty entry */ 3613194Shelge .set RT_FILE,4 /* valid file entry */ 3711099Ssam /* processor registers and bits */ 3811099Ssam .set RXCS,32 3911099Ssam .set RXDB,33 4011099Ssam .set TXCS,34 4111099Ssam .set TXDB,35 4211099Ssam .set RXCS_DONE,0x80 4311099Ssam .set TXCS_RDY,0x80 4411099Ssam .set TXCS_pr,7 /* bit position of TXCS ready bit */ 4511099Ssam .set RXCS_pd,7 /* bit position of RXCS done bit */ 4611099Ssam /* console storage registers and bits */ 4711099Ssam .set CSRS,0x1c 4811099Ssam .set CSRD,0x1d 4911099Ssam .set CSTS,0x1e 5011099Ssam .set CSTD,0x1f 5111099Ssam /* TU commands and bits */ 5211099Ssam .set TU_BREAK,1 5311099Ssam .set TU_INIT,4 5411099Ssam .set TU_CONTINUE,16 5511099Ssam .set TU_READY,7 /* bit position of CSRS ready bit */ 5611099Ssam .set TU_PACKETLEN,8 /* length of readcom block */ 5711099Ssam /* local stack variables */ 5813194Shelge .set ext,-4 /* file ext. */ 5913194Shelge .set name,-20 /* 12 bytes for full name */ 6013210Shelge .set rt_name,-20-FNSIZ /* rad50 file name */ 6111099Ssam 6213194Shelge /* 6313194Shelge * Initialization. 6413194Shelge */ 6511099Ssam init: 6611099Ssam .word 0 /* entry mask for dec monitor */ 6711099Ssam nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 6811099Ssam nop;nop;nop;nop;nop 6911099Ssam movl $RELOC,fp /* core loc to which to move this program */ 7013210Shelge addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 7111099Ssam clrl r0 7211099Ssam 1: 7311099Ssam movc3 $end,(r0),(fp) /* move boot up to relocated position */ 7411099Ssam jmp start+RELOC 7511099Ssam 7611099Ssam start: 7711099Ssam mtpr $TU_BREAK,$CSTS /* set break condition */ 7813194Shelge clrl r2 /* nulls */ 7913194Shelge bsbw xmit2 /* wait 2 character times */ 8013194Shelge mfpr $CSRD,r2 /* clear receive buffer */ 8111099Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 8213194Shelge bsbw xmit2 /* xmit 'em */ 8311099Ssam 1: 8413194Shelge mfpr $CSRD,r7 /* get recv data */ 8511099Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 8613194Shelge bneq 1b /* nope, look more */ 8711099Ssam 8813210Shelge movab name(fp),r4 /* start of filename storage */ 8913210Shelge clrq (r4) /* init name field */ 9013210Shelge clrq name+8(fp) 9113194Shelge clrq rt_name(fp) /* init rad50 filename */ 9211099Ssam movzbl $'=,r0 /* prompt character */ 9311099Ssam bsbw putc /* output char to main console */ 9411099Ssam 9513210Shelge /* 9613210Shelge * Read in a file name from console. 9713210Shelge */ 9811099Ssam movl r4,r1 /* loc at which to store file name */ 9911099Ssam nxtc: 10011099Ssam bsbw getc /* get input char's in file name */ 10111099Ssam cmpb r0,$012 /* terminator ? */ 10211099Ssam beql nullc 10311099Ssam movb r0,(r1)+ 10411099Ssam brb nxtc 10511099Ssam nullc: 10613210Shelge cmpl r4,r1 10713194Shelge beql start /* restart if empty string */ 10813194Shelge clrb (r1) /* add null byte at end */ 10911099Ssam 11013194Shelge /* 11113210Shelge * User-specified filename has been stored at name(fp), 11213210Shelge * read the entire directory contents into low core. 11313194Shelge */ 11411099Ssam dirred: 11513194Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 11611099Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 11713194Shelge clrl r11 /* start address */ 11811099Ssam bsbw taper /* read no. bytes indicated */ 11913194Shelge /* 12013194Shelge * Read in the character conversion table which reside in block 1 12113210Shelge * (the second block) on the cassette. Place it after the directory 12213210Shelge * on low core (from 0x400). 12313194Shelge */ 12413210Shelge movl $1,r10 /* block number */ 12513194Shelge movl $BLKSIZ,r6 /* read one block */ 12613194Shelge bsbw taper 12711099Ssam 12813194Shelge /* 12913194Shelge * Convert the ascii filename to rad50. 13013210Shelge * R4 still points to name(fp) 13113194Shelge */ 13213194Shelge movl $6,r3 /* max length of filename */ 13313194Shelge 1: 13413194Shelge cmpb $'.,(r4)+ /* look for '.' */ 13513210Shelge beql 1f 13613194Shelge sobgtr r3,1b 13713210Shelge incl r4 /* point past '.' if ext is present */ 13813210Shelge 1: 13913194Shelge clrb -1(r4) /* end name with null */ 14013194Shelge movl $3,r3 /* max length of extension */ 14113194Shelge movab ext(fp),r5 /* place extension here */ 14213194Shelge 1: 14313194Shelge movb (r4)+,(r5)+ 14413194Shelge beql 1f /* the string is null terminated */ 14513194Shelge sobgtr r3,1b 14613194Shelge 1: 14713194Shelge movab name(fp),r4 14813194Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 14913194Shelge bsbw rad50 /* convert filename */ 15013194Shelge movab ext(fp),r4 15113194Shelge movab rt_name+4(fp),r5 15213194Shelge bsbw rad50 /* convert extension */ 15313194Shelge 15413194Shelge /* 15513194Shelge * Search entire directory for user-specified file name. 15613194Shelge */ 15713194Shelge 15813194Shelge movab rt_name(fp),r4 /* search for this file */ 15913210Shelge movl $10,r5 /* point to first file entry */ 16013210Shelge movzwl -2(r5),r10 /* r10 = block # where files begin */ 16113194Shelge 2: 16213194Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 16311099Ssam beql fndfil /* found match */ 16413194Shelge 1: 16513210Shelge addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 16613194Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 16713210Shelge # cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 16813210Shelge # beql 1b /* not really necessary since deleted entries will fail */ 16913210Shelge /* to compare anyway */ 17013210Shelge cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 17113194Shelge bneq 2b 17211099Ssam brw start /* entry not in directory; start over */ 17311099Ssam 17413194Shelge /* 17513194Shelge * Found desired directory entry 17613194Shelge */ 17711099Ssam fndfil: 17813210Shelge /* start block no., 2 bytes in r10 */ 17913194Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 18013194Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 18113210Shelge cmpl r6,$RELOC-512 /* check if file fits below stack */ 18213210Shelge blss filok 18313210Shelge brw start /* file too large */ 18411099Ssam 18513194Shelge /* 18613194Shelge * Read in desired file from tape. 18713194Shelge */ 18811099Ssam filok: 18911099Ssam movl r6,r5 /* start of bss space */ 19013194Shelge clrl r11 /* start address */ 19111099Ssam bsbb taper 19211099Ssam 19313194Shelge /* 19413194Shelge * Clear core. 19513194Shelge */ 19611099Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 19711099Ssam 1: 19811099Ssam clrb (r5)+ 19911099Ssam sobgtr r0,1b 20011099Ssam 20113194Shelge /* 20213194Shelge * Jump to start of file & execute. 20313194Shelge */ 20413210Shelge addl3 $20,fp,ap /* ?? */ 20511099Ssam clrl r5 20611099Ssam calls $0,(r5) 20711099Ssam bad: 20811099Ssam brw start 20911099Ssam 21013210Shelge /* 21113210Shelge * Read (r6) bytes from block (r10) 21213210Shelge * into loc (r11). 21313210Shelge */ 21411099Ssam taper: 21513194Shelge clrl r8 /* initialize checksum */ 21613194Shelge movab readcom,r0 /* read command packet addr */ 21711099Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 21811099Ssam 1: 21913194Shelge movzwl (r0)+,r2 /* get 2 chars from block */ 22013194Shelge bsbb xmit /* xmit and update ckecksum */ 22113194Shelge sobgtr r1,1b /* loop if more */ 22211099Ssam 22313210Shelge /* 22413210Shelge * Now do variable part of packet. 22513210Shelge */ 22613194Shelge movl r6,r2 /* byte count */ 22711099Ssam bsbb xmit 22813194Shelge movl r10,r2 /* starting block number */ 22911099Ssam bsbb xmit 23013194Shelge movzwl r8,r2 /* accumulated ckecksum */ 23111099Ssam bsbb xmit 23211099Ssam 23313210Shelge /* 23413210Shelge * Collect read packet from device. 23513210Shelge */ 23611099Ssam 1: 23713194Shelge bsbb recv2 /* get 2 packet characters */ 23813194Shelge decb r2 /* data packet? */ 23913194Shelge bneq 1f /* branch on end of data */ 24013194Shelge movzbl r1,r8 /* get byte count of packet */ 24111099Ssam 24213210Shelge /* 24313210Shelge * Read data into memory. 24413210Shelge */ 24511099Ssam 2: 24613194Shelge bsbb recv1 /* get a char */ 24713210Shelge movb r1,(r11)+ /* stuff into memory */ 24813194Shelge sobgtr r8,2b /* loop if more */ 24913194Shelge bsbb recv2 /* skip checksum */ 25013194Shelge brb 1b /* read next packet */ 25111099Ssam 25213210Shelge /* 25313210Shelge * End of data xfer; check for errors. 25413210Shelge */ 25511099Ssam 1: 25613194Shelge bsbb recv2 /* get success code */ 25713194Shelge tstl r1 /* error in read? */ 25813194Shelge blss 9f /* branch if status error */ 25911099Ssam movl $5,r0 26011099Ssam 1: 26113194Shelge bsbb recv2 /* discard 10 bytes */ 26211099Ssam sobgtr r0,1b 26311099Ssam rsb 26411099Ssam 26513210Shelge /* Fatal error */ 26611099Ssam 9: 26711099Ssam movab ermsg,r1 26811099Ssam 1: 26911099Ssam movb (r1)+,r0 27011099Ssam beql bad 27111099Ssam bsbb putc 27211099Ssam brb 1b 27311099Ssam 27413210Shelge /* 27513210Shelge * Update checksum in r8 and xmit 2 characters. 27613210Shelge */ 27711099Ssam xmit: 27813194Shelge addw2 r2,r8 /* update checksum */ 27913210Shelge adwc $0,r8 /* add in carry */ 28011099Ssam 28113210Shelge /* send the 2 characters contained in r2 */ 28211099Ssam xmit2: 28313194Shelge bsbb 1f /* xmit one of 'em */ 28413194Shelge ashl $-8,r2,r2 /* get next char */ 28513194Shelge /* fall into... */ 28611099Ssam 1: 28713194Shelge mfpr $CSTS,r7 /* get xmit status */ 28813194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 28913194Shelge mtpr r2,$CSTD /* send char */ 29011099Ssam rsb 29111099Ssam 29213210Shelge /* 29313210Shelge * Receive 2 characters, return in r2 and r1. 29413210Shelge */ 29511099Ssam recv2: 29613194Shelge bsbb recv1 /* recv one of 'em */ 29713194Shelge /* fall into... */ 29811099Ssam 29913210Shelge /* 30013210Shelge * Receive 1 character. 30113210Shelge */ 30211099Ssam recv1: 30313194Shelge movzbl r1,r2 /* save previous byte */ 30411099Ssam 1: 30513194Shelge mfpr $CSRS,r7 /* get recv status */ 30613194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 30713194Shelge mfpr $CSRD,r1 /* get char */ 308*13237Shelge blss 9b /* branch on recv error */ 30911099Ssam rsb 31011099Ssam 31111099Ssam getc: 31211099Ssam mfpr $RXCS,r0 31311099Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 31411099Ssam mfpr $RXDB,r0 31513194Shelge movzbl r0,r0 31611099Ssam cmpb r0,$015 31711099Ssam bneq putc /* echo and return */ 31811099Ssam bsbb putc /* carriage return */ 31913194Shelge # movb $0,r0 32013194Shelge # bsbb putc /* delay */ 32111099Ssam movb $012,r0 /* send line feed and return */ 32211099Ssam putc: 32311099Ssam mfpr $TXCS,r2 32411099Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 32511099Ssam mtpr r0,$TXDB 32611099Ssam rsb 32711099Ssam 32813194Shelge /* 32913194Shelge * Convert the filename given from the console 33013194Shelge * to radix 50 (rt-11) format. 33113194Shelge */ 33213194Shelge rad50: 33313210Shelge clrw r1 33413194Shelge bsbb getb50 /* get next ascii byte, exit if null */ 33513194Shelge mull3 $03100,r0,r1 33613194Shelge bsbb getb50 33713194Shelge mull3 $050,r0,r2 33813194Shelge addl2 r2,r1 33913194Shelge bsbb getb50 34013194Shelge addl2 r0,r1 /* last byte, just add it in */ 34113194Shelge movw r1,(r5)+ /* save result */ 34213210Shelge brb rad50 34313194Shelge 34413194Shelge getb50: 34513194Shelge movzbl (r4)+,r0 /* get next ascii byte */ 34613194Shelge beql 1f /* if zero: end of string */ 34713210Shelge movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 34813194Shelge rsb 34913194Shelge 1: 35013194Shelge tstl (sp)+ /* we're through, get back to where */ 35113194Shelge /* rad50 was called */ 35213194Shelge movw r1,(r5) /* but first save the result */ 35313194Shelge rsb 35413194Shelge 35511099Ssam .align 2 35611099Ssam readcom: 35713194Shelge .byte 2 /* command packet flag */ 35813194Shelge .byte 10 /* number of bytes in message */ 35913194Shelge .byte 2 /* tu read opcode */ 36013194Shelge .byte 0 /* modifier */ 36113194Shelge .byte 0 /* unit number */ 36213194Shelge .byte 0 /* switches */ 36313194Shelge .word 0 /* sequence number */ 36413194Shelge /* byte count and block number follow */ 36511099Ssam 36611099Ssam ermsg: 36713210Shelge .asciz "tu err\r\n" 36811099Ssam end: 369*13237Shelge 370*13237Shelge /* 371*13237Shelge * Ascii to rad 50 conversion table, 372*13237Shelge * stored on the second block on the cassette 373*13237Shelge * 374*13237Shelge * NOTE: Always make sure this table ends up 375*13237Shelge * starting at byte 512!!!! 376*13237Shelge */ 377*13237Shelge .align 2 378*13237Shelge .data 2 379*13237Shelge .long 0x1d1d1d1d 380*13237Shelge .long 0x1d1d1d1d 381*13237Shelge .long 0x1d1d1d1d 382*13237Shelge .long 0x1d1d1d1d 383*13237Shelge .long 0x1d1d1d1d 384*13237Shelge .long 0x1d1d1d1d 385*13237Shelge .long 0x1d1d1d1d 386*13237Shelge .long 0x1d1d1d1d 387*13237Shelge .long 0x1d1d1d00 388*13237Shelge .long 0x1d1d1d1b 389*13237Shelge .long 0x1d1d1d1d 390*13237Shelge .long 0x1d1c1d1d 391*13237Shelge .long 0x21201f1e 392*13237Shelge .long 0x25242322 393*13237Shelge .long 0x1d1d2726 394*13237Shelge .long 0x1d1d1d1d 395*13237Shelge .long 0x302011d 396*13237Shelge .long 0x7060504 397*13237Shelge .long 0xb0a0908 398*13237Shelge .long 0xf0e0d0c 399*13237Shelge .long 0x13121110 400*13237Shelge .long 0x17161514 401*13237Shelge .long 0x1d1a1918 402*13237Shelge .long 0x1d1d1d1d 403*13237Shelge .long 0x302011d 404*13237Shelge .long 0x7060504 405*13237Shelge .long 0xb0a0908 406*13237Shelge .long 0xf0e0d0c 407*13237Shelge .long 0x13121110 408*13237Shelge .long 0x17161514 409*13237Shelge .long 0x1d1a1918 410*13237Shelge .long 0x1d1d1d1d 411*13237Shelge .long 0x1d1d1d1d 412*13237Shelge .long 0x1d1d1d1d 413*13237Shelge .long 0x1d1d1d1d 414*13237Shelge .long 0x1d1d1d1d 415*13237Shelge .long 0x1d1d1d1d 416*13237Shelge .long 0x1d1d1d1d 417*13237Shelge .long 0x1d1d1d1d 418*13237Shelge .long 0x1d1d1d1d 419*13237Shelge .long 0x1d1d1d00 420*13237Shelge .long 0x1d1d1d1b 421*13237Shelge .long 0x1d1d1d1d 422*13237Shelge .long 0x1d1c1d1d 423*13237Shelge .long 0x21201f1e 424*13237Shelge .long 0x25242322 425*13237Shelge .long 0x1d1d2726 426*13237Shelge .long 0x1d1d1d1d 427*13237Shelge .long 0x302011d 428*13237Shelge .long 0x7060504 429*13237Shelge .long 0xb0a0908 430*13237Shelge .long 0xf0e0d0c 431*13237Shelge .long 0x13121110 432*13237Shelge .long 0x17161514 433*13237Shelge .long 0x1d1a1918 434*13237Shelge .long 0x1d1d1d1d 435*13237Shelge .long 0x302011d 436*13237Shelge .long 0x7060504 437*13237Shelge .long 0xb0a0908 438*13237Shelge .long 0xf0e0d0c 439*13237Shelge .long 0x13121110 440*13237Shelge .long 0x17161514 441*13237Shelge .long 0x1d1a1918 442*13237Shelge .long 0x1d1d1d 443*13237Shelge .data 444