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