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