Commit | Line | Data |
---|---|---|
3fa0fcf5 | 1 | /* tuboot.s 4.1 83/02/16 */ |
1aa3420e SL |
2 | |
3 | /* | |
4 | * VAX tu58 console cassette boot block | |
5 | * | |
6 | * Thomas Ferrin 27oct82 | |
7 | * | |
8 | * Reads a program from a tp directory on tape | |
9 | * and executes it. Program 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''. | |
3fa0fcf5 HS |
13 | * |
14 | * Helge Skrivervik CSRG/UCB 18jun83 | |
15 | * Changed to use rt-11 format directory & files | |
16 | * instead of tp format | |
1aa3420e SL |
17 | */ |
18 | .set RELOC,0x70000 | |
19 | /* a.out defines */ | |
20 | .set HDRSIZ,040 /* size of file header for VAX */ | |
21 | .set MAGIC,0410 /* file type id in header */ | |
22 | .set TSIZ,4 /* text size */ | |
23 | .set DSIZ,8 /* data size */ | |
24 | .set BSIZ,12 /* bss size */ | |
25 | .set TENT,024 /* task header entry loc */ | |
3fa0fcf5 HS |
26 | /* rt-11 directory definitions */ |
27 | .set DIRBLK,6 /* rt-11 directory starts at block 6 */ | |
28 | .set FILSIZ,8 /* rt-11 direc entry offset for file size */ | |
29 | .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ | |
1aa3420e | 30 | .set BLKSIZ,512 /* tape block size, bytes */ |
3fa0fcf5 HS |
31 | .set NUMDIR,2 /* no. of dir blocks on tape */ |
32 | .set RT_FNSIZ,8 /* size of rad50 filename + 2 */ | |
33 | .set NAME,2 /* direc entry offset for filename */ | |
34 | .set RT_STAT,1 /* direc entry offset for entry status */ | |
35 | /* rt-11 directory entry status */ | |
36 | .set RT_ESEG,8 /* end of directory segment */ | |
37 | .set RT_NULL,2 /* empty entry */ | |
38 | .set RT_FILE,4 /* valid file entry */ | |
1aa3420e SL |
39 | /* processor registers and bits */ |
40 | .set RXCS,32 | |
41 | .set RXDB,33 | |
42 | .set TXCS,34 | |
43 | .set TXDB,35 | |
44 | .set RXCS_DONE,0x80 | |
45 | .set TXCS_RDY,0x80 | |
46 | .set TXCS_pr,7 /* bit position of TXCS ready bit */ | |
47 | .set RXCS_pd,7 /* bit position of RXCS done bit */ | |
48 | /* console storage registers and bits */ | |
49 | .set CSRS,0x1c | |
50 | .set CSRD,0x1d | |
51 | .set CSTS,0x1e | |
52 | .set CSTD,0x1f | |
53 | /* TU commands and bits */ | |
54 | .set TU_BREAK,1 | |
55 | .set TU_INIT,4 | |
56 | .set TU_CONTINUE,16 | |
57 | .set TU_READY,7 /* bit position of CSRS ready bit */ | |
58 | .set TU_PACKETLEN,8 /* length of readcom block */ | |
59 | /* local stack variables */ | |
3fa0fcf5 HS |
60 | .set ext,-4 /* file ext. */ |
61 | .set name,-20 /* 12 bytes for full name */ | |
62 | .set rt_name,-20-RT_FNSIZ /* rad50 file name */ | |
1aa3420e | 63 | |
3fa0fcf5 HS |
64 | /* |
65 | * Initialization. | |
66 | */ | |
1aa3420e SL |
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 $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 | /* init tu58 */ | |
80 | mtpr $TU_BREAK,$CSTS /* set break condition */ | |
3fa0fcf5 HS |
81 | clrl r2 /* nulls */ |
82 | bsbw xmit2 /* wait 2 character times */ | |
83 | mfpr $CSRD,r2 /* clear receive buffer */ | |
1aa3420e | 84 | movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ |
3fa0fcf5 | 85 | bsbw xmit2 /* xmit 'em */ |
1aa3420e | 86 | 1: |
3fa0fcf5 | 87 | mfpr $CSRD,r7 /* get recv data */ |
1aa3420e | 88 | cmpb r7,$TU_CONTINUE /* is it a continue flag? */ |
3fa0fcf5 | 89 | bneq 1b /* nope, look more */ |
1aa3420e | 90 | |
3fa0fcf5 | 91 | clrq rt_name(fp) /* init rad50 filename */ |
1aa3420e SL |
92 | movab name(fp),r4 /* start of filename storage */ |
93 | movzbl $'=,r0 /* prompt character */ | |
94 | bsbw putc /* output char to main console */ | |
95 | ||
96 | /* read in a file name */ | |
97 | movl r4,r1 /* loc at which to store file name */ | |
98 | nxtc: | |
99 | bsbw getc /* get input char's in file name */ | |
100 | cmpb r0,$012 /* terminator ? */ | |
101 | beql nullc | |
102 | movb r0,(r1)+ | |
103 | brb nxtc | |
104 | nullc: | |
105 | subl3 r4,r1,r9 /* size of path name */ | |
3fa0fcf5 HS |
106 | beql start /* restart if empty string */ |
107 | clrb (r1) /* add null byte at end */ | |
108 | incl r9 /* and fix length */ | |
1aa3420e | 109 | |
3fa0fcf5 HS |
110 | /* |
111 | * user-specified filename has been stored at name(fp) | |
112 | * read in entire directory contents into low core | |
113 | */ | |
1aa3420e | 114 | dirred: |
3fa0fcf5 | 115 | movl $DIRBLK,r10 /* directory starts at block DIRBLK */ |
1aa3420e | 116 | movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ |
3fa0fcf5 | 117 | clrl r11 /* start address */ |
1aa3420e | 118 | bsbw taper /* read no. bytes indicated */ |
3fa0fcf5 HS |
119 | /* |
120 | * Read in the character conversion table which reside in block 1 | |
121 | * (the second block) on the cassette. | |
122 | */ | |
123 | movl $1,r10 /* start block */ | |
124 | movl $BLKSIZ,r6 /* read one block */ | |
125 | movl 0x400,r11 /* place it after the directory */ | |
126 | bsbw taper | |
1aa3420e | 127 | |
3fa0fcf5 HS |
128 | /* |
129 | * Convert the ascii filename to rad50. | |
130 | */ | |
131 | movab name(fp),r4 /* ptr to ascii name */ | |
132 | movl $6,r3 /* max length of filename */ | |
133 | 1: | |
134 | cmpb $'.,(r4)+ /* look for '.' */ | |
135 | sobgtr r3,1b | |
136 | clrb -1(r4) /* end name with null */ | |
137 | movl $3,r3 /* max length of extension */ | |
138 | movab ext(fp),r5 /* place extension here */ | |
139 | 1: | |
140 | movb (r4)+,(r5)+ | |
141 | beql 1f /* the string is null terminated */ | |
142 | sobgtr r3,1b | |
143 | 1: | |
144 | movab name(fp),r4 | |
145 | movab rt_name(fp),r5 /* ptr to rad50 name */ | |
146 | bsbw rad50 /* convert filename */ | |
147 | movab ext(fp),r4 | |
148 | movab rt_name+4(fp),r5 | |
149 | bsbw rad50 /* convert extension */ | |
150 | ||
151 | /* | |
152 | * Search entire directory for user-specified file name. | |
153 | */ | |
154 | ||
155 | movab rt_name(fp),r4 /* search for this file */ | |
156 | movl $10,r5 /* dir buff loc = 0, point to first */ | |
157 | /* file entry */ | |
158 | movzwl -2(r5),r3 /* r3 = block # where files begin */ | |
159 | 2: | |
160 | cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ | |
1aa3420e | 161 | beql fndfil /* found match */ |
3fa0fcf5 HS |
162 | 1: |
163 | addw2 FILSIZ(r5),r3 /* add file length to block pointer */ | |
164 | addl2 $ENTSIZ,r5 /* move to next entry */ | |
165 | # cpmb RT_STAT(r5),$RT_NULL /* check if deleted file */ | |
166 | # beql 1b | |
167 | cmpb RT_STAT(r5),$RT_ESEG /* check if end of segment */ | |
168 | bneq 2b | |
1aa3420e SL |
169 | brw start /* entry not in directory; start over */ |
170 | ||
3fa0fcf5 HS |
171 | /* |
172 | * Found desired directory entry | |
173 | */ | |
1aa3420e | 174 | fndfil: |
3fa0fcf5 HS |
175 | movl r3,r10 /* start block no., 2 bytes */ |
176 | movzwl FILSIZ(r5),r6 /* file size (blocks) */ | |
177 | mull2 $BLKSIZ,r6 /* file size (bytes) */ | |
178 | # cmpl r6,$RELOC-512 /* check if file fits below stack */ | |
179 | # blss filok | |
180 | # brw start /* file too large */ | |
1aa3420e | 181 | |
3fa0fcf5 HS |
182 | /* |
183 | * Read in desired file from tape. | |
184 | */ | |
1aa3420e SL |
185 | filok: |
186 | movl r6,r5 /* start of bss space */ | |
3fa0fcf5 | 187 | clrl r11 /* start address */ |
1aa3420e | 188 | bsbb taper |
3fa0fcf5 | 189 | # bsbb rew |
1aa3420e | 190 | |
3fa0fcf5 HS |
191 | /* |
192 | * Clear core. | |
193 | */ | |
1aa3420e SL |
194 | subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ |
195 | 1: | |
196 | clrb (r5)+ | |
197 | sobgtr r0,1b | |
198 | ||
3fa0fcf5 HS |
199 | /* |
200 | * Jump to start of file & execute. | |
201 | */ | |
1aa3420e SL |
202 | addl3 $20,fp,ap |
203 | clrl r5 | |
204 | calls $0,(r5) | |
205 | bad: | |
206 | brw start | |
207 | ||
208 | /* rewind tape */ | |
3fa0fcf5 | 209 | #ifdef notdef |
1aa3420e | 210 | rew: |
3fa0fcf5 HS |
211 | movb $5,readcom+2 /* position opcode */ |
212 | clrl r10 /* block 0 */ | |
213 | clrl r6 /* 0 bytes */ | |
1aa3420e | 214 | bsbb taper |
3fa0fcf5 | 215 | movb $2,readcom+2 /* read opcode */ |
1aa3420e | 216 | rsb |
3fa0fcf5 | 217 | #endif |
1aa3420e | 218 | |
3fa0fcf5 | 219 | /* read (r6) bytes from (r10) into loc (r11) */ |
1aa3420e | 220 | taper: |
3fa0fcf5 HS |
221 | clrl r8 /* initialize checksum */ |
222 | movab readcom,r0 /* read command packet addr */ | |
1aa3420e SL |
223 | movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ |
224 | 1: | |
3fa0fcf5 HS |
225 | movzwl (r0)+,r2 /* get 2 chars from block */ |
226 | bsbb xmit /* xmit and update ckecksum */ | |
227 | sobgtr r1,1b /* loop if more */ | |
1aa3420e SL |
228 | |
229 | /* now do variable part of packet */ | |
3fa0fcf5 | 230 | movl r6,r2 /* byte count */ |
1aa3420e | 231 | bsbb xmit |
3fa0fcf5 | 232 | movl r10,r2 /* starting block number */ |
1aa3420e | 233 | bsbb xmit |
3fa0fcf5 | 234 | movzwl r8,r2 /* accumulated ckecksum */ |
1aa3420e SL |
235 | bsbb xmit |
236 | ||
237 | /* collect read packet from device */ | |
3fa0fcf5 | 238 | movl r11,r0 /* starting addr */ |
1aa3420e | 239 | 1: |
3fa0fcf5 HS |
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 */ | |
1aa3420e SL |
244 | |
245 | /* read data into memory */ | |
246 | 2: | |
3fa0fcf5 HS |
247 | bsbb recv1 /* get a char */ |
248 | movb r1,(r0)+ /* stuff into memory */ | |
249 | sobgtr r8,2b /* loop if more */ | |
250 | bsbb recv2 /* skip checksum */ | |
251 | brb 1b /* read next packet */ | |
1aa3420e SL |
252 | |
253 | /* end of data xfer; check for errors */ | |
254 | 1: | |
3fa0fcf5 HS |
255 | subl2 r6,r0 /* all bytes xfered? */ |
256 | bneq 9f /* nope, error */ | |
257 | bsbb recv2 /* get success code */ | |
258 | tstl r1 /* error in read? */ | |
259 | blss 9f /* branch if status error */ | |
1aa3420e SL |
260 | movl $5,r0 |
261 | 1: | |
3fa0fcf5 | 262 | bsbb recv2 /* discard 10 bytes */ |
1aa3420e SL |
263 | sobgtr r0,1b |
264 | rsb | |
265 | ||
266 | /* fatal error */ | |
267 | 9: | |
268 | movab ermsg,r1 | |
269 | 1: | |
270 | movb (r1)+,r0 | |
271 | beql bad | |
272 | bsbb putc | |
273 | brb 1b | |
274 | ||
275 | /* update checksum in r8 and xmit 2 characters */ | |
276 | xmit: | |
3fa0fcf5 HS |
277 | addw2 r2,r8 /* update checksum */ |
278 | bcc xmit2 /* branch if no overflow */ | |
279 | incw r8 /* add in carry */ | |
1aa3420e SL |
280 | |
281 | /* send the 2 characters contained in r2 */ | |
282 | xmit2: | |
3fa0fcf5 HS |
283 | bsbb 1f /* xmit one of 'em */ |
284 | ashl $-8,r2,r2 /* get next char */ | |
285 | /* fall into... */ | |
1aa3420e | 286 | 1: |
3fa0fcf5 HS |
287 | mfpr $CSTS,r7 /* get xmit status */ |
288 | bbc $TU_READY,r7,1b /* loop until ready */ | |
289 | mtpr r2,$CSTD /* send char */ | |
1aa3420e SL |
290 | rsb |
291 | ||
292 | /* receive 2 characters, return in r2 and r1 */ | |
293 | recv2: | |
3fa0fcf5 HS |
294 | bsbb recv1 /* recv one of 'em */ |
295 | /* fall into... */ | |
1aa3420e SL |
296 | |
297 | /* receive 1 character */ | |
298 | recv1: | |
3fa0fcf5 | 299 | movzbl r1,r2 /* save previous byte */ |
1aa3420e | 300 | 1: |
3fa0fcf5 HS |
301 | mfpr $CSRS,r7 /* get recv status */ |
302 | bbc $TU_READY,r7,1b /* loop until ready */ | |
303 | mfpr $CSRD,r1 /* get char */ | |
304 | # blss 9b /* branch on recv error */ | |
1aa3420e SL |
305 | rsb |
306 | ||
307 | getc: | |
308 | mfpr $RXCS,r0 | |
309 | bbc $RXCS_pd,r0,getc /* receiver ready ? */ | |
310 | mfpr $RXDB,r0 | |
3fa0fcf5 | 311 | movzbl r0,r0 |
1aa3420e SL |
312 | cmpb r0,$015 |
313 | bneq putc /* echo and return */ | |
314 | bsbb putc /* carriage return */ | |
3fa0fcf5 HS |
315 | # movb $0,r0 |
316 | # bsbb putc /* delay */ | |
1aa3420e SL |
317 | movb $012,r0 /* send line feed and return */ |
318 | putc: | |
319 | mfpr $TXCS,r2 | |
320 | bbc $TXCS_pr,r2,putc /* transmitter ready ? */ | |
1aa3420e SL |
321 | mtpr r0,$TXDB |
322 | rsb | |
323 | ||
3fa0fcf5 HS |
324 | /* |
325 | * Convert the filename given from the console | |
326 | * to radix 50 (rt-11) format. | |
327 | */ | |
328 | rad50: | |
329 | movl $0x400,r6 /* address of conversion table */ | |
330 | 1: | |
331 | bsbb getb50 /* get next ascii byte, exit if null */ | |
332 | mull3 $03100,r0,r1 | |
333 | bsbb getb50 | |
334 | mull3 $050,r0,r2 | |
335 | addl2 r2,r1 | |
336 | bsbb getb50 | |
337 | addl2 r0,r1 /* last byte, just add it in */ | |
338 | movw r1,(r5)+ /* save result */ | |
339 | brb 1b | |
340 | ||
341 | getb50: | |
342 | movzbl (r4)+,r0 /* get next ascii byte */ | |
343 | beql 1f /* if zero: end of string */ | |
344 | addl2 r6,r0 /* calculate conversion table address */ | |
345 | movzbl (r0),r0 /* and get the r50 byte from the table*/ | |
346 | rsb | |
347 | 1: | |
348 | tstl (sp)+ /* we're through, get back to where */ | |
349 | /* rad50 was called */ | |
350 | movw r1,(r5) /* but first save the result */ | |
351 | rsb | |
352 | ||
1aa3420e SL |
353 | .align 2 |
354 | readcom: | |
3fa0fcf5 HS |
355 | .byte 2 /* command packet flag */ |
356 | .byte 10 /* number of bytes in message */ | |
357 | .byte 2 /* tu read opcode */ | |
358 | .byte 0 /* modifier */ | |
359 | .byte 0 /* unit number */ | |
360 | .byte 0 /* switches */ | |
361 | .word 0 /* sequence number */ | |
362 | /* byte count and block number follow */ | |
1aa3420e SL |
363 | |
364 | ermsg: | |
365 | .asciz "tu58 err\r\n" | |
366 | end: |