1 /* hp2100_mt.c: HP 2100 12559C 9-Track Magnetic Tape Unit Interface
2
3 Copyright (c) 1993-2016, Robert M. Supnik
4 Copyright (c) 2017-2020, J. David Bryan
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the names of the authors shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from the authors.
26
27 MT 12559C 9-Track Magnetic Tape Unit Interface
28
29 09-Dec-20 JDB Replaced "io_assert" with "io_assert_ENF"
30 02-Dec-20 JDB RESET no longer presets the interface
31 18-Mar-19 JDB Reordered SCP includes
32 24-Jan-19 JDB Removed DEV_TAPE from DEVICE flags
33 11-Jul-18 JDB Revised I/O model
34 20-Jul-17 JDB Removed "mtc_stopioe" variable and register
35 13-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for ATTACH -R
36 13-May-16 JDB Modified for revised SCP API function parameter types
37 24-Dec-14 JDB Added casts for explicit downward conversions
38 10-Jan-13 MP Added DEV_TAPE to DEVICE flags
39 09-May-12 JDB Separated assignments from conditional expressions
40 25-Mar-12 JDB Removed redundant MTAB_VUN from "format" MTAB entry
41 10-Feb-12 JDB Deprecated DEVNO in favor of SC
42 28-Mar-11 JDB Tidied up signal handling
43 29-Oct-10 JDB Fixed command scanning error in mtcio ioIOO handler
44 26-Oct-10 JDB Changed I/O signal handler for revised signal model
45 04-Sep-08 JDB Fixed missing flag after CLR command
46 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC
47 26-Jun-08 JDB Rewrote device I/O to model backplane signals
48 28-Dec-06 JDB Added ioCRS state to I/O decoders
49 07-Oct-04 JDB Allow enable/disable from either device
50 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan)
51 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)
52 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
53 Implemented DMA SRQ (follows FLG)
54 21-Dec-03 RMS Adjusted msc_ctime for TSB (from Mike Gemeny)
55 25-Apr-03 RMS Revised for extended file support
56 28-Mar-03 RMS Added multiformat support
57 28-Feb-03 RMS Revised for magtape library
58 30-Sep-02 RMS Revamped error handling
59 28-Aug-02 RMS Added end of medium support
60 30-May-02 RMS Widened POS to 32b
61 22-Apr-02 RMS Added maximum record length test
62 20-Jan-02 RMS Fixed bug on last character write
63 03-Dec-01 RMS Added read only unit, extended SET/SHOW support
64 07-Sep-01 RMS Moved function prototypes
65 30-Nov-00 RMS Made variable names unique
66 04-Oct-98 RMS V2.4 magtape format
67
68 References:
69 - 12559A 9-Track Magnetic Tape Unit Interface Kit Operating and Service Manual
70 (12559-9001, July 1970)
71 - SIMH Magtape Representation and Handling
72 (Bob Supnik, 30-Aug-2006)
73
74
75 The 3030 was one of HP's earliest tape drives. The 12559A controller
76 supported a single 800 bpi, 9-track drive, operating at 75 inches per second.
77 It had two unusual characteristics:
78
79 - The controller accepted only one byte per I/O word, rather than packing
80 two bytes per word.
81
82 - The drive could not read or write fewer than 12 bytes per record.
83
84 The first behavior meant that DMA operation required the byte-unpacking
85 feature of the 12578A DMA card for the 2116 computer. The second meant that
86 software drivers had to pad short records with blanks or nulls.
87
88
89 Implementation notes:
90
91 1. The HP 3030 Magnetic Tape Subsystem diagnostic, part number 20433-60001,
92 has never been located, so this simulator has not been fully tested. It
93 does pass a functional test under DOS-III using driver DVR22.
94 */
95
96
97
98 #include "sim_defs.h"
99 #include "sim_tape.h"
100
101 #include "hp2100_defs.h"
102 #include "hp2100_io.h"
103
104
105
106 #define DB_V_SIZE 16 /* max data buf */
107 #define DBSIZE (1 << DB_V_SIZE) /* max data cmd */
108
109 /* Command - mtc_fnc */
110
111 #define FNC_CLR 0300 /* clear */
112 #define FNC_WC 0031 /* write */
113 #define FNC_RC 0023 /* read */
114 #define FNC_GAP 0011 /* write gap */
115 #define FNC_FSR 0003 /* forward space */
116 #define FNC_BSR 0041 /* backward space */
117 #define FNC_REW 0201 /* rewind */
118 #define FNC_RWS 0101 /* rewind and offline */
119 #define FNC_WFM 0035 /* write file mark */
120
121 /* Status - stored in mtc_sta, (d) = dynamic */
122
123 #define STA_LOCAL 0400 /* local (d) */
124 #define STA_EOF 0200 /* end of file */
125 #define STA_BOT 0100 /* beginning of tape */
126 #define STA_EOT 0040 /* end of tape */
127 #define STA_TIM 0020 /* timing error */
128 #define STA_REJ 0010 /* programming error */
129 #define STA_WLK 0004 /* write locked (d) */
130 #define STA_PAR 0002 /* parity error */
131 #define STA_BUSY 0001 /* busy (d) */
132
133 /* Interface state */
134
135 typedef struct {
136 FLIP_FLOP control; /* control flip-flop */
137 FLIP_FLOP flag; /* flag flip-flop */
138 FLIP_FLOP flag_buffer; /* flag buffer flip-flop */
139 } CARD_STATE;
140
141 static CARD_STATE mtd; /* data per-card state */
142 static CARD_STATE mtc; /* command per-card state */
143
144
145 /* Interface local SCP support routines */
146
147 static IO_INTERFACE mtd_interface;
148 static IO_INTERFACE mtc_interface;
149
150
151 static int32 mtc_fnc = 0; /* function */
152 static int32 mtc_sta = 0; /* status register */
153 static int32 mtc_dtf = 0; /* data xfer flop */
154 static int32 mtc_1st = 0; /* first svc flop */
155 static int32 mtc_ctime = 40; /* command wait */
156 static int32 mtc_gtime = 1000; /* gap stop time */
157 static int32 mtc_xtime = 15; /* data xfer time */
158 static uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
159 static t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
160 static const uint32 mtc_cmd[] = {
161 FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };
162 static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]);
163
164 static t_stat mtc_svc (UNIT *uptr);
165 static t_stat mt_reset (DEVICE *dptr);
166 static t_stat mtc_attach (UNIT *uptr, char *cptr);
167 static t_stat mtc_detach (UNIT *uptr);
168 static t_stat mt_map_err (UNIT *uptr, t_stat st);
169 static t_stat mt_clear (void);
170
171 /* Device information blocks */
172
173 static DIB mt_dib [] = {
174 { &mtd_interface, /* the device's I/O interface function pointer */
175 NULL, /* the power state function pointer */
176 MTD, /* the device's select code (02-77) */
177 0, /* the card index */
178 "12559C 9-Track Magnetic Tape Unit Interface Data Channel", /* the card description */
179 NULL }, /* the ROM description */
180
181 { &mtc_interface, /* the device's I/O interface function pointer */
182 NULL, /* the power state function pointer */
183 MTC, /* the device's select code (02-77) */
184 0, /* the card index */
185 "12559C 9-Track Magnetic Tape Unit Interface Command Channel", /* the card description */
186 NULL } /* the ROM description */
187 };
188
189 #define mtd_dib mt_dib [0]
190 #define mtc_dib mt_dib [1]
191
192
193 /* Data card SCP data structures */
194
195
196 /* Unit list */
197
198 static UNIT mtd_unit [] = {
199 /* Event Routine Unit Flags Capacity Delay */
200 /* ------------- ---------- -------- ----- */
201 { UDATA (NULL, 0, 0) }
202 };
203
204
205 /* Register list */
206
207 static REG mtd_reg [] = {
208 { FLDATA (FLG, mtd.flag, 0) },
209 { FLDATA (FBF, mtd.flag_buffer, 0) },
210 { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
211 { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
212 { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
213
214 DIB_REGS (mtd_dib),
215
216 { NULL }
217 };
218
219
220 /* Modifier list */
221
222 static MTAB mtd_mod [] = {
223 /* Entry Flags Value Print String Match String Validation Display Descriptor */
224 /* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
225 { MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
226 { MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
227 { 0 }
228 };
229
230
231 /* Debugging trace list */
232
233 static DEBTAB mt_deb [] = {
234 { "IOBUS", TRACE_IOBUS }, /* trace I/O bus signals and data words received and returned */
235 { NULL, 0 }
236 };
237
238
239 /* Device descriptor */
240
241 DEVICE mtd_dev = {
242 "MTD", /* device name */
243 mtd_unit, /* unit array */
244 mtd_reg, /* register array */
245 mtd_mod, /* modifier array */
246 1, /* number of units */
247 10, /* address radix */
248 16, /* address width */
249 1, /* address increment */
250 8, /* data radix */
251 8, /* data width */
252 NULL, /* examine routine */
253 NULL, /* deposit routine */
254 &mt_reset, /* reset routine */
255 NULL, /* boot routine */
256 NULL, /* attach routine */
257 NULL, /* detach routine */
258 &mtd_dib, /* device information block pointer */
259 DEV_DISABLE | DEV_DIS | DEV_DEBUG, /* device flags */
260 0, /* debug control flags */
261 mt_deb, /* debug flag name array */
262 NULL, /* memory size change routine */
263 NULL /* logical device name */
264 };
265
266
267 /* Command card SCP data structures */
268
269
270 /* Unit list */
271
272 #define UNIT_FLAGS (UNIT_ATTABLE | UNIT_ROABLE)
273
274 static UNIT mtc_unit [] = {
275 /* Event Routine Unit Flags Capacity Delay */
276 /* ------------- ---------- -------- ----- */
277 { UDATA (&mtc_svc, UNIT_FLAGS, 0) },
278 };
279
280
281 /* Register list */
282
283 static REG mtc_reg [] = {
284 { ORDATA (FNC, mtc_fnc, 8) },
285 { ORDATA (STA, mtc_sta, 9) },
286 { ORDATA (BUF, mtc_unit [0].buf, 8) },
287 { FLDATA (CTL, mtc.control, 0) },
288 { FLDATA (FLG, mtc.flag, 0) },
289 { FLDATA (FBF, mtc.flag_buffer, 0) },
290 { FLDATA (DTF, mtc_dtf, 0) },
291 { FLDATA (FSVC, mtc_1st, 0) },
292 { DRDATA (POS, mtc_unit [0].pos, T_ADDR_W), PV_LEFT },
293 { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT },
294 { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT },
295 { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT },
296
297 DIB_REGS (mtc_dib),
298
299 { NULL }
300 };
301
302
303 /* Modifier list.
304
305 The LOCKED and WRITEENABLED modifiers are deprecated. The supported method
306 of write-protecting a tape drive is to attach the tape image with the -R
307 (read-only) switch or by setting the host operating system's read-only
308 attribute on the tape image file. This simulates removing the write ring
309 from the tape reel before mounting it on the drive. There is no hardware
310 method of write-protecting a mounted and positioned tape reel.
311
312
313 Implementation notes:
314
315 1. The UNIT_RO modifier displays "write ring" if the flag is not set. There
316 is no corresponding entry for the opposite condition because "read only"
317 is automatically printed after the attached filename.
318
319 2. FORMAT is really a unit option, but as there is only one unit, it is
320 specified as MTAB_XDV so that SHOW MTC FORMAT is accepted, rather than
321 requiring SHOW MTC0 FORMAT.
322 */
323
324 static MTAB mtc_mod [] = {
325 /* Mask Value Match Value Print String Match String Validation Display Descriptor */
326 /* ------------- ------------- ---------------- --------------- ------------ ------- ---------- */
327 { UNIT_RO, 0, "write ring", NULL, NULL, NULL, NULL },
328
329 { MTUF_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
330 { MTUF_WLK, MTUF_WLK, NULL, "LOCKED", NULL, NULL, NULL },
331
332
333 /* Entry Flags Value Print String Match String Validation Display Descriptor */
334 /* ------------------- ----- ------------ ------------ ----------------- ------------------ ---------------- */
335 { MTAB_XDV, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
336
337 { MTAB_XDV, 2u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
338 { MTAB_XDV | MTAB_NMO, ~2u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &mt_dib },
339 { 0 }
340 };
341
342
343 /* Device descriptor */
344
345 DEVICE mtc_dev = {
346 "MTC", /* device name */
347 mtc_unit, /* unit array */
348 mtc_reg, /* register array */
349 mtc_mod, /* modifier array */
350 1, /* number of units */
351 10, /* address radix */
352 31, /* address width */
353 1, /* address increment */
354 8, /* data radix */
355 8, /* data width */
356 NULL, /* examine routine */
357 NULL, /* deposit routine */
358 &mt_reset, /* reset routine */
359 NULL, /* boot routine */
360 &mtc_attach, /* attach routine */
361 &mtc_detach, /* detach routine */
362 &mtc_dib, /* device information block pointer */
363 DEV_DISABLE | DEV_DIS | DEV_DEBUG, /* device flags */
364 0, /* debug control flags */
365 mt_deb, /* debug flag name array */
366 NULL, /* memory size change routine */
367 NULL /* logical device name */
368 };
369
370
371
372 /* Data channel interface.
373
374 The 12559A data channel interface has a number of non-standard features:
375
376 - The card does not drive PRL or IRQ.
377 - The card does not respond to IAK.
378 - There is no control flip-flop; CLC resets the data transfer flip-flop.
379 - POPIO issues a CLR command and clears the flag and flag buffer flip-flops.
380 - CRS is not used.
381
382 Implementation notes:
383
384 1. The data channel has a flag buffer flip-flop (necessary for the proper
385 timing of the flag flip-flop), but the data channel does not interrupt,
386 so the flag buffer serves no other purpose.
387 */
388
mtd_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)389 static SIGNALS_VALUE mtd_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
390 {
391 INBOUND_SIGNAL signal;
392 INBOUND_SET working_set = inbound_signals;
393 SIGNALS_VALUE outbound = { ioNONE, 0 };
394
395 while (working_set) { /* while signals remain */
396 signal = IONEXTSIG (working_set); /* isolate the next signal */
397
398 switch (signal) { /* dispatch the I/O signal */
399
400 case ioCLF: /* Clear Flag flip-flop */
401 mtd.flag_buffer = CLEAR; /* reset the flag buffer */
402 mtd.flag = CLEAR; /* and flag flip-flops */
403 break;
404
405
406 case ioSTF: /* Set Flag flip-flop */
407 mtd.flag_buffer = SET; /* set the flag buffer flip-flop */
408 break;
409
410
411 case ioENF: /* Enable Flag */
412 if (mtd.flag_buffer == SET) /* if the flag buffer flip-flop is set */
413 mtd.flag = SET; /* then set the flag flip-flop */
414 break;
415
416
417 case ioSFC: /* Skip if Flag is Clear */
418 if (mtd.flag == CLEAR) /* if the flag flip-flop is clear */
419 outbound.signals |= ioSKF; /* then assert the Skip on Flag signal */
420 break;
421
422
423 case ioSFS: /* Skip if Flag is Set */
424 if (mtd.flag == SET) /* if the flag flip-flop is set */
425 outbound.signals |= ioSKF; /* then assert the Skip on Flag signal */
426 break;
427
428
429 case ioIOI: /* I/O data input */
430 outbound.value = mtc_unit [0].buf; /* merge in return status */
431 break;
432
433
434 case ioIOO: /* I/O data output */
435 mtc_unit [0].buf = inbound_value & D8_MASK; /* store data */
436 break;
437
438
439 case ioPOPIO: /* Power-On Preset to I/O */
440 mt_clear (); /* issue CLR to controller */
441 mtd.flag_buffer = CLEAR; /* clear the flag buffer flip-flop */
442 break;
443
444
445 case ioCLC: /* Clear Control flip-flop */
446 mtd.flag_buffer = CLEAR; /* reset the flag buffer */
447 mtd.flag = CLEAR; /* and flag flip-flops */
448
449 mtc_dtf = 0; /* clr xfer flop */
450 break;
451
452
453 case ioSIR: /* Set Interrupt Request */
454 if (mtd.flag == SET) /* if the flag flip-flop is set */
455 outbound.signals |= ioSRQ; /* then assert SRQ */
456 break;
457
458
459 case ioPRH: /* Priority High */
460 outbound.signals |= ioPRL | cnPRL | cnVALID; /* PRL is tied to PRH */
461 break;
462
463
464 case ioSTC: /* not used by this interface */
465 case ioCRS: /* not used by this interface */
466 case ioIAK: /* not used by this interface */
467 case ioIEN: /* not used by this interface */
468 case ioEDT: /* not used by this interface */
469 case ioPON: /* not used by this interface */
470 break;
471 }
472
473 IOCLEARSIG (working_set, signal); /* remove the current signal from the set */
474 } /* and continue until all signals are processed */
475
476 return outbound; /* return the outbound signals and value */
477 }
478
479
480 /* Command channel interface.
481
482 The 12559A command interface is reasonably standard, although POPIO clears,
483 rather than sets, the flag and flag buffer flip-flops. One unusual feature
484 is that commands are initiated when they are output to the interface with
485 OTA/B, rather than waiting until control is set with STC. STC simply enables
486 command-channel interrupts.
487
488 Implementation notes:
489
490 1. In hardware, the command channel card passes PRH to PRL. The data card
491 actually drives PRL with the command channel's control and flag states.
492 That is, the priority chain is broken at the data card, although the
493 command card is interrupting. This works in hardware, but we must break
494 PRL at the command card under simulation to allow the command card to
495 interrupt.
496
497 2. In hardware, the CLR command takes 5 milliseconds to complete. During
498 this time, the BUSY bit is set in the status word. Under simulation, we
499 complete immediately, and the BUSY bit never sets..
500 */
501
mtc_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)502 static SIGNALS_VALUE mtc_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
503 {
504 uint32 i, data;
505 int32 valid;
506 INBOUND_SIGNAL signal;
507 INBOUND_SET working_set = inbound_signals;
508 SIGNALS_VALUE outbound = { ioNONE, 0 };
509 t_bool irq_enabled = FALSE;
510
511 while (working_set) { /* while signals remain */
512 signal = IONEXTSIG (working_set); /* isolate the next signal */
513
514 switch (signal) { /* dispatch the I/O signal */
515
516 case ioCLF: /* Clear Flag flip-flop */
517 mtc.flag_buffer = CLEAR; /* reset the flag buffer */
518 mtc.flag = CLEAR; /* and flag flip-flops */
519 break;
520
521
522 case ioSTF: /* Set Flag flip-flop */
523 mtc.flag_buffer = SET; /* set the flag buffer flip-flop */
524 break;
525
526
527 case ioENF: /* Enable Flag */
528 if (mtc.flag_buffer == SET) /* if the flag buffer flip-flop is set */
529 mtc.flag = SET; /* then set the flag flip-flop */
530 break;
531
532
533 case ioSFC: /* Skip if Flag is Clear */
534 if (mtc.flag == CLEAR) /* if the flag flip-flop is clear */
535 outbound.signals |= ioSKF; /* then assert the Skip on Flag signal */
536 break;
537
538
539 case ioSFS: /* Skip if Flag is Set */
540 if (mtc.flag == SET) /* if the flag flip-flop is set */
541 outbound.signals |= ioSKF; /* then assert the Skip on Flag signal */
542 break;
543
544
545 case ioIOI: /* I/O data input */
546 outbound.value = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY);
547
548 if (mtc_unit [0].flags & UNIT_ATT) { /* construct status */
549 if (sim_is_active (mtc_unit))
550 outbound.value |= STA_BUSY;
551
552 if (sim_tape_wrp (mtc_unit))
553 outbound.value |= STA_WLK;
554 }
555
556 else
557 outbound.value |= STA_BUSY | STA_LOCAL;
558 break;
559
560
561 case ioIOO: /* I/O data output */
562 data = inbound_value & D8_MASK; /* only the lower 8 bits are connected */
563 mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */
564
565 if (data == FNC_CLR) { /* clear? */
566 mt_clear (); /* send CLR to controller */
567
568 mtd.flag_buffer = mtd.flag = CLEAR; /* clear data flag buffer and flag */
569 mtc.flag_buffer = mtc.flag = SET; /* set command flag buffer and flag */
570 break; /* command completes immediately */
571 }
572
573 for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */
574 if (data == mtc_cmd[i]) {
575 valid = 1;
576 break;
577 }
578
579 if (not valid || sim_is_active (mtc_unit) || /* is cmd valid? */
580 ((mtc_sta & STA_BOT) && (data == FNC_BSR)) ||
581 (sim_tape_wrp (mtc_unit) &&
582 ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM))))
583 mtc_sta = mtc_sta | STA_REJ;
584
585 else {
586 sim_activate (mtc_unit, mtc_ctime); /* start tape */
587 mtc_fnc = data; /* save function */
588 mtc_sta = STA_BUSY; /* unit busy */
589 mt_ptr = 0; /* init buffer ptr */
590
591 mtd.flag_buffer = mtd.flag = CLEAR; /* clear data flag buffer and flag */
592 mtc.flag_buffer = mtc.flag = CLEAR; /* and command flag buffer and flag */
593
594 mtc_1st = 1; /* set 1st flop */
595 mtc_dtf = 1; /* set xfer flop */
596 }
597 break;
598
599
600 case ioPOPIO: /* Power-On Preset to I/O */
601 mtc.flag_buffer = CLEAR; /* clear the flag buffer flip-flop */
602 mtc.flag = CLEAR; /* and flag flip-flops */
603 break;
604
605
606 case ioCRS: /* Control Reset */
607 mtc.control = CLEAR; /* clear the control flip-flop */
608 break;
609
610
611 case ioCLC: /* Clear Control flip-flop */
612 mtc.control = CLEAR;
613 break;
614
615
616 case ioSTC: /* Set Control flip-flop */
617 mtc.control = SET;
618 break;
619
620
621 case ioSIR: /* Set Interrupt Request */
622 if (mtc.control & mtc.flag) /* if the control and flag flip-flops are set */
623 outbound.signals |= cnVALID; /* then deny PRL */
624 else /* otherwise */
625 outbound.signals |= cnPRL | cnVALID; /* conditionally assert PRL */
626
627 if (mtc.control & mtc.flag & mtc.flag_buffer) /* if the control, flag, and flag buffer flip-flops are set */
628 outbound.signals |= cnIRQ; /* then conditionally assert IRQ */
629
630 if (mtc.flag == SET) /* if the flag flip-flop is set */
631 outbound.signals |= ioSRQ; /* then assert SRQ */
632 break;
633
634
635 case ioIAK: /* Interrupt Acknowledge */
636 mtc.flag_buffer = CLEAR; /* clear the flag buffer flip-flop */
637 break;
638
639
640 case ioIEN: /* Interrupt Enable */
641 irq_enabled = TRUE; /* permit IRQ to be asserted */
642 break;
643
644
645 case ioPRH: /* Priority High */
646 if (irq_enabled && outbound.signals & cnIRQ) /* if IRQ is enabled and conditionally asserted */
647 outbound.signals |= ioIRQ | ioFLG; /* then assert IRQ and FLG */
648
649 if (not irq_enabled || outbound.signals & cnPRL) /* if IRQ is disabled or PRL is conditionally asserted */
650 outbound.signals |= ioPRL; /* then assert it unconditionally */
651 break;
652
653
654 case ioEDT: /* not used by this interface */
655 case ioPON: /* not used by this interface */
656 break;
657 }
658
659 IOCLEARSIG (working_set, signal); /* remove the current signal from the set */
660 } /* and continue until all signals are processed */
661
662 return outbound; /* return the outbound signals and value */
663 }
664
665
666 /* Unit service
667
668 If rewind done, reposition to start of tape, set status
669 else, do operation, set done, interrupt
670
671 Can't be write locked, can only write lock detached unit
672 */
673
mtc_svc(UNIT * uptr)674 static t_stat mtc_svc (UNIT *uptr)
675 {
676 t_mtrlnt tbc;
677 t_stat st, r = SCPE_OK;
678
679 if (not (mtc_unit [0].flags & UNIT_ATT)) { /* offline? */
680 mtc_sta = STA_LOCAL | STA_REJ; /* rejected */
681
682 mtc.flag_buffer = SET; /* set the flag buffer */
683 io_assert_ENF (&mtc_dib); /* and flag flip-flops */
684
685 return SCPE_OK;
686 }
687
688 switch (mtc_fnc) { /* case on function */
689
690 case FNC_REW: /* rewind */
691 sim_tape_rewind (uptr); /* BOT */
692 mtc_sta = STA_BOT; /* update status */
693 break;
694
695 case FNC_RWS: /* rewind and offline */
696 sim_tape_rewind (uptr); /* clear position */
697 return sim_tape_detach (uptr); /* don't set cch flg */
698
699 case FNC_WFM: /* write file mark */
700 st = sim_tape_wrtmk (uptr); /* write tmk */
701 if (st != MTSE_OK) /* error? */
702 r = mt_map_err (uptr, st); /* map error */
703 mtc_sta = STA_EOF; /* set EOF status */
704 break;
705
706 case FNC_GAP: /* erase gap */
707 break;
708
709 case FNC_FSR: /* space forward */
710 st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */
711 if (st != MTSE_OK) /* error? */
712 r = mt_map_err (uptr, st); /* map error */
713 break;
714
715 case FNC_BSR: /* space reverse */
716 st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */
717 if (st != MTSE_OK) /* error? */
718 r = mt_map_err (uptr, st); /* map error */
719 break;
720
721 case FNC_RC: /* read */
722 if (mtc_1st) { /* first svc? */
723 mtc_1st = mt_ptr = 0; /* clr 1st flop */
724 st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */
725 if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */
726 else if (st != MTSE_OK) { /* other error? */
727 r = mt_map_err (uptr, st); /* map error */
728 if (r == SCPE_OK) { /* recoverable? */
729 sim_activate (uptr, mtc_gtime); /* sched IRG */
730 mtc_fnc = 0; /* NOP func */
731 return SCPE_OK;
732 }
733 break; /* non-recov, done */
734 }
735 if (mt_max < 12) { /* record too short? */
736 mtc_sta = mtc_sta | STA_PAR; /* set flag */
737 break;
738 }
739 }
740 if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */
741 if (mtd.flag) mtc_sta = mtc_sta | STA_TIM;
742 mtc_unit [0].buf = mtxb [mt_ptr++]; /* fetch next */
743
744 mtd.flag_buffer = SET; /* set the flag buffer */
745 io_assert_ENF (&mtd_dib); /* and flag flip-flops */
746
747 sim_activate (uptr, mtc_xtime); /* re-activate */
748 return SCPE_OK;
749 }
750 sim_activate (uptr, mtc_gtime); /* schedule gap */
751 mtc_fnc = 0; /* nop */
752 return SCPE_OK;
753
754 case FNC_WC: /* write */
755 if (mtc_1st) mtc_1st = 0; /* no xfr on first */
756 else {
757 if (mt_ptr < DBSIZE) { /* room in buffer? */
758 mtxb[mt_ptr++] = (uint8) mtc_unit [0].buf;
759 mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */
760 }
761 else mtc_sta = mtc_sta | STA_PAR;
762 }
763 if (mtc_dtf) { /* xfer flop set? */
764 mtd.flag_buffer = SET; /* set the flag buffer */
765 io_assert_ENF (&mtd_dib); /* and flag flip-flops */
766
767 sim_activate (uptr, mtc_xtime); /* re-activate */
768 return SCPE_OK;
769 }
770 if (mt_ptr) { /* write buffer */
771 st = sim_tape_wrrecf (uptr, mtxb, mt_ptr); /* write */
772 if (st != MTSE_OK) { /* error? */
773 r = mt_map_err (uptr, st); /* map error */
774 break; /* done */
775 }
776 }
777 sim_activate (uptr, mtc_gtime); /* schedule gap */
778 mtc_fnc = 0; /* nop */
779 return SCPE_OK;
780
781 default: /* unknown */
782 break;
783 }
784
785 mtc.flag_buffer = SET; /* set the flag buffer */
786 io_assert_ENF (&mtc_dib); /* and flag flip-flops */
787 mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */
788 return r;
789 }
790
791 /* Map tape error status */
792
mt_map_err(UNIT * uptr,t_stat st)793 static t_stat mt_map_err (UNIT *uptr, t_stat st)
794 {
795 switch (st) {
796
797 case MTSE_FMT: /* illegal fmt */
798 case MTSE_UNATT: /* unattached */
799 mtc_sta = mtc_sta | STA_REJ; /* reject */
800 return SCPE_IERR; /* never get here! */
801
802 case MTSE_OK: /* no error */
803 return SCPE_IERR; /* never get here! */
804
805 case MTSE_EOM: /* end of medium */
806 case MTSE_TMK: /* end of file */
807 mtc_sta = mtc_sta | STA_EOF; /* eof */
808 break;
809
810 case MTSE_IOERR: /* IO error */
811 mtc_sta = mtc_sta | STA_PAR; /* error */
812 return SCPE_IOERR;
813 break;
814
815 case MTSE_INVRL: /* invalid rec lnt */
816 mtc_sta = mtc_sta | STA_PAR;
817 return SCPE_MTRLNT;
818
819 case MTSE_RECE: /* record in error */
820 mtc_sta = mtc_sta | STA_PAR; /* error */
821 break;
822
823 case MTSE_BOT: /* reverse into BOT */
824 mtc_sta = mtc_sta | STA_BOT; /* set status */
825 break;
826
827 case MTSE_WRP: /* write protect */
828 mtc_sta = mtc_sta | STA_REJ; /* reject */
829 break;
830 }
831
832 return SCPE_OK;
833 }
834
835
836 /* Controller clear */
837
mt_clear(void)838 static t_stat mt_clear (void)
839 {
840 t_stat st;
841
842 if (sim_is_active (mtc_unit) && /* write in prog? */
843 (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */
844 st = sim_tape_wrrecf (mtc_unit, mtxb, mt_ptr | MTR_ERF);
845 if (st != MTSE_OK)
846 mt_map_err (mtc_unit, st);
847 }
848
849 if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && sim_is_active (mtc_unit))
850 sim_cancel (mtc_unit);
851
852 mtc_1st = mtc_dtf = 0;
853 mtc_sta = mtc_sta & STA_BOT;
854
855 return SCPE_OK;
856 }
857
858
859 /* Reset routine */
860
mt_reset(DEVICE * dptr)861 static t_stat mt_reset (DEVICE *dptr)
862 {
863 hp_enbdis_pair (dptr, /* make pair cons */
864 (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev);
865
866 mtc_fnc = 0;
867 mtc_1st = mtc_dtf = 0;
868
869 sim_cancel (mtc_unit); /* cancel activity */
870 sim_tape_reset (mtc_unit);
871
872 if (mtc_unit [0].flags & UNIT_ATT)
873 mtc_sta = (sim_tape_bot (mtc_unit)? STA_BOT: 0) |
874 (sim_tape_wrp (mtc_unit)? STA_WLK: 0);
875 else
876 mtc_sta = STA_LOCAL | STA_BUSY;
877
878 return SCPE_OK;
879 }
880
881
882 /* Attach routine */
883
mtc_attach(UNIT * uptr,char * cptr)884 static t_stat mtc_attach (UNIT *uptr, char *cptr)
885 {
886 t_stat r;
887
888 r = sim_tape_attach (uptr, cptr); /* attach unit */
889 if (r != SCPE_OK) return r; /* update status */
890 mtc_sta = STA_BOT;
891 return r;
892 }
893
894 /* Detach routine */
895
mtc_detach(UNIT * uptr)896 static t_stat mtc_detach (UNIT* uptr)
897 {
898 mtc_sta = 0; /* update status */
899 return sim_tape_detach (uptr); /* detach unit */
900 }
901