1*14312Ssam /* tuboot.c 4.6 83/08/01 */ 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 */ 58*14312Ssam .set ext,-4 /* file ext. */ 59*14312Ssam .set name,-20 /* 12 bytes for full name */ 60*14312Ssam .set rt_name,-20-FNSIZ /* rad50 file name */ 61*14312Ssam /* reboot flags for boot */ 62*14312Ssam .set RB_ASK,3 /* ask name and come up single user */ 6311099Ssam 6413194Shelge /* 6513194Shelge * Initialization. 6613194Shelge */ 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 */ 7213210Shelge addl3 $rt_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 mtpr $TU_BREAK,$CSTS /* set break condition */ 8013194Shelge clrl r2 /* nulls */ 8113194Shelge bsbw xmit2 /* wait 2 character times */ 8213194Shelge mfpr $CSRD,r2 /* clear receive buffer */ 8311099Ssam movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 8413194Shelge bsbw xmit2 /* xmit 'em */ 8511099Ssam 1: 8613194Shelge mfpr $CSRD,r7 /* get recv data */ 8711099Ssam cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 8813194Shelge bneq 1b /* nope, look more */ 8911099Ssam 9013210Shelge movab name(fp),r4 /* start of filename storage */ 9113210Shelge clrq (r4) /* init name field */ 9213210Shelge clrq name+8(fp) 9313194Shelge clrq rt_name(fp) /* init rad50 filename */ 9411099Ssam movzbl $'=,r0 /* prompt character */ 9511099Ssam bsbw putc /* output char to main console */ 9611099Ssam 9713210Shelge /* 9813210Shelge * Read in a file name from console. 9913210Shelge */ 10011099Ssam movl r4,r1 /* loc at which to store file name */ 10111099Ssam nxtc: 10211099Ssam bsbw getc /* get input char's in file name */ 10311099Ssam cmpb r0,$012 /* terminator ? */ 10411099Ssam beql nullc 10511099Ssam movb r0,(r1)+ 10611099Ssam brb nxtc 10711099Ssam nullc: 10813210Shelge cmpl r4,r1 10913194Shelge beql start /* restart if empty string */ 11013194Shelge clrb (r1) /* add null byte at end */ 11111099Ssam 11213194Shelge /* 11313210Shelge * User-specified filename has been stored at name(fp), 11413210Shelge * read the entire directory contents into low core. 11513194Shelge */ 11611099Ssam dirred: 11713194Shelge movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 11811099Ssam movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 11913194Shelge clrl r11 /* start address */ 12011099Ssam bsbw taper /* read no. bytes indicated */ 12113194Shelge /* 12213194Shelge * Read in the character conversion table which reside in block 1 12313210Shelge * (the second block) on the cassette. Place it after the directory 12413210Shelge * on low core (from 0x400). 12513194Shelge */ 12613210Shelge movl $1,r10 /* block number */ 12713194Shelge movl $BLKSIZ,r6 /* read one block */ 12813194Shelge bsbw taper 12911099Ssam 13013194Shelge /* 13113194Shelge * Convert the ascii filename to rad50. 13213210Shelge * R4 still points to name(fp) 13313194Shelge */ 13413194Shelge movl $6,r3 /* max length of filename */ 13513194Shelge 1: 13613194Shelge cmpb $'.,(r4)+ /* look for '.' */ 13713210Shelge beql 1f 13813194Shelge sobgtr r3,1b 13913210Shelge incl r4 /* point past '.' if ext is present */ 14013210Shelge 1: 14113194Shelge clrb -1(r4) /* end name with null */ 14213194Shelge movl $3,r3 /* max length of extension */ 14313194Shelge movab ext(fp),r5 /* place extension here */ 14413194Shelge 1: 14513194Shelge movb (r4)+,(r5)+ 14613194Shelge beql 1f /* the string is null terminated */ 14713194Shelge sobgtr r3,1b 14813194Shelge 1: 14913194Shelge movab name(fp),r4 15013194Shelge movab rt_name(fp),r5 /* ptr to rad50 name */ 15113194Shelge bsbw rad50 /* convert filename */ 15213194Shelge movab ext(fp),r4 15313194Shelge movab rt_name+4(fp),r5 15413194Shelge bsbw rad50 /* convert extension */ 15513194Shelge 15613194Shelge /* 15713194Shelge * Search entire directory for user-specified file name. 15813194Shelge */ 15913194Shelge 16013194Shelge movab rt_name(fp),r4 /* search for this file */ 16113210Shelge movl $10,r5 /* point to first file entry */ 16213210Shelge movzwl -2(r5),r10 /* r10 = block # where files begin */ 16313194Shelge 2: 16413194Shelge cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 16511099Ssam beql fndfil /* found match */ 16613194Shelge 1: 16713210Shelge addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 16813194Shelge addl2 $ENTSIZ,r5 /* move to next entry */ 16913210Shelge # cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 17013210Shelge # beql 1b /* not really necessary since deleted entries will fail */ 17113210Shelge /* to compare anyway */ 17213210Shelge cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 17313194Shelge bneq 2b 17411099Ssam brw start /* entry not in directory; start over */ 17511099Ssam 17613194Shelge /* 17713194Shelge * Found desired directory entry 17813194Shelge */ 17911099Ssam fndfil: 18013210Shelge /* start block no., 2 bytes in r10 */ 18113194Shelge movzwl FILSIZ(r5),r6 /* file size (blocks) */ 18213194Shelge mull2 $BLKSIZ,r6 /* file size (bytes) */ 18313210Shelge cmpl r6,$RELOC-512 /* check if file fits below stack */ 18413210Shelge blss filok 18513210Shelge brw start /* file too large */ 18611099Ssam 18713194Shelge /* 18813194Shelge * Read in desired file from tape. 18913194Shelge */ 19011099Ssam filok: 19111099Ssam movl r6,r5 /* start of bss space */ 19213194Shelge clrl r11 /* start address */ 19311099Ssam bsbb taper 19411099Ssam 19513194Shelge /* 19613194Shelge * Clear core. 19713194Shelge */ 19811099Ssam subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 19911099Ssam 1: 20011099Ssam clrb (r5)+ 20111099Ssam sobgtr r0,1b 20211099Ssam 20313194Shelge /* 20413194Shelge * Jump to start of file & execute. 20513194Shelge */ 20613210Shelge addl3 $20,fp,ap /* ?? */ 20711099Ssam clrl r5 208*14312Ssam movl $RB_ASK,r11 20911099Ssam calls $0,(r5) 21011099Ssam bad: 21111099Ssam brw start 21211099Ssam 21313210Shelge /* 21413210Shelge * Read (r6) bytes from block (r10) 21513210Shelge * into loc (r11). 21613210Shelge */ 21711099Ssam taper: 21813194Shelge clrl r8 /* initialize checksum */ 21913194Shelge movab readcom,r0 /* read command packet addr */ 22011099Ssam movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 22111099Ssam 1: 22213194Shelge movzwl (r0)+,r2 /* get 2 chars from block */ 22313194Shelge bsbb xmit /* xmit and update ckecksum */ 22413194Shelge sobgtr r1,1b /* loop if more */ 22511099Ssam 22613210Shelge /* 22713210Shelge * Now do variable part of packet. 22813210Shelge */ 22913194Shelge movl r6,r2 /* byte count */ 23011099Ssam bsbb xmit 23113194Shelge movl r10,r2 /* starting block number */ 23211099Ssam bsbb xmit 23313194Shelge movzwl r8,r2 /* accumulated ckecksum */ 23411099Ssam bsbb xmit 23511099Ssam 23613210Shelge /* 23713210Shelge * Collect read packet from device. 23813210Shelge */ 23911099Ssam 1: 24013194Shelge bsbb recv2 /* get 2 packet characters */ 24113194Shelge decb r2 /* data packet? */ 24213194Shelge bneq 1f /* branch on end of data */ 24313194Shelge movzbl r1,r8 /* get byte count of packet */ 24411099Ssam 24513210Shelge /* 24613210Shelge * Read data into memory. 24713210Shelge */ 24811099Ssam 2: 24913194Shelge bsbb recv1 /* get a char */ 25013210Shelge movb r1,(r11)+ /* stuff into memory */ 25113194Shelge sobgtr r8,2b /* loop if more */ 25213194Shelge bsbb recv2 /* skip checksum */ 25313194Shelge brb 1b /* read next packet */ 25411099Ssam 25513210Shelge /* 25613210Shelge * End of data xfer; check for errors. 25713210Shelge */ 25811099Ssam 1: 25913194Shelge bsbb recv2 /* get success code */ 26013194Shelge tstl r1 /* error in read? */ 26113194Shelge blss 9f /* branch if status error */ 26211099Ssam movl $5,r0 26311099Ssam 1: 26413194Shelge bsbb recv2 /* discard 10 bytes */ 26511099Ssam sobgtr r0,1b 26611099Ssam rsb 26711099Ssam 26813210Shelge /* Fatal error */ 26911099Ssam 9: 27011099Ssam movab ermsg,r1 27111099Ssam 1: 27211099Ssam movb (r1)+,r0 27311099Ssam beql bad 27411099Ssam bsbb putc 27511099Ssam brb 1b 27611099Ssam 27713210Shelge /* 27813210Shelge * Update checksum in r8 and xmit 2 characters. 27913210Shelge */ 28011099Ssam xmit: 28113194Shelge addw2 r2,r8 /* update checksum */ 28213210Shelge adwc $0,r8 /* add in carry */ 28311099Ssam 28413210Shelge /* send the 2 characters contained in r2 */ 28511099Ssam xmit2: 28613194Shelge bsbb 1f /* xmit one of 'em */ 28713194Shelge ashl $-8,r2,r2 /* get next char */ 28813194Shelge /* fall into... */ 28911099Ssam 1: 29013194Shelge mfpr $CSTS,r7 /* get xmit status */ 29113194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 29213194Shelge mtpr r2,$CSTD /* send char */ 29311099Ssam rsb 29411099Ssam 29513210Shelge /* 29613210Shelge * Receive 2 characters, return in r2 and r1. 29713210Shelge */ 29811099Ssam recv2: 29913194Shelge bsbb recv1 /* recv one of 'em */ 30013194Shelge /* fall into... */ 30111099Ssam 30213210Shelge /* 30313210Shelge * Receive 1 character. 30413210Shelge */ 30511099Ssam recv1: 30613194Shelge movzbl r1,r2 /* save previous byte */ 30711099Ssam 1: 30813194Shelge mfpr $CSRS,r7 /* get recv status */ 30913194Shelge bbc $TU_READY,r7,1b /* loop until ready */ 31013194Shelge mfpr $CSRD,r1 /* get char */ 31113237Shelge blss 9b /* branch on recv error */ 31211099Ssam rsb 31311099Ssam 31411099Ssam getc: 31511099Ssam mfpr $RXCS,r0 31611099Ssam bbc $RXCS_pd,r0,getc /* receiver ready ? */ 31711099Ssam mfpr $RXDB,r0 31813439Ssam extzv $0,$7,r0,r0 31911099Ssam cmpb r0,$015 32011099Ssam bneq putc /* echo and return */ 32111099Ssam bsbb putc /* carriage return */ 32213194Shelge # movb $0,r0 32313194Shelge # bsbb putc /* delay */ 32411099Ssam movb $012,r0 /* send line feed and return */ 32511099Ssam putc: 32611099Ssam mfpr $TXCS,r2 32711099Ssam bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 32811099Ssam mtpr r0,$TXDB 32911099Ssam rsb 33011099Ssam 33113194Shelge /* 33213194Shelge * Convert the filename given from the console 33313194Shelge * to radix 50 (rt-11) format. 33413194Shelge */ 33513194Shelge rad50: 33613210Shelge clrw r1 33713194Shelge bsbb getb50 /* get next ascii byte, exit if null */ 33813194Shelge mull3 $03100,r0,r1 33913194Shelge bsbb getb50 34013194Shelge mull3 $050,r0,r2 34113194Shelge addl2 r2,r1 34213194Shelge bsbb getb50 34313194Shelge addl2 r0,r1 /* last byte, just add it in */ 34413194Shelge movw r1,(r5)+ /* save result */ 34513210Shelge brb rad50 34613194Shelge 34713194Shelge getb50: 34813194Shelge movzbl (r4)+,r0 /* get next ascii byte */ 34913194Shelge beql 1f /* if zero: end of string */ 35013210Shelge movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 35113194Shelge rsb 35213194Shelge 1: 35313194Shelge tstl (sp)+ /* we're through, get back to where */ 35413194Shelge /* rad50 was called */ 35513194Shelge movw r1,(r5) /* but first save the result */ 35613194Shelge rsb 35713194Shelge 35811099Ssam .align 2 35911099Ssam readcom: 36013194Shelge .byte 2 /* command packet flag */ 36113194Shelge .byte 10 /* number of bytes in message */ 36213194Shelge .byte 2 /* tu read opcode */ 36313194Shelge .byte 0 /* modifier */ 36413194Shelge .byte 0 /* unit number */ 36513194Shelge .byte 0 /* switches */ 36613194Shelge .word 0 /* sequence number */ 36713194Shelge /* byte count and block number follow */ 36811099Ssam 36911099Ssam ermsg: 370*14312Ssam .asciz "tuerr\r\n" 37111099Ssam end: 37213237Shelge 37313237Shelge /* 37413237Shelge * Ascii to rad 50 conversion table, 37513237Shelge * stored on the second block on the cassette 37613237Shelge * 37713237Shelge * NOTE: Always make sure this table ends up 37813237Shelge * starting at byte 512!!!! 37913237Shelge */ 38013237Shelge .align 2 38113237Shelge .data 2 38213237Shelge .long 0x1d1d1d1d 38313237Shelge .long 0x1d1d1d1d 38413237Shelge .long 0x1d1d1d1d 38513237Shelge .long 0x1d1d1d1d 38613237Shelge .long 0x1d1d1d1d 38713237Shelge .long 0x1d1d1d1d 38813237Shelge .long 0x1d1d1d1d 38913237Shelge .long 0x1d1d1d1d 39013237Shelge .long 0x1d1d1d00 39113237Shelge .long 0x1d1d1d1b 39213237Shelge .long 0x1d1d1d1d 39313237Shelge .long 0x1d1c1d1d 39413237Shelge .long 0x21201f1e 39513237Shelge .long 0x25242322 39613237Shelge .long 0x1d1d2726 39713237Shelge .long 0x1d1d1d1d 39813237Shelge .long 0x302011d 39913237Shelge .long 0x7060504 40013237Shelge .long 0xb0a0908 40113237Shelge .long 0xf0e0d0c 40213237Shelge .long 0x13121110 40313237Shelge .long 0x17161514 40413237Shelge .long 0x1d1a1918 40513237Shelge .long 0x1d1d1d1d 40613237Shelge .long 0x302011d 40713237Shelge .long 0x7060504 40813237Shelge .long 0xb0a0908 40913237Shelge .long 0xf0e0d0c 41013237Shelge .long 0x13121110 41113237Shelge .long 0x17161514 41213237Shelge .long 0x1d1a1918 41313237Shelge .long 0x1d1d1d1d 41413237Shelge .long 0x1d1d1d1d 41513237Shelge .long 0x1d1d1d1d 41613237Shelge .long 0x1d1d1d1d 41713237Shelge .long 0x1d1d1d1d 41813237Shelge .long 0x1d1d1d1d 41913237Shelge .long 0x1d1d1d1d 42013237Shelge .long 0x1d1d1d1d 42113237Shelge .long 0x1d1d1d1d 42213237Shelge .long 0x1d1d1d00 42313237Shelge .long 0x1d1d1d1b 42413237Shelge .long 0x1d1d1d1d 42513237Shelge .long 0x1d1c1d1d 42613237Shelge .long 0x21201f1e 42713237Shelge .long 0x25242322 42813237Shelge .long 0x1d1d2726 42913237Shelge .long 0x1d1d1d1d 43013237Shelge .long 0x302011d 43113237Shelge .long 0x7060504 43213237Shelge .long 0xb0a0908 43313237Shelge .long 0xf0e0d0c 43413237Shelge .long 0x13121110 43513237Shelge .long 0x17161514 43613237Shelge .long 0x1d1a1918 43713237Shelge .long 0x1d1d1d1d 43813237Shelge .long 0x302011d 43913237Shelge .long 0x7060504 44013237Shelge .long 0xb0a0908 44113237Shelge .long 0xf0e0d0c 44213237Shelge .long 0x13121110 44313237Shelge .long 0x17161514 44413237Shelge .long 0x1d1a1918 44513237Shelge .long 0x1d1d1d 44613237Shelge .data 447