Commit | Line | Data |
---|---|---|
d52f1552 TL |
1 | # define MIN(a,b) (a<b?a:b) |
2 | # define RP6CYL 815 /* no. RP06 cylinders/pack */ | |
3 | # define RP6TRK 19 /* no. tracks/cyl */ | |
4 | # define RP6SEC 22 /* no. sectors/track */ | |
5 | # define RP6ST (RP6TRK*RP6SEC) /* no. sectors/cyl */ | |
6 | # define MAXSEC (RP6CYL*RP6TRK*RP6SEC) /* sectors/pack */ | |
7 | # define M0 0x20010000 /* phys addr MBA 0 */ | |
8 | # define M1 0x20012000 /* phys addr MBA 1 */ | |
9 | # define M0_cr (M0+4) /* MBA 0 control reg addr */ | |
10 | # define M1_cr (M1+4) /* MBA 1 control reg addr */ | |
11 | # define M0_map (M0+0x800) /* start MBA 0 map reg's */ | |
12 | # define M1_map (M1+0x800) /* start MBA 1 map reg's */ | |
13 | # define M0_var (M0+0xc) /* MBA 0 virt addr reg */ | |
14 | # define M1_var (M1+0xc) /* MBA 1 virt addr reg */ | |
15 | # define M0_bc (M0+0x10) /* MBA 0 byte count reg */ | |
16 | # define M1_bc (M1+0x10) /* MBA 1 byte count reg */ | |
17 | # define MBAinit 01 /* MBA init bit */ | |
18 | /* */ | |
19 | # define TM (M1+0x400) /* base for TM02/TE16 reg's */ | |
20 | # define RP (M0+0x400) /* base for RP06 reg's, drive 0 */ | |
21 | /* */ | |
22 | # define TM_tc (TM+0x24) /* TM02 tape control reg */ | |
23 | # define TM_cs1 (TM+0) /* TM02 control 1 reg */ | |
24 | # define TM_ds (TM+4) /* status reg */ | |
25 | # define TM_fc (TM+0x14) /* TM02 frame count reg */ | |
26 | /* */ | |
27 | # define RP_cr 0 /* RP06 control reg offset, longword */ | |
28 | # define RP_sr 1 /* RP06 status reg offset */ | |
29 | # define RP_stk 5 /* RP06 sector/track reg offset */ | |
30 | # define RP_off 011 /* RP offset reg */ | |
31 | # define RP_cyl 10 /* RP06 cylinder reg offset */ | |
32 | /* */ | |
33 | # define RP_GO 1 /* go bit */ | |
34 | # define RP_RD 070 /* RP06 read function code */ | |
35 | # define RP_WR 060 /* RP06 write function code */ | |
36 | # define RP_DC 010 /* drive clear function code */ | |
37 | # define RP_FMT 0x1000 /* format bit in RP offset reg */ | |
38 | # define RP_RIP 020 /* Read-in Preset function code */ | |
39 | # define RP_MOL 0x1000 /* medium online bit in status */ | |
40 | # define RP_DRY 0200 /* drive ready, status reg */ | |
41 | # define RP_ERR 040000 /* composite error, status reg */ | |
42 | /* */ | |
43 | # define TM_GO 1 /* TM02 go bit */ | |
44 | # define TM_DCLR 010 /* TM02 drive clear function code */ | |
45 | # define TM_SFWD 030 /* space forward function code */ | |
46 | # define TM_WRTF 060 /* write forward function code */ | |
47 | # define TM_REDF 070 /* read forward function code */ | |
48 | # define TM_RWND 06 /* TM02 Rewind */ | |
49 | # define TM_WEOF 026 /* write end of file function */ | |
50 | # define TCHAR 01300 /* TM02/TE16 drive 0 ,800 BPI,PDP11,etc. */ | |
51 | # define TM_DRDY 0200 /* TM02/drive ready,status reg */ | |
52 | # define TM_ERR 040000 /* TM02 composite error, status reg */ | |
53 | /* */ | |
54 | # define RXCS 32 /* receiver control/staus */ | |
55 | # define RXDB 33 /* receiver data */ | |
56 | # define TXCS 34 /* transmitter control/status */ | |
57 | # define TXDB 35 /* transmitter data */ | |
58 | # define RXCS_DONE 0x80 /* receiver done */ | |
59 | # define TXCS_RDY 0x80 /* transmitter ready */ | |
60 | /* */ | |
61 | # define BUFSIZ 5120 /* max tape block size = input buffer size */ | |
62 | # define MAXUNI 1 | |
63 | # define NL 012 | |
64 | # define CR 015 | |
65 | /* */ | |
66 | char input[BUFSIZ] ; /* tape input buffer */ | |
67 | struct { int reg ; } ; | |
68 | int blksiz ,tapoff , dskoff , wsize , dblks ; | |
69 | int count; | |
70 | unsigned int ins , outs ; | |
71 | unsigned short nread , bytoff , error ; | |
72 | int *RPptr , dunit ; /* ptr to start of RP reg's for desired drive */ | |
73 | main() { | |
74 | /* | |
75 | * Stand-alone program to copy TM02/TE16 drive 0 mag tape to | |
76 | * RP06 disc. | |
77 | * User specifies tape block size (must be multiple of 512), tape | |
78 | * offset (tape blocks), disc unit no., disc offset (512-byte | |
79 | * blocks) and count of tape blocks to be transferred. | |
80 | */ | |
81 | int getcon() , putstr() , a2l() , l2a() ; | |
82 | ||
83 | putlin("d2tcpy : Disk-to-Tape Copy") ; | |
84 | putnl() ; | |
85 | ||
86 | bsize : | |
87 | if (putstr("tape block size : ")) goto fini ; | |
88 | if (getcon(input)) goto fini ; | |
89 | putnl() ; | |
90 | blksiz = a2l(input) ; | |
91 | if ((blksiz <= 0) || (blksiz > BUFSIZ)) goto bsize ; | |
92 | if (blksiz%512) goto bsize ; /* block size must be 512 multiple */ | |
93 | M0_cr->reg = MBAinit ; /* MBA 0 init */ | |
94 | M1_cr->reg = MBAinit ; /* MBA 1 init */ | |
95 | ||
96 | TM_tc->reg = TCHAR ; /* TE16,drive 0 ,800 BPI, PDP11, odd parity, | |
97 | abort on error */ | |
98 | TM_cs1->reg = TM_DCLR | TM_GO ; /* clear tape drive 0 */ | |
99 | if (terror()) goto taperr ; | |
100 | ||
101 | toff : | |
102 | if (putstr("tape offset : ")) goto fini ; | |
103 | if (getcon(input)) goto fini ; | |
104 | putnl() ; | |
105 | tapoff = a2l(input) ; | |
106 | if (tapoff < 0) goto toff ; | |
107 | if (taprew()) goto taperr ; | |
108 | if (tapspc(tapoff)) goto taperr ; | |
109 | ||
110 | dun : | |
111 | if (putstr("disk unit : ")) goto fini ; | |
112 | if (getcon(input)) goto fini ; | |
113 | putnl() ; | |
114 | dunit = a2l(input) ; | |
115 | if ((dunit > MAXUNI) || (dunit < 0)) goto dun ; | |
116 | ||
117 | doff : | |
118 | if (putstr("disc offset : ")) goto fini ; | |
119 | if (getcon(input)) goto fini ; | |
120 | putnl() ; | |
121 | dskoff = a2l(input) ; | |
122 | if ((dskoff < 0) || (dskoff > MAXSEC-1)) goto doff ; | |
123 | ||
124 | gknt : | |
125 | if (putstr("no. of input blocks : ")) goto fini ; | |
126 | if (getcon(input)) goto fini ; | |
127 | putnl() ; | |
128 | count = a2l(input) ; | |
129 | if (count < 0) goto gknt ; | |
130 | ||
131 | error = 0 ; | |
132 | ||
133 | if (init()) goto bsize ; | |
134 | ||
135 | while ((error == 0) && (count>0)) { | |
136 | if (dread()) { | |
137 | putlin("disc i/o error") ; | |
138 | goto ioerr ; | |
139 | } | |
140 | ins++ ; /* count of disk blocks input */ | |
141 | if (twrite()) { | |
142 | taperr : | |
143 | putlin("tape i/o error") ; | |
144 | ioerr : | |
145 | error++ ; | |
146 | continue ; | |
147 | } | |
148 | outs =+ dblks ; /* count of tape blocks output */ | |
149 | count -= nread ;/* dec no. blocks read */ | |
150 | } | |
151 | ||
152 | fini : | |
153 | TM_cs1->reg = TM_WEOF | TM_GO; | |
154 | twait(); | |
155 | TM_cs1->reg = TM_RWND | TM_GO; | |
156 | twait(); | |
157 | return(0) ; | |
158 | } | |
159 | ||
160 | /* */ | |
161 | ||
162 | putstr(csp) | |
163 | register char *csp ; | |
164 | { | |
165 | if (putcon(csp)) return(-1) ; | |
166 | return(0) ; | |
167 | } | |
168 | ||
169 | /* */ | |
170 | ||
171 | putlin(sptr) | |
172 | register char *sptr ; | |
173 | { | |
174 | if (putcon(sptr)) return(-1) ; | |
175 | if (putnl()) return(-1) ; | |
176 | return(0) ; | |
177 | } | |
178 | ||
179 | /* */ | |
180 | ||
181 | putnl() | |
182 | { | |
183 | if (putcon("\r\n")) return(-1) ; | |
184 | return(0) ; | |
185 | } | |
186 | ||
187 | /* */ | |
188 | ||
189 | putcon(csp) | |
190 | register char *csp ; | |
191 | { | |
192 | /* | |
193 | * Function to output null-terminated string pointed to | |
194 | * by 'csp' to the VAX LSI terminal. | |
195 | */ | |
196 | register c ; | |
197 | ||
198 | c = 0 ; | |
199 | while (c = (*csp++)) putc(c) ; | |
200 | return(0) ; | |
201 | } | |
202 | ||
203 | /* */ | |
204 | ||
205 | putc(c) | |
206 | { | |
207 | /* wait for LSI printer to be ready */ | |
208 | while ((mfpr(TXCS) & TXCS_RDY) == 0) ; | |
209 | /* output character */ | |
210 | mtpr(TXDB,c&0177) ; | |
211 | } | |
212 | ||
213 | /* */ | |
214 | ||
215 | getcon(cs) | |
216 | register char *cs ; | |
217 | { | |
218 | /* | |
219 | * Function to return char's from VAX LSI keyboard to | |
220 | * char array 'cs' - input stops when CR or LF received - | |
221 | * null char appended to end of input | |
222 | */ | |
223 | register int c , c2 ; | |
224 | int getc() ; | |
225 | ||
226 | inloop : | |
227 | c = getc() ; /* get 1 char from terminal */ | |
228 | putc(c) ; /* echo char */ | |
229 | if ((c == NL) || (c == CR)) { | |
230 | putc(CR) ; | |
231 | putc(0) ; | |
232 | putc(NL) ; | |
233 | (*cs++) = '\0' ; | |
234 | return(0) ; | |
235 | } | |
236 | else { | |
237 | (*cs++) = c ; | |
238 | goto inloop ; | |
239 | } | |
240 | } | |
241 | ||
242 | /* */ | |
243 | ||
244 | getc() | |
245 | { | |
246 | /* | |
247 | * Return char from VAX LSI terminal char buffer | |
248 | */ | |
249 | int mfpr() ; | |
250 | ||
251 | /* Wait for receiver done (user entered char) | |
252 | */ | |
253 | while ((mfpr(RXCS) & RXCS_DONE) == 0) ; | |
254 | return (mfpr(RXDB) & 0177) ; /* return char from receiver buffer */ | |
255 | } | |
256 | ||
257 | /* */ | |
258 | ||
259 | mtpr(regno,value) | |
260 | { | |
261 | asm(" mtpr 8(ap),4(ap)") ; | |
262 | } | |
263 | ||
264 | /* */ | |
265 | ||
266 | mfpr(regno) | |
267 | { | |
268 | asm(" mfpr 4(ap),r0") ; | |
269 | } | |
270 | ||
271 | /* */ | |
272 | ||
273 | a2l(as) | |
274 | register char *as ; | |
275 | { | |
276 | /* | |
277 | * Convert null-terminated ascii string to binary | |
278 | * and return value. | |
279 | * 1st char in string : | |
280 | * 0 -> octal | |
281 | * x -> hex | |
282 | * else decimal | |
283 | */ | |
284 | register value , base , sign , digit ; | |
285 | ||
286 | digit = value = sign = 0 ; | |
287 | base = 10 ; /* default base */ | |
288 | ||
289 | aloop : | |
290 | if ((digit = (*as++)) == 0) return(value) ; /* null */ | |
291 | ||
292 | if (digit == '-') { | |
293 | sign++ ; | |
294 | goto aloop ; | |
295 | } | |
296 | ||
297 | if (digit == '0') base = 8 ; /* octal base */ | |
298 | else { if (digit == 'x') base = 16 ; /* hex base */ | |
299 | else value = (digit-060) ; /* 060 = '0' */ | |
300 | } | |
301 | ||
302 | while (digit = (*as++)) { | |
303 | if (digit < '0') return(0) ; | |
304 | switch (base) { | |
305 | case 8 : { | |
306 | if (digit > '7') return(0) ; | |
307 | digit -= 060 ; | |
308 | break ; | |
309 | } | |
310 | case 10 : { | |
311 | if (digit > '9') return(0) ; | |
312 | digit -= 060 ; | |
313 | break ; | |
314 | } | |
315 | case 16 : { | |
316 | if (digit <= '9') { | |
317 | digit -= 060 ; | |
318 | break ; | |
319 | } | |
320 | if ((digit >= 'A') && (digit <= 'F')) { | |
321 | digit = (digit - 0101 + 10) ; | |
322 | break ; | |
323 | } | |
324 | if ((digit >= 'a') && (digit <= 'f')) { | |
325 | digit = digit - 0141 + 10 ; | |
326 | break ; | |
327 | } | |
328 | return(0) ; | |
329 | break ; | |
330 | } | |
331 | } | |
332 | value = (value * base) + digit ; | |
333 | } | |
334 | return (sign ? -value : value) ; | |
335 | } | |
336 | ||
337 | /* */ | |
338 | ||
339 | taprew() | |
340 | { | |
341 | /* | |
342 | * Function to rewind TM02/TE16 drive | |
343 | */ | |
344 | TM_cs1->reg = TM_RWND | TM_GO ; | |
345 | twait() ; | |
346 | if (terror()) return(-1) ; | |
347 | return(0) ; | |
348 | } | |
349 | ||
350 | /* */ | |
351 | ||
352 | tapspc(fblk) | |
353 | { | |
354 | /* | |
355 | * Function to space forward 'fblk' blocks on TM02/TE16 drive | |
356 | */ | |
357 | if (fblk) { | |
358 | TM_fc->reg = (-fblk) ; /* no. blocks */ | |
359 | TM_cs1->reg = TM_SFWD | TM_GO ; /* space forward */ | |
360 | twait() ; | |
361 | if (terror()) return(-1) ; | |
362 | } | |
363 | return(0) ; | |
364 | } | |
365 | ||
366 | /* */ | |
367 | ||
368 | twait() | |
369 | { | |
370 | /* | |
371 | * Function to wait until TM02/TE16 is not busy | |
372 | */ | |
373 | while ((TM_ds->reg & TM_DRDY) == 0) ; | |
374 | } | |
375 | ||
376 | /* */ | |
377 | ||
378 | terror() | |
379 | { | |
380 | /* | |
381 | * Function to check for TM02 error | |
382 | * Return (-1) if error, | |
383 | * esle return (0). | |
384 | */ | |
385 | if (TM_ds->reg & TM_ERR) return(-1) ; | |
386 | return(0) ; | |
387 | } | |
388 | ||
389 | /* */ | |
390 | ||
391 | init() { | |
392 | /* | |
393 | * Initialization. | |
394 | * Initialize MBA 0 (disk) and MBA 1 (tape). | |
395 | * Initialize TM02/TE16 for drive 0 , 800 BPI, PDP11, etc. | |
396 | * Set up MBA 0 and MBA 1 map registers to map a max. | |
397 | * transfer of 'BUFSIZ' bytes. | |
398 | */ | |
399 | register int *mp0 , *mp1 , i , page ; | |
400 | ||
401 | ||
402 | nread = BUFSIZ/blksiz ; /* no. of tape reads to fill input buffer */ | |
403 | wsize = nread * blksiz ; /* no. bytes each write to disc */ | |
404 | dblks = wsize/512 ; /* no. of disc blocks on each write */ | |
405 | RPptr = RP + (dunit * 32 * 4) ; /* start of RP reg's for drive */ | |
406 | if ((*(RPptr+RP_sr) & RP_MOL) == 0) { | |
407 | putlin("unit not online") ; | |
408 | return(-1) ; | |
409 | } | |
410 | ||
411 | *(RPptr+RP_cr) = RP_RIP | RP_GO ; /* preset :/ | |
412 | *(RPptr+RP_off) = RP_FMT ; /* set format bit */ | |
413 | bytoff = (int)(&input[0])&0777 ; /* byte offset of buffer addr */ | |
414 | page = ((int)&input[0] >> 9) & 07777777 ; /* start page of buffer */ | |
415 | mp0 = M0_map ; /* phys addr of MBA 0 map reg base */ | |
416 | mp1 = M1_map ; /* " " " 1 " " */ | |
417 | ||
418 | i = (((BUFSIZ+511)>>9)&0777) + 1 ; /* max. no. of pages */ | |
419 | ||
420 | while (i--) | |
421 | (*mp0++) = (*mp1++) = 0x80000000 | page++ ; /* map entry */ | |
422 | ||
423 | } | |
424 | ||
425 | /* */ | |
426 | ||
427 | twrite() | |
428 | { | |
429 | /* | |
430 | * Function to write TM02/TE16 tape drive, 'blksiz' bytes each | |
431 | * write, and 'nread' writes. | |
432 | */ | |
433 | register int i, j ; | |
434 | ||
435 | j = 0; | |
436 | for (i = MIN(nread,count) ; i ; i--) { | |
437 | M1_var->reg = bytoff + j++ * blksiz; | |
438 | M1_bc->reg = (-blksiz) ; /* MBA 1 byte count reg */ | |
439 | TM_fc->reg = (-blksiz); /* tape frame counter register */ | |
440 | TM_cs1->reg = TM_WRTF | TM_GO ; /* write forward */ | |
441 | twait() ; /* wait for ready */ | |
442 | if (terror()) return(-1) ; /* return on error */ | |
443 | } | |
444 | return(0) ; /* normal return */ | |
445 | } | |
446 | ||
447 | /* */ | |
448 | ||
449 | dread() | |
450 | { | |
451 | /* | |
452 | * Function to read 'wsize' bytes (512 multiple) from disc | |
453 | * to buffer 'input[]". | |
454 | */ | |
455 | register int i , j ; | |
456 | ||
457 | *(RPptr+RP_cr) = RP_DC | RP_GO ; /* drive clear */ | |
458 | *(RPptr+RP_cyl) = dskoff/RP6ST ; /* cylinder no. */ | |
459 | i = dskoff%RP6ST ; | |
460 | j = (i/RP6SEC)<<8 ; /* track */ | |
461 | *(RPptr+RP_stk) = j | (i%RP6SEC) ; /* sector : track */ | |
462 | M0_bc->reg = (count<nread?-(count*512):(-wsize)) ; /* byte count */ | |
463 | M0_var->reg = bytoff ; /* virt addr reg = map no. + byte off */ | |
464 | *(RPptr+RP_cr) = RP_RD | RP_GO ; /* write */ | |
465 | ||
466 | dskoff =+ dblks ; /* point to next disc sector */ | |
467 | dwait() ; /* wait for i/o to finish */ | |
468 | if (derror()) return(-1) ; /* error */ | |
469 | return(0) ; /* normal return */ | |
470 | } | |
471 | ||
472 | /* */ | |
473 | ||
474 | dwait() { | |
475 | /* | |
476 | * Function to wait MBA 0 RP06 disc unit to be ready. | |
477 | */ | |
478 | while ((*(RPptr+RP_sr)&RP_DRY) == 0) ; | |
479 | } | |
480 | ||
481 | /* */ | |
482 | ||
483 | derror() | |
484 | { | |
485 | /* | |
486 | * Function to check for MBA 0 RP06 error. | |
487 | */ | |
488 | if (*(RPptr+RP_sr) & RP_ERR) return(-1) ; | |
489 | return(0) ; | |
490 | } | |
491 | ||
492 | /* */ | |
493 | ||
494 | halt() | |
495 | { | |
496 | asm(" halt") ; | |
497 | } | |
498 | ||
499 | /* */ | |
500 | ||
501 | l2a(val,rptr) | |
502 | register int val ; | |
503 | register char *rptr ; | |
504 | { | |
505 | register int i ; | |
506 | register char *tp ; | |
507 | int knt ; | |
508 | char tmp[20] , sign ; | |
509 | ||
510 | knt = sign = 0 ; | |
511 | if (val < 0) { | |
512 | sign++ ; | |
513 | val = (-val) ; | |
514 | } | |
515 | ||
516 | tp = tmp ; | |
517 | loop : | |
518 | knt++ ; | |
519 | i = val/10 ; /* quotient & base 10 */ | |
520 | (*tp++) = val%10 + '0' ; /* ascii remainder */ | |
521 | val = i ; | |
522 | if (val == 0) { | |
523 | /* done dividing */ | |
524 | if (sign) { knt++ ; (*tp++) = '-' ; } | |
525 | for (i = knt ; i ; i--) | |
526 | (*rptr++) = tmp[i-1] ; | |
527 | (*rptr++) = '\0' ; | |
528 | return(knt) ; | |
529 | } | |
530 | else goto loop ; | |
531 | } | |
532 | ||
533 | /* */ | |
534 | ||
535 | echo(lngword) | |
536 | register int lngword ; | |
537 | { | |
538 | char tmp[30] ; | |
539 | ||
540 | l2a(lngword,tmp) ; | |
541 | putlin(tmp) ; | |
542 | } |