1 /* pdp8_ct.c: PDP-8 cassette tape simulator
2
3 Copyright (c) 2006-2011, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 ct TA8E/TU60 cassette tape
27
28 13-Aug-07 RMS Fixed handling of BEOT
29 06-Aug-07 RMS Foward op at BOT skips initial file gap
30 30-May-2007 RMS Fixed typo (Norm Lastovica)
31
32 Magnetic tapes are represented as a series of variable records
33 of the form:
34
35 32b byte count
36 byte 0
37 byte 1
38 :
39 byte n-2
40 byte n-1
41 32b byte count
42
43 If the byte count is odd, the record is padded with an extra byte
44 of junk. File marks are represented by a byte count of 0.
45
46 Cassette format differs in one very significant way: it has file gaps
47 rather than file marks. If the controller spaces or reads into a file
48 gap and then reverses direction, the file gap is not seen again. This
49 is in contrast to magnetic tapes, where the file mark is a character
50 sequence and is seen again if direction is reversed. In addition,
51 cassettes have an initial file gap which is automatically skipped on
52 forward operations from beginning of tape.
53
54 Note that the read and write sequences for the cassette are asymmetric:
55
56 Read: KLSA /SELECT READ
57 KGOA /INIT READ, CLEAR DF
58 <data flag sets, char in buf>
59 KGOA /READ 1ST CHAR, CLEAR DF
60 DCA CHAR
61 :
62 <data flag sets, char in buf>
63 KGOA /READ LAST CHAR, CLEAR DF
64 DCA CHAR
65 <data flag sets, CRC1 in buf>
66 KLSA /SELECT CRC MODE
67 KGOA /READ 1ST CRC
68 <data flag sets, CRC2 in buf>
69 KGOA /READ 2ND CRC
70 <ready flag/CRC error flag sets>
71
72 Write: KLSA /SELECT WRITE
73 TAD CHAR /1ST CHAR
74 KGOA /INIT WRITE, CHAR TO BUF, CLEAR DF
75 <data flag sets, char to tape>
76 :
77 TAD CHAR /LAST CHAR
78 KGOA /CHAR TO BUF, CLEAR DF
79 <data flag sets, char to tape>
80 KLSA /SELECT CRC MODE
81 KGOA /WRITE CRC, CLEAR DF
82 <ready flag sets, CRC on tape>
83 */
84
85 #include "pdp8_defs.h"
86 #include "sim_tape.h"
87
88 #define CT_NUMDR 2 /* #drives */
89 #define FNC u3 /* unit function */
90 #define UST u4 /* unit status */
91 #define CT_MAXFR (CT_SIZE) /* max record lnt */
92 #define CT_SIZE 93000 /* chars/tape */
93
94 /* Status Register A */
95
96 #define SRA_ENAB 0200 /* enable */
97 #define SRA_V_UNIT 6 /* unit */
98 #define SRA_M_UNIT (CT_NUMDR - 1)
99 #define SRA_V_FNC 3 /* function */
100 #define SRA_M_FNC 07
101 #define SRA_READ 00
102 #define SRA_REW 01
103 #define SRA_WRITE 02
104 #define SRA_SRF 03
105 #define SRA_WFG 04
106 #define SRA_SRB 05
107 #define SRA_CRC 06
108 #define SRA_SFF 07
109 #define SRA_2ND 010
110 #define SRA_IE 0001 /* int enable */
111 #define GET_UNIT(x) (((x) >> SRA_V_UNIT) & SRA_M_UNIT)
112 #define GET_FNC(x) (((x) >> SRA_V_FNC) & SRA_M_FNC)
113
114 /* Function code flags */
115
116 #define OP_WRI 01 /* op is a write */
117 #define OP_REV 02 /* op is rev motion */
118 #define OP_FWD 04 /* op is fwd motion */
119
120 /* Unit status flags */
121
122 #define UST_REV (OP_REV) /* last op was rev */
123 #define UST_GAP 01 /* last op hit gap */
124
125 /* Status Register B, ^ = computed on the fly */
126
127 #define SRB_WLE 0400 /* "write lock err" */
128 #define SRB_CRC 0200 /* CRC error */
129 #define SRB_TIM 0100 /* timing error */
130 #define SRB_BEOT 0040 /* ^BOT/EOT */
131 #define SRB_EOF 0020 /* end of file */
132 #define SRB_EMP 0010 /* ^drive empty */
133 #define SRB_REW 0004 /* rewinding */
134 #define SRB_WLK 0002 /* ^write locked */
135 #define SRB_RDY 0001 /* ^ready */
136 #define SRB_ALLERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_BEOT|SRB_EOF|SRB_EMP)
137 #define SRB_XFRERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_EOF)
138
139 extern int32 int_req, stop_inst;
140 extern UNIT cpu_unit;
141 extern FILE *sim_deb;
142
143 uint32 ct_sra = 0; /* status reg A */
144 uint32 ct_srb = 0; /* status reg B */
145 uint32 ct_db = 0; /* data buffer */
146 uint32 ct_df = 0; /* data flag */
147 uint32 ct_write = 0; /* TU60 write flag */
148 uint32 ct_bptr = 0; /* buf ptr */
149 uint32 ct_blnt = 0; /* buf length */
150 int32 ct_stime = 1000; /* start time */
151 int32 ct_ctime = 100; /* char latency */
152 uint32 ct_stopioe = 1; /* stop on error */
153 uint8 *ct_xb = NULL; /* transfer buffer */
154 static uint8 ct_fnc_tab[SRA_M_FNC + 1] = {
155 OP_FWD, 0 , OP_WRI|OP_FWD, OP_REV,
156 OP_WRI|OP_FWD, OP_REV, 0, OP_FWD
157 };
158
159 DEVICE ct_dev;
160 int32 ct70 (int32 IR, int32 AC);
161 t_stat ct_svc (UNIT *uptr);
162 t_stat ct_reset (DEVICE *dptr);
163 t_stat ct_attach (UNIT *uptr, char *cptr);
164 t_stat ct_detach (UNIT *uptr);
165 t_stat ct_boot (int32 unitno, DEVICE *dptr);
166 uint32 ct_updsta (UNIT *uptr);
167 int32 ct_go_start (int32 AC);
168 int32 ct_go_cont (UNIT *uptr, int32 AC);
169 t_stat ct_map_err (UNIT *uptr, t_stat st);
170 UNIT *ct_busy (void);
171 void ct_set_df (t_bool timchk);
172 t_bool ct_read_char (void);
173 uint32 ct_crc (uint8 *buf, uint32 cnt);
174
175 /* CT data structures
176
177 ct_dev CT device descriptor
178 ct_unit CT unit list
179 ct_reg CT register list
180 ct_mod CT modifier list
181 */
182
183 DIB ct_dib = { DEV_CT, 1, { &ct70 } };
184
185 UNIT ct_unit[] = {
186 { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) },
187 { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) },
188 };
189
190 REG ct_reg[] = {
191 { ORDATA (CTSRA, ct_sra, 8) },
192 { ORDATA (CTSRB, ct_srb, 8) },
193 { ORDATA (CTDB, ct_db, 8) },
194 { FLDATA (CTDF, ct_df, 0) },
195 { FLDATA (RDY, ct_srb, 0) },
196 { FLDATA (WLE, ct_srb, 8) },
197 { FLDATA (WRITE, ct_write, 0) },
198 { FLDATA (INT, int_req, INT_V_CT) },
199 { DRDATA (BPTR, ct_bptr, 17) },
200 { DRDATA (BLNT, ct_blnt, 17) },
201 { DRDATA (STIME, ct_stime, 24), PV_LEFT + REG_NZ },
202 { DRDATA (CTIME, ct_ctime, 24), PV_LEFT + REG_NZ },
203 { FLDATA (STOP_IOE, ct_stopioe, 0) },
204 { URDATA (UFNC, ct_unit[0].FNC, 8, 4, 0, CT_NUMDR, 0), REG_HRO },
205 { URDATA (UST, ct_unit[0].UST, 8, 2, 0, CT_NUMDR, 0), REG_HRO },
206 { URDATA (POS, ct_unit[0].pos, 10, T_ADDR_W, 0,
207 CT_NUMDR, PV_LEFT | REG_RO) },
208 { FLDATA (DEVNUM, ct_dib.dev, 6), REG_HRO },
209 { NULL }
210 };
211
212 MTAB ct_mod[] = {
213 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
214 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
215 // { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
216 // &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
217 { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL,
218 NULL, &sim_tape_show_capac, NULL },
219 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
220 &set_dev, &show_dev, NULL },
221 { 0 }
222 };
223
224 DEVICE ct_dev = {
225 "CT", ct_unit, ct_reg, ct_mod,
226 CT_NUMDR, 10, 31, 1, 8, 8,
227 NULL, NULL, &ct_reset,
228 &ct_boot, &ct_attach, &ct_detach,
229 &ct_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG
230 };
231
232 /* IOT routines */
233
ct70(int32 IR,int32 AC)234 int32 ct70 (int32 IR, int32 AC)
235 {
236 int32 srb;
237 UNIT *uptr;
238
239 srb = ct_updsta (NULL); /* update status */
240 switch (IR & 07) { /* decode IR<9:11> */
241
242 case 0: /* KCLR */
243 ct_reset (&ct_dev); /* reset the world */
244 break;
245
246 case 1: /* KSDR */
247 if (ct_df)
248 AC |= IOT_SKP;
249 break;
250
251 case 2: /* KSEN */
252 if (srb & SRB_ALLERR)
253 AC |= IOT_SKP;
254 break;
255
256 case 3: /* KSBF */
257 if ((srb & SRB_RDY) && !(srb & SRB_EMP))
258 AC |= IOT_SKP;
259 break;
260
261 case 4: /* KLSA */
262 ct_sra = AC & 0377;
263 ct_updsta (NULL);
264 return ct_sra ^ 0377;
265
266 case 5: /* KSAF */
267 if (ct_df || (srb & (SRB_ALLERR|SRB_RDY)))
268 AC |= IOT_SKP;
269 break;
270
271 case 6: /* KGOA */
272 ct_df = 0; /* clear data flag */
273 if ((uptr = ct_busy ())) /* op in progress? */
274 AC = ct_go_cont (uptr, AC); /* yes */
275 else AC = ct_go_start (AC); /* no, start */
276 ct_updsta (NULL);
277 break;
278
279 case 7: /* KSRB */
280 return srb & 0377;
281 } /* end switch */
282
283 return AC;
284 }
285
286 /* Start a new operation - cassette is not busy */
287
ct_go_start(int32 AC)288 int32 ct_go_start (int32 AC)
289 {
290 UNIT *uptr = ct_dev.units + GET_UNIT (ct_sra);
291 uint32 fnc = GET_FNC (ct_sra);
292 uint32 flg = ct_fnc_tab[fnc];
293 uint32 old_ust = uptr->UST;
294
295 if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
296 ">>CT start: op=%o, old_sta = %o, pos=%d\n",
297 fnc, uptr->UST, uptr->pos);
298 if ((ct_sra & SRA_ENAB) && (uptr->flags & UNIT_ATT)) { /* enabled, att? */
299 ct_srb &= ~(SRB_XFRERR|SRB_REW); /* clear err, rew */
300 if (flg & OP_WRI) { /* write-type op? */
301 if (sim_tape_wrp (uptr)) { /* locked? */
302 ct_srb |= SRB_WLE; /* set flag, abort */
303 return AC;
304 }
305 ct_write = 1; /* set TU60 wr flag */
306 ct_db = AC & 0377;
307 }
308 else {
309 ct_write = 0;
310 ct_db = 0;
311 }
312 ct_srb &= ~SRB_BEOT; /* tape in motion */
313 if (fnc == SRA_REW) /* rew? set flag */
314 ct_srb |= SRB_REW;
315 if ((fnc != SRA_REW) && !(flg & OP_WRI)) { /* read cmd? */
316 t_mtrlnt t;
317 t_stat st;
318 uptr->UST = flg & UST_REV; /* save direction */
319 if (sim_tape_bot (uptr) && (flg & OP_FWD)) { /* spc/read fwd bot? */
320 st = sim_tape_rdrecf (uptr, ct_xb, &t, CT_MAXFR); /* skip file gap */
321 if (st != MTSE_TMK) /* not there? */
322 sim_tape_rewind (uptr); /* restore tap pos */
323 else old_ust = 0; /* defang next */
324 }
325 if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* rev in gap? */
326 if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
327 ">>CT skip gap: op=%o, old_sta = %o, pos=%d\n",
328 fnc, uptr->UST, uptr->pos);
329 if (uptr->UST) /* skip file gap */
330 sim_tape_rdrecr (uptr, ct_xb, &t, CT_MAXFR);
331 else sim_tape_rdrecf (uptr, ct_xb, &t, CT_MAXFR);
332 }
333 }
334 else uptr->UST = 0;
335 ct_bptr = 0; /* init buffer */
336 ct_blnt = 0;
337 uptr->FNC = fnc; /* save function */
338 sim_activate (uptr, ct_stime); /* schedule op */
339 }
340 if ((fnc == SRA_READ) || (fnc == SRA_CRC)) /* read or CRC? */
341 return 0; /* get "char" */
342 return AC;
343 }
344
345 /* Continue an in-progress operation - cassette is in motion */
346
ct_go_cont(UNIT * uptr,int32 AC)347 int32 ct_go_cont (UNIT *uptr, int32 AC)
348 {
349 int32 fnc = GET_FNC (ct_sra);
350
351 switch (fnc) { /* case on function */
352
353 case SRA_READ: /* read */
354 return ct_db; /* return data */
355
356 case SRA_WRITE: /* write */
357 ct_db = AC & 0377; /* save data */
358 break;
359
360 case SRA_CRC: /* CRC */
361 if ((uptr->FNC & SRA_M_FNC) != SRA_CRC) /* if not CRC */
362 uptr->FNC = SRA_CRC; /* start CRC seq */
363 if (!ct_write) /* read? AC <- buf */
364 return ct_db;
365 break;
366
367 default:
368 break;
369 }
370
371 return AC;
372 }
373
374 /* Unit service */
375
ct_svc(UNIT * uptr)376 t_stat ct_svc (UNIT *uptr)
377 {
378 uint32 i, crc;
379 uint32 flgs = ct_fnc_tab[uptr->FNC & SRA_M_FNC];
380 t_mtrlnt tbc;
381 t_stat st, r;
382
383 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
384 ct_updsta (uptr); /* update status */
385 return (ct_stopioe? SCPE_UNATT: SCPE_OK);
386 }
387 if (((flgs & OP_REV) && sim_tape_bot (uptr)) || /* rev at BOT or */
388 ((flgs & OP_FWD) && sim_tape_eot (uptr))) { /* fwd at EOT? */
389 ct_srb |= SRB_BEOT; /* error */
390 ct_updsta (uptr); /* op done */
391 return SCPE_OK;
392 }
393
394 r = SCPE_OK;
395 switch (uptr->FNC) { /* case on function */
396
397 case SRA_READ: /* read start */
398 st = sim_tape_rdrecf (uptr, ct_xb, &ct_blnt, CT_MAXFR); /* get rec */
399 if (st == MTSE_RECE) /* rec in err? */
400 ct_srb |= SRB_CRC;
401 else if (st != MTSE_OK) { /* other error? */
402 r = ct_map_err (uptr, st); /* map error */
403 break;
404 }
405 crc = ct_crc (ct_xb, ct_blnt); /* calculate CRC */
406 ct_xb[ct_blnt++] = (crc >> 8) & 0377; /* append to buffer */
407 ct_xb[ct_blnt++] = crc & 0377;
408 uptr->FNC |= SRA_2ND; /* next state */
409 sim_activate (uptr, ct_ctime); /* sched next char */
410 return SCPE_OK;
411
412 case SRA_READ|SRA_2ND: /* read char */
413 if (!ct_read_char ()) /* read, overrun? */
414 break;
415 ct_set_df (TRUE); /* set data flag */
416 sim_activate (uptr, ct_ctime); /* sched next char */
417 return SCPE_OK;
418
419 case SRA_WRITE: /* write start */
420 for (i = 0; i < CT_MAXFR; i++) /* clear buffer */
421 ct_xb[i] = 0;
422 uptr->FNC |= SRA_2ND; /* next state */
423 sim_activate (uptr, ct_ctime); /* sched next char */
424 return SCPE_OK;
425
426 case SRA_WRITE|SRA_2ND: /* write char */
427 if ((ct_bptr < CT_MAXFR) && /* room in buf? */
428 ((uptr->pos + ct_bptr) < uptr->capac)) /* room on tape? */
429 ct_xb[ct_bptr++] = ct_db; /* store char */
430 ct_set_df (TRUE); /* set data flag */
431 sim_activate (uptr, ct_ctime); /* sched next char */
432 return SCPE_OK;
433
434 case SRA_CRC: /* CRC */
435 if (ct_write) { /* write? */
436 if ((st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr))) /* write, err? */
437 r = ct_map_err (uptr, st); /* map error */
438 break; /* write done */
439 }
440 ct_read_char (); /* get second CRC */
441 ct_set_df (FALSE); /* set df */
442 uptr->FNC |= SRA_2ND; /* next state */
443 sim_activate (uptr, ct_ctime);
444 return SCPE_OK;
445
446 case SRA_CRC|SRA_2ND: /* second read CRC */
447 if (ct_bptr != ct_blnt) { /* partial read? */
448 crc = ct_crc (ct_xb, ct_bptr); /* actual CRC */
449 if (crc != 0) /* must be zero */
450 ct_srb |= SRB_CRC;
451 }
452 break; /* read done */
453
454 case SRA_WFG: /* write file gap */
455 if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */
456 r = ct_map_err (uptr, st); /* map error */
457 break;
458
459 case SRA_REW: /* rewind */
460 sim_tape_rewind (uptr);
461 ct_srb |= SRB_BEOT; /* set BOT */
462 break;
463
464 case SRA_SRB: /* space rev blk */
465 if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */
466 r = ct_map_err (uptr, st); /* map error */
467 break;
468
469 case SRA_SRF: /* space rev file */
470 while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
471 r = ct_map_err (uptr, st); /* map error */
472 break;
473
474 case SRA_SFF: /* space fwd file */
475 while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
476 r = ct_map_err (uptr, st); /* map error */
477 break;
478
479 default: /* never get here! */
480 return SCPE_IERR;
481 } /* end case */
482
483 ct_updsta (uptr); /* update status */
484 if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
485 ">>CT done: op=%o, statusA = %o, statusB = %o, pos=%d\n",
486 uptr->FNC, ct_sra, ct_srb, uptr->pos);
487 return r;
488 }
489
490 /* Update controller status */
491
ct_updsta(UNIT * uptr)492 uint32 ct_updsta (UNIT *uptr)
493 {
494 int32 srb;
495
496 if (uptr == NULL) { /* unit specified? */
497 uptr = ct_busy (); /* use busy unit */
498 if ((uptr == NULL) && (ct_sra & SRA_ENAB)) /* none busy? */
499 uptr = ct_dev.units + GET_UNIT (ct_sra); /* use sel unit */
500 }
501 else if (ct_srb & SRB_EOF) /* save gap */
502 uptr->UST |= UST_GAP;
503 if (uptr) { /* any unit? */
504 ct_srb &= ~(SRB_WLK|SRB_EMP|SRB_RDY); /* clear dyn flags */
505 if ((uptr->flags & UNIT_ATT) == 0) /* unattached? */
506 ct_srb = (ct_srb | SRB_EMP|SRB_WLK) & ~SRB_REW; /* empty, locked */
507 if (!sim_is_active (uptr)) { /* not busy? */
508 ct_srb = (ct_srb | SRB_RDY) & ~SRB_REW; /* ready, ~rew */
509 }
510 if (sim_tape_wrp (uptr) || (ct_srb & SRB_REW)) /* locked or rew? */
511 ct_srb |= SRB_WLK; /* set locked */
512 }
513 if (ct_sra & SRA_ENAB) /* can TA see TU60? */
514 srb = ct_srb;
515 else srb = 0; /* no */
516 if ((ct_sra & SRA_IE) && /* int enabled? */
517 (ct_df || (srb & (SRB_ALLERR|SRB_RDY)))) /* any flag? */
518 int_req |= INT_CT; /* set int req */
519 else int_req &= ~INT_CT; /* no, clr int req */
520 return srb;
521 }
522
523 /* Set data flag */
524
ct_set_df(t_bool timchk)525 void ct_set_df (t_bool timchk)
526 {
527 if (ct_df && timchk) /* flag still set? */
528 ct_srb |= SRB_TIM;
529 ct_df = 1; /* set data flag */
530 if (ct_sra & SRA_IE) /* if ie, int req */
531 int_req |= INT_CT;
532 return;
533 }
534
535 /* Read character */
536
ct_read_char(void)537 t_bool ct_read_char (void)
538 {
539 if (ct_bptr < ct_blnt) { /* more chars? */
540 ct_db = ct_xb[ct_bptr++];
541 return TRUE;
542 }
543 ct_db = 0;
544 ct_srb |= SRB_CRC; /* overrun */
545 return FALSE;
546 }
547
548 /* Test if controller busy */
549
ct_busy(void)550 UNIT *ct_busy (void)
551 {
552 uint32 u;
553 UNIT *uptr;
554
555 for (u = 0; u < CT_NUMDR; u++) { /* loop thru units */
556 uptr = ct_dev.units + u;
557 if (sim_is_active (uptr))
558 return uptr;
559 }
560 return NULL;
561 }
562
563 /* Calculate CRC on buffer */
564
ct_crc(uint8 * buf,uint32 cnt)565 uint32 ct_crc (uint8 *buf, uint32 cnt)
566 {
567 uint32 crc, i, j;
568
569 crc = 0;
570 for (i = 0; i < cnt; i++) {
571 crc = crc ^ (((uint32) buf[i]) << 8);
572 for (j = 0; j < 8; j++) {
573 if (crc & 1)
574 crc = (crc >> 1) ^ 0xA001;
575 else crc = crc >> 1;
576 }
577 }
578 return crc;
579 }
580
581 /* Map error status */
582
ct_map_err(UNIT * uptr,t_stat st)583 t_stat ct_map_err (UNIT *uptr, t_stat st)
584 {
585 switch (st) {
586
587 case MTSE_FMT: /* illegal fmt */
588 case MTSE_UNATT: /* unattached */
589 ct_srb |= SRB_CRC;
590 case MTSE_OK: /* no error */
591 return SCPE_IERR; /* never get here! */
592
593 case MTSE_TMK: /* end of file */
594 ct_srb |= SRB_EOF;
595 break;
596
597 case MTSE_IOERR: /* IO error */
598 ct_srb |= SRB_CRC; /* set crc err */
599 if (ct_stopioe)
600 return SCPE_IOERR;
601 break;
602
603 case MTSE_INVRL: /* invalid rec lnt */
604 ct_srb |= SRB_CRC; /* set crc err */
605 return SCPE_MTRLNT;
606
607 case MTSE_RECE: /* record in error */
608 case MTSE_EOM: /* end of medium */
609 ct_srb |= SRB_CRC; /* set crc err */
610 break;
611
612 case MTSE_BOT: /* reverse into BOT */
613 ct_srb |= SRB_BEOT; /* set BOT */
614 break;
615
616 case MTSE_WRP: /* write protect */
617 ct_srb |= SRB_WLE; /* set wlk err */
618 break;
619 }
620
621 return SCPE_OK;
622 }
623
624 /* Reset routine */
625
ct_reset(DEVICE * dptr)626 t_stat ct_reset (DEVICE *dptr)
627 {
628 uint32 u;
629 UNIT *uptr;
630
631 ct_sra = 0;
632 ct_srb = 0;
633 ct_df = 0;
634 ct_db = 0;
635 ct_write = 0;
636 ct_bptr = 0;
637 ct_blnt = 0;
638 int_req = int_req & ~INT_CT; /* clear interrupt */
639 for (u = 0; u < CT_NUMDR; u++) { /* loop thru units */
640 uptr = ct_dev.units + u;
641 sim_cancel (uptr); /* cancel activity */
642 sim_tape_reset (uptr); /* reset tape */
643 }
644 if (ct_xb == NULL)
645 ct_xb = (uint8 *) calloc (CT_MAXFR + 2, sizeof (uint8));
646 if (ct_xb == NULL)
647 return SCPE_MEM;
648 return SCPE_OK;
649 }
650
651 /* Attach routine */
652
ct_attach(UNIT * uptr,char * cptr)653 t_stat ct_attach (UNIT *uptr, char *cptr)
654 {
655 t_stat r;
656
657 r = sim_tape_attach (uptr, cptr);
658 if (r != SCPE_OK)
659 return r;
660 ct_updsta (NULL);
661 uptr->UST = 0;
662 return r;
663 }
664
665 /* Detach routine */
666
ct_detach(UNIT * uptr)667 t_stat ct_detach (UNIT* uptr)
668 {
669 t_stat r;
670
671 if (!(uptr->flags & UNIT_ATT)) /* check attached */
672 return SCPE_OK;
673 r = sim_tape_detach (uptr);
674 ct_updsta (NULL);
675 uptr->UST = 0;
676 return r;
677 }
678
679 /* Bootstrap routine */
680
681 #define BOOT_START 04000
682 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
683
684 static const uint16 boot_rom[] = {
685 01237, /* BOOT, TAD M50 /change CRC to REW */
686 01206, /* CRCCHK, TAD L260 /crc op */
687 06704, /* KLSA /load op */
688 06706, /* KGOA /start */
689 06703, /* KSBF /ready? */
690 05204, /* RDCOD, JMP .-1 /loop */
691 07264, /* L260, CML STA RAL /L = 1, AC = halt */
692 06702, /* KSEN /error? */
693 07610, /* SKP CLA /halt on any error */
694 03211, /* DCA . /except REW or FFG */
695 03636, /* DCA I PTR /TAD I PTR mustn't change L */
696 01205, /* TAD RDCOD /read op */
697 06704, /* KLSA /load op */
698 06706, /* KGOA /start */
699 06701, /* LOOP, KSDF /data ready? */
700 05216, /* JMP .-1 /loop */
701 07002, /* BSW /to upper 6b */
702 07430, /* SZL /second byte? */
703 01636, /* TAD I PTR /yes */
704 07022, /* CML BSW /swap back */
705 03636, /* DCA I PTR /store in mem */
706 07420, /* SNL /done with both bytes? */
707 02236, /* ISZ PTR /yes, bump mem ptr */
708 02235, /* ISZ KNT /done with record? */
709 05215, /* JMP LOOP /next byte */
710 07346, /* STA CLL RTL */
711 07002, /* BSW /AC = 7757 */
712 03235, /* STA KNT /now read 200 byte record */
713 05201, /* JMP CRCCHK /go check CRC */
714 07737, /* KNT, 7737 /1's compl of byte count */
715 03557, /* PTR, 3557 /load point */
716 07730, /* M50, 7730 /CLA SPA SZL */
717 };
718
ct_boot(int32 unitno,DEVICE * dptr)719 t_stat ct_boot (int32 unitno, DEVICE *dptr)
720 {
721 int32 i;
722 extern int32 saved_PC;
723 extern uint16 M[];
724
725 if ((ct_dib.dev != DEV_CT) || unitno) /* only std devno */
726 return STOP_NOTSTD;
727 for (i = 0; i < BOOT_LEN; i++)
728 M[BOOT_START + i] = boot_rom[i];
729 saved_PC = BOOT_START;
730 return SCPE_OK;
731 }
732