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