1 /* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator
3 Copyright (c) 1993-2006, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 ms 13181A 7970B 800bpi nine track magnetic tape
27 13183A 7970E 1600bpi nine track magnetic tape
29 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
30 18-Sep-06 JDB Fixed 2nd CLR after WC causing another write
31 Improve debug reporting, add debug flags
32 14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot
33 30-Aug-06 JDB Added erase gap support, improved tape lib err reporting
34 07-Jul-06 JDB Added CAPACITY as alternate for REEL
35 Fixed EOT test for unlimited reel size
36 16-Feb-06 RMS Revised for new EOT test
37 22-Jul-05 RMS Fixed compiler warning on Solaris (from Doug Glyn)
38 01-Mar-05 JDB Added SET OFFLINE; rewind/offline now does not detach
39 07-Oct-04 JDB Fixed enable/disable from either device
40 14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan)
41 - fixed erroneous execution of rejected command
42 - fixed erroneous execution of select-only command
43 - fixed erroneous execution of clear command
44 - fixed odd byte handling for read
45 - fixed spurious odd byte status on 13183A EOF
46 - modified handling of end of medium
47 - added detailed timing, with fast and realistic modes
48 - added reel sizes to simulate end of tape
49 - added debug printouts
50 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)
51 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
52 Fixed SR setting in IBL
54 Implemented DMA SRQ (follows FLG)
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 18-Oct-02 RMS Added BOOT command, added 13183A support
59 30-Sep-02 RMS Revamped error handling
60 29-Aug-02 RMS Added end of medium support
61 30-May-02 RMS Widened POS to 32b
62 22-Apr-02 RMS Added maximum record length test
64 Magnetic tapes are represented as a series of variable records
75 If the byte count is odd, the record is padded with an extra byte
76 of junk. File marks are represented by a byte count of 0.
79 - 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
80 (13181-90901, Nov-1982)
81 - 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
82 (13183-90901, Nov-1983)
85 #include "hp2100_defs.h"
88 #define UNIT_V_OFFLINE (MTUF_V_UF + 0) /* unit offline */
89 #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
91 #define MS_NUMDR 4 /* number of drives */
92 #define DB_N_SIZE 16 /* max data buf */
93 #define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
94 #define FNC u3 /* function */
95 #define UST u4 /* unit status */
96 #define REEL u5 /* tape reel size */
98 #define BPI_13181 800 /* 800 bpi for 13181 cntlr */
99 #define BPI_13183 1600 /* 1600 bpi for 13183 cntlr */
100 #define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */
101 #define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */
102 #define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */
106 #define DEB_CMDS (1 << 0) /* command init and compl */
107 #define DEB_CPU (1 << 1) /* CPU I/O */
108 #define DEB_RWS (1 << 2) /* tape reads, writes, status */
110 /* Command - msc_fnc */
112 #define FNC_CLR 00110 /* clear */
113 #define FNC_GAP 00015 /* write gap */
114 #define FNC_GFM 00215 /* gap+file mark */
115 #define FNC_RC 00023 /* read */
116 #define FNC_WC 00031 /* write */
117 #define FNC_FSR 00003 /* forward space */
118 #define FNC_BSR 00041 /* backward space */
119 #define FNC_FSF 00203 /* forward file */
120 #define FNC_BSF 00241 /* backward file */
121 #define FNC_REW 00101 /* rewind */
122 #define FNC_RWS 00105 /* rewind and offline */
123 #define FNC_WFM 00211 /* write file mark */
124 #define FNC_RFF 00223 /* read file fwd (diag) */
125 #define FNC_RRR 00061 /* read record rev (diag) */
126 #define FNC_CMPL 00400 /* completion state */
127 #define FNC_V_SEL 9 /* select */
128 #define FNC_M_SEL 017
129 #define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL)
131 #define FNF_MOT 00001 /* motion */
132 #define FNF_OFL 00004
133 #define FNF_WRT 00010 /* write */
134 #define FNF_REV 00040 /* reverse */
135 #define FNF_RWD 00100 /* rewind */
136 #define FNF_CHS 00400 /* change select */
138 #define FNC_SEL ((FNC_M_SEL << FNC_V_SEL) | FNF_CHS)
140 /* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */
142 #define STA_PE 0100000 /* 1600 bpi (d) */
143 #define STA_V_SEL 13 /* unit sel (d) */
145 #define STA_SEL (STA_M_SEL << STA_V_SEL)
146 #define STA_ODD 0004000 /* odd bytes */
147 #define STA_REW 0002000 /* rewinding (u) */
148 #define STA_TBSY 0001000 /* transport busy (d) */
149 #define STA_BUSY 0000400 /* ctrl busy */
150 #define STA_EOF 0000200 /* end of file */
151 #define STA_BOT 0000100 /* beg of tape (d) */
152 #define STA_EOT 0000040 /* end of tape (d) */
153 #define STA_TIM 0000020 /* timing error */
154 #define STA_REJ 0000010 /* programming error */
155 #define STA_WLK 0000004 /* write locked (d) */
156 #define STA_PAR 0000002 /* parity error */
157 #define STA_LOCAL 0000001 /* local (d) */
158 #define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \
159 STA_EOT | STA_WLK | STA_LOCAL)
161 extern uint32 PC
, SR
;
162 extern uint32 dev_cmd
[2], dev_ctl
[2], dev_flg
[2], dev_fbf
[2], dev_srq
[2];
163 extern int32 sim_switches
;
164 extern FILE *sim_deb
;
166 int32 ms_ctype
= 0; /* ctrl type */
167 int32 ms_timing
= 1; /* timing type */
168 int32 msc_sta
= 0; /* status */
169 int32 msc_buf
= 0; /* buffer */
170 int32 msc_usl
= 0; /* unit select */
171 int32 msc_1st
= 0; /* first service */
172 int32 msc_stopioe
= 1; /* stop on error */
173 int32 msd_buf
= 0; /* data buffer */
174 uint8 msxb
[DBSIZE
] = { 0 }; /* data buffer */
175 t_mtrlnt ms_ptr
= 0, ms_max
= 0; /* buffer ptrs */
177 /* Hardware timing at 45 IPS 13181 13183
178 (based on 1580 instr/msec) instr msec SCP instr msec SCP
179 -------------------- --------------------
180 - BOT start delay : btime = 161512 102.22 184 252800 160.00 288
181 - motion cmd start delay : ctime = 14044 8.89 16 17556 11.11 20
182 - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120
183 - IRG traversal time : itime = 24885 15.75 - 27387 17.33 -
184 - rewind initiation time : rtime = 878 0.56 1 878 0.56 1
185 - data xfer time / word : xtime = 88 55.56us - 44 27.78us -
187 NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with
188 "E116 BYTE TIME SHORT" if the correct data transfer time is used for
189 13181A interface. Set "xtime" to 115 (instructions) to pass that
190 diagnostic. Rev. 2040 of the tape diagnostic fixes this problem and
191 passes with the correct data transfer time.
194 int32 msc_btime
= 0; /* BOT start delay */
195 int32 msc_ctime
= 0; /* motion cmd start delay */
196 int32 msc_gtime
= 0; /* GAP traversal time */
197 int32 msc_itime
= 0; /* IRG traversal time */
198 int32 msc_rtime
= 0; /* rewind initiation time */
199 int32 msc_xtime
= 0; /* data xfer time / word */
201 typedef int32 TIMESET
[6]; /* set of controller times */
203 int32
*const timers
[] = { &msc_btime
, &msc_ctime
, &msc_gtime
,
204 &msc_itime
, &msc_rtime
, &msc_xtime
};
206 const TIMESET msc_times
[3] = {
207 { 161512, 14044, 175553, 24885, 878, 88 }, /* 13181A */
208 { 252800, 17556, 105333, 27387, 878, 44 }, /* 13183A */
209 { 1, 1000, 1, 1, 100, 10 } /* FAST */
212 DEVICE msd_dev
, msc_dev
;
213 int32
msdio (int32 inst
, int32 IR
, int32 dat
);
214 int32
mscio (int32 inst
, int32 IR
, int32 dat
);
215 t_stat
msc_svc (UNIT
*uptr
);
216 t_stat
msc_reset (DEVICE
*dptr
);
217 t_stat
msc_attach (UNIT
*uptr
, char *cptr
);
218 t_stat
msc_detach (UNIT
*uptr
);
219 t_stat
msc_online (UNIT
*uptr
, int32 value
, char *cptr
, void *desc
);
220 t_stat
msc_boot (int32 unitno
, DEVICE
*dptr
);
221 t_stat
ms_write_gap (UNIT
*uptr
);
222 t_stat
ms_map_err (UNIT
*uptr
, t_stat st
);
223 t_stat
ms_settype (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
224 t_stat
ms_showtype (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
225 t_stat
ms_set_timing (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
226 t_stat
ms_show_timing (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
227 t_stat
ms_set_reelsize (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
228 t_stat
ms_show_reelsize (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
229 void ms_config_timing (void);
230 char *ms_cmd_name (uint32 cmd
);
232 /* MSD data structures
234 msd_dev MSD device descriptor
235 msd_unit MSD unit list
236 msd_reg MSD register list
240 { MSD
, 0, 0, 0, 0, 0, &msdio
},
241 { MSC
, 0, 0, 0, 0, 0, &mscio
}
244 #define msd_dib ms_dib[0]
245 #define msc_dib ms_dib[1]
247 UNIT msd_unit
= { UDATA (NULL
, 0, 0) };
250 { ORDATA (BUF
, msd_buf
, 16) },
251 { FLDATA (CMD
, msd_dib
.cmd
, 0), REG_HRO
},
252 { FLDATA (CTL
, msd_dib
.ctl
, 0) },
253 { FLDATA (FLG
, msd_dib
.flg
, 0) },
254 { FLDATA (FBF
, msd_dib
.fbf
, 0) },
255 { FLDATA (SRQ
, msd_dib
.srq
, 0) },
256 { BRDATA (DBUF
, msxb
, 8, 8, DBSIZE
) },
257 { DRDATA (BPTR
, ms_ptr
, DB_N_SIZE
+ 1) },
258 { DRDATA (BMAX
, ms_max
, DB_N_SIZE
+ 1) },
259 { ORDATA (DEVNO
, msd_dib
.devno
, 6), REG_HRO
},
264 { MTAB_XTD
| MTAB_VDV
, 1, "DEVNO", "DEVNO",
265 &hp_setdev
, &hp_showdev
, &msd_dev
},
270 "MSD", &msd_unit
, msd_reg
, msd_mod
,
271 1, 10, DB_N_SIZE
, 1, 8, 8,
272 NULL
, NULL
, &msc_reset
,
274 &msd_dib
, DEV_DISABLE
277 /* MSC data structures
279 msc_dev MSC device descriptor
280 msc_unit MSC unit list
281 msc_reg MSC register list
282 msc_mod MSC modifier list
283 msc_deb MSC debug flags
287 { UDATA (&msc_svc
, UNIT_ATTABLE
| UNIT_ROABLE
|
288 UNIT_DISABLE
| UNIT_OFFLINE
, 0) },
289 { UDATA (&msc_svc
, UNIT_ATTABLE
| UNIT_ROABLE
|
290 UNIT_DISABLE
| UNIT_OFFLINE
, 0) },
291 { UDATA (&msc_svc
, UNIT_ATTABLE
| UNIT_ROABLE
|
292 UNIT_DISABLE
| UNIT_OFFLINE
, 0) },
293 { UDATA (&msc_svc
, UNIT_ATTABLE
| UNIT_ROABLE
|
294 UNIT_DISABLE
| UNIT_OFFLINE
, 0) }
298 { ORDATA (STA
, msc_sta
, 12) },
299 { ORDATA (BUF
, msc_buf
, 16) },
300 { ORDATA (USEL
, msc_usl
, 2) },
301 { FLDATA (FSVC
, msc_1st
, 0) },
302 { FLDATA (CMD
, msc_dib
.cmd
, 0), REG_HRO
},
303 { FLDATA (CTL
, msc_dib
.ctl
, 0) },
304 { FLDATA (FLG
, msc_dib
.flg
, 0) },
305 { FLDATA (FBF
, msc_dib
.fbf
, 0) },
306 { FLDATA (SRQ
, msc_dib
.srq
, 0) },
307 { URDATA (POS
, msc_unit
[0].pos
, 10, T_ADDR_W
, 0, MS_NUMDR
, PV_LEFT
) },
308 { URDATA (FNC
, msc_unit
[0].FNC
, 8, 8, 0, MS_NUMDR
, REG_HRO
) },
309 { URDATA (UST
, msc_unit
[0].UST
, 8, 12, 0, MS_NUMDR
, REG_HRO
) },
310 { URDATA (REEL
, msc_unit
[0].REEL
, 10, 2, 0, MS_NUMDR
, REG_HRO
) },
311 { DRDATA (BTIME
, msc_btime
, 24), REG_NZ
+ PV_LEFT
},
312 { DRDATA (CTIME
, msc_ctime
, 24), REG_NZ
+ PV_LEFT
},
313 { DRDATA (GTIME
, msc_gtime
, 24), REG_NZ
+ PV_LEFT
},
314 { DRDATA (ITIME
, msc_itime
, 24), REG_NZ
+ PV_LEFT
},
315 { DRDATA (RTIME
, msc_rtime
, 24), REG_NZ
+ PV_LEFT
},
316 { DRDATA (XTIME
, msc_xtime
, 24), REG_NZ
+ PV_LEFT
},
317 { FLDATA (TIMING
, ms_timing
, 0), REG_HRO
},
318 { FLDATA (STOP_IOE
, msc_stopioe
, 0) },
319 { FLDATA (CTYPE
, ms_ctype
, 0), REG_HRO
},
320 { ORDATA (DEVNO
, msc_dib
.devno
, 6), REG_HRO
},
325 { UNIT_OFFLINE
, UNIT_OFFLINE
, "offline", "OFFLINE", NULL
},
326 { UNIT_OFFLINE
, 0, "online", "ONLINE", msc_online
},
327 { MTUF_WLK
, 0, "write enabled", "WRITEENABLED", NULL
},
328 { MTUF_WLK
, MTUF_WLK
, "write locked", "LOCKED", NULL
},
329 { MTAB_XTD
| MTAB_VUN
, 0, "CAPACITY", "CAPACITY",
330 &ms_set_reelsize
, &ms_show_reelsize
, NULL
},
331 { MTAB_XTD
| MTAB_VUN
| MTAB_NMO
, 1, "REEL", "REEL",
332 &ms_set_reelsize
, &ms_show_reelsize
, NULL
},
333 { MTAB_XTD
| MTAB_VUN
, 0, "FORMAT", "FORMAT",
334 &sim_tape_set_fmt
, &sim_tape_show_fmt
, NULL
},
335 { MTAB_XTD
| MTAB_VDV
, 0, NULL
, "13181A",
336 &ms_settype
, NULL
, NULL
},
337 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "13183A",
338 &ms_settype
, NULL
, NULL
},
339 { MTAB_XTD
| MTAB_VDV
, 0, "TYPE", NULL
,
340 NULL
, &ms_showtype
, NULL
},
341 { MTAB_XTD
| MTAB_VDV
, 0, NULL
, "REALTIME",
342 &ms_set_timing
, NULL
, NULL
},
343 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "FASTTIME",
344 &ms_set_timing
, NULL
, NULL
},
345 { MTAB_XTD
| MTAB_VDV
, 0, "TIMING", NULL
,
346 NULL
, &ms_show_timing
, NULL
},
347 { MTAB_XTD
| MTAB_VDV
, 1, "DEVNO", "DEVNO",
348 &hp_setdev
, &hp_showdev
, &msd_dev
},
353 { "CMDS", DEB_CMDS
},
360 "MSC", msc_unit
, msc_reg
, msc_mod
,
361 MS_NUMDR
, 10, 31, 1, 8, 8,
362 NULL
, NULL
, &msc_reset
,
363 &msc_boot
, &msc_attach
, &msc_detach
,
364 &msc_dib
, DEV_DISABLE
| DEV_DEBUG
,
365 0, msc_deb
, NULL
, NULL
368 /* IO instructions */
370 int32
msdio (int32 inst
, int32 IR
, int32 dat
)
374 devd
= IR
& I_DEVMASK
; /* get device no */
375 switch (inst
) { /* case on opcode */
377 case ioFLG
: /* flag clear/set */
378 if ((IR
& I_HC
) == 0) { setFSR (devd
); } /* STF */
381 case ioSFC
: /* skip flag clear */
382 if (FLG (devd
) == 0) PC
= (PC
+ 1) & VAMASK
;
385 case ioSFS
: /* skip flag set */
386 if (FLG (devd
) != 0) PC
= (PC
+ 1) & VAMASK
;
389 case ioOTX
: /* output */
390 msd_buf
= dat
; /* store data */
393 case ioMIX
: /* merge */
397 case ioLIX
: /* load */
401 case ioCRS
: /* control reset (action unverif) */
402 case ioCTL
: /* control clear/set */
403 if (IR
& I_CTL
) { /* CLC */
404 clrCTL (devd
); /* clr ctl, cmd */
408 setCTL (devd
); /* set ctl, cmd */
413 case ioEDT
: /* DMA end */
414 clrFSR (devd
); /* same as CLF */
421 if (IR
& I_HC
) { clrFSR (devd
); } /* H/C option */
425 int32
mscio (int32 inst
, int32 IR
, int32 dat
)
427 int32 i
, devc
, devd
, sched_time
;
429 UNIT
*uptr
= msc_dev
.units
+ msc_usl
;
430 static const uint8 map_sel
[16] = {
431 0, 0, 1, 1, 2, 2, 2, 2,
432 3, 3, 3, 3, 3, 3, 3, 3
435 devc
= IR
& I_DEVMASK
; /* get device no */
437 switch (inst
) { /* case on opcode */
439 case ioFLG
: /* flag clear/set */
440 if ((IR
& I_HC
) == 0) { setFSR (devc
); } /* STF */
443 case ioSFC
: /* skip flag clear */
444 if (FLG (devc
) == 0) PC
= (PC
+ 1) & VAMASK
;
447 case ioSFS
: /* skip flag set */
448 if (FLG (devc
) != 0) PC
= (PC
+ 1) & VAMASK
;
451 case ioOTX
: /* output */
452 if (DEBUG_PRI (msc_dev
, DEB_CPU
))
453 fprintf (sim_deb
, ">>MSC OTx: Command = %06o\n", dat
);
455 msc_sta
= msc_sta
& ~STA_REJ
; /* clear reject */
456 if ((dat
& 0377) == FNC_CLR
) break; /* clear always ok */
457 if (msc_sta
& STA_BUSY
) { /* busy? reject */
458 msc_sta
= msc_sta
| STA_REJ
; /* dont chg select */
461 if (dat
& FNF_CHS
) { /* select change */
462 msc_usl
= map_sel
[FNC_GETSEL (dat
)]; /* is immediate */
463 uptr
= msc_dev
.units
+ msc_usl
;
464 if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
465 fprintf (sim_deb
, ">>MSC OTx: Unit %d selected\n", msc_usl
);
467 if (((dat
& FNF_MOT
) && sim_is_active (uptr
)) ||
468 ((dat
& FNF_REV
) && sim_tape_bot (uptr
)) ||
469 ((dat
& FNF_WRT
) && sim_tape_wrp (uptr
)))
470 msc_sta
= msc_sta
| STA_REJ
; /* reject? */
473 case ioLIX
: /* load */
475 case ioMIX
: /* merge */
476 dat
= dat
| (msc_sta
& ~STA_DYN
); /* get card status */
477 if ((uptr
->flags
& UNIT_OFFLINE
) == 0) { /* online? */
478 dat
= dat
| uptr
->UST
; /* add unit status */
479 if (sim_tape_bot (uptr
)) /* BOT? */
481 if (sim_is_active (uptr
) && /* TBSY unless RWD at BOT */
482 !((uptr
->FNC
& FNF_RWD
) && sim_tape_bot (uptr
)))
483 dat
= dat
| STA_TBSY
;
484 if (sim_tape_wrp (uptr
)) /* write prot? */
486 if (sim_tape_eot (uptr
)) /* EOT? */
489 else dat
= dat
| STA_TBSY
| STA_LOCAL
;
490 if (ms_ctype
) dat
= dat
| STA_PE
| /* 13183A? */
491 (msc_usl
<< STA_V_SEL
);
492 if (DEBUG_PRI (msc_dev
, DEB_CPU
))
493 fprintf (sim_deb
, ">>MSC LIx: Status = %06o\n", dat
);
496 case ioCRS
: /* control reset (action unverif) */
497 case ioCTL
: /* control clear/set */
498 if (IR
& I_CTL
) { clrCTL (devc
); } /* CLC */
499 else if (!(msc_sta
& STA_REJ
)) { /* STC, last cmd rejected? */
500 if ((msc_buf
& 0377) == FNC_CLR
) { /* clear? */
501 for (i
= 0; i
< MS_NUMDR
; i
++) { /* look for write in progr */
502 if (sim_is_active (&msc_unit
[i
]) && /* unit active? */
503 (msc_unit
[i
].FNC
== FNC_WC
) && /* last cmd write? */
504 (ms_ptr
> 0)) { /* partial buffer? */
505 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
507 ">>MSC STC: Unit %d wrote %d word partial record\n",
509 if (st
= sim_tape_wrrecf (uptr
, msxb
, ms_ptr
| MTR_ERF
))
510 ms_map_err (uptr
, st
); /* discard any error */
511 ms_ptr
= 0; /* clear partial */
513 if ((msc_unit
[i
].UST
& STA_REW
) == 0)
514 sim_cancel (&msc_unit
[i
]); /* stop if not rew */
516 setCTL (devc
); /* set CTL for STC */
517 setFSR (devc
); /* set FLG for completion */
518 msc_sta
= msc_1st
= 0; /* clr ctlr status */
519 if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
520 fputs (">>MSC STC: Controller cleared\n", sim_deb
);
523 uptr
->FNC
= msc_buf
& 0377; /* save function */
524 if (uptr
->FNC
& FNF_RWD
) { /* rewind? */
525 if (!sim_tape_bot (uptr
)) /* not at BOT? */
526 uptr
->UST
= STA_REW
; /* set rewinding */
527 sched_time
= msc_rtime
; /* set response time */
530 if (sim_tape_bot (uptr
)) /* at BOT? */
531 sched_time
= msc_btime
; /* use BOT start time */
532 else if ((uptr
->FNC
== FNC_GAP
) || (uptr
->FNC
== FNC_GFM
))
533 sched_time
= msc_gtime
; /* use gap traversal time */
535 if (uptr
->FNC
!= FNC_GAP
)
536 sched_time
+= msc_ctime
; /* add base command time */
538 if (msc_buf
& ~FNC_SEL
) { /* NOP for unit sel alone */
539 sim_activate (uptr
, sched_time
); /* else schedule op */
540 if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
542 ">>MSC STC: Unit %d command %03o (%s) scheduled, "
543 "pos = %d, time = %d\n",
544 msc_usl
, uptr
->FNC
, ms_cmd_name (uptr
->FNC
),
545 uptr
->pos
, sched_time
);
547 else if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
548 fputs (">>MSC STC: Unit select (NOP)\n", sim_deb
);
549 msc_sta
= STA_BUSY
; /* ctrl is busy */
551 setCTL (devc
); /* go */
555 case ioEDT
: /* DMA end */
556 clrFSR (devc
); /* same as CLF */
563 if (IR
& I_HC
) { clrFSR (devc
); } /* H/C option */
569 If rewind done, reposition to start of tape, set status
570 else, do operation, set done, interrupt.
572 In addition to decreasing the timing intervals, the FASTTIME option enables
573 two additional optimizations: WFM for GFM substitution, and BOT gap
574 elimination. If FASTTIME is selected, gap and file mark (GFM) commands are
575 processed as WFM (write file mark) commands. That is, the preceding GAP is
576 not performed. Also, the initial gap that normally precedes the first data
577 record or EOF mark at the beginning of the tape is omitted. These omissions
578 result in smaller tape image files. If REALTIME is selected, the gaps are
579 included. Note that the gaps (and realistic timing) are necessary to pass
580 the 7970 diagnostics.
583 t_stat
msc_svc (UNIT
*uptr
)
585 int32 devc
, devd
, unum
;
587 t_stat st
, r
= SCPE_OK
;
589 devc
= msc_dib
.devno
; /* get device nos */
590 devd
= msd_dib
.devno
;
591 unum
= uptr
- msc_dev
.units
; /* get unit number */
593 if ((uptr
->FNC
!= FNC_RWS
) && (uptr
->flags
& UNIT_OFFLINE
)) { /* offline? */
594 msc_sta
= (msc_sta
| STA_REJ
) & ~STA_BUSY
; /* reject */
595 setFSR (devc
); /* set cch flg */
596 return IORETURN (msc_stopioe
, SCPE_UNATT
);
599 switch (uptr
->FNC
) { /* case on function */
601 case FNC_RWS
: /* rewind offline */
602 sim_tape_rewind (uptr
); /* rewind tape */
603 uptr
->flags
= uptr
->flags
| UNIT_OFFLINE
; /* set offline */
604 uptr
->UST
= 0; /* clear REW status */
605 break; /* we're done */
607 case FNC_REW
: /* rewind */
608 if (uptr
->UST
& STA_REW
) { /* rewind in prog? */
609 uptr
->FNC
|= FNC_CMPL
; /* set compl state */
610 sim_activate (uptr
, msc_ctime
); /* sched completion */
612 break; /* anyway, ctrl done */
614 case FNC_REW
| FNC_CMPL
: /* complete rewind */
615 sim_tape_rewind (uptr
); /* rewind tape */
616 uptr
->UST
= 0; /* clear REW status */
617 return SCPE_OK
; /* drive is free */
619 case FNC_GFM
: /* gap + file mark */
620 if (ms_timing
== 1) /* fast timing? */
621 goto DO_WFM
; /* do plain file mark */
622 /* else fall into GAP */
623 case FNC_GAP
: /* erase gap */
624 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
626 ">>MSC svc: Unit %d wrote gap\n",
628 if ((r
= ms_write_gap (uptr
)) || /* write tape gap; error? */
629 (uptr
->FNC
!= FNC_GFM
)) /* not GFM? */
630 break; /* bail out now */
631 /* else drop into WFM */
632 case FNC_WFM
: /* write file mark */
633 if ((ms_timing
== 0) && sim_tape_bot (uptr
)) { /* realistic timing + BOT? */
634 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
636 ">>MSC svc: Unit %d wrote initial gap\n",
638 if (st
= ms_write_gap (uptr
)) { /* write initial gap; error? */
639 r
= ms_map_err (uptr
, st
); /* map error */
640 break; /* terminate operation */
644 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
646 ">>MSC svc: Unit %d wrote file mark\n",
648 if (st
= sim_tape_wrtmk (uptr
)) /* write tmk, err? */
649 r
= ms_map_err (uptr
, st
); /* map error */
650 msc_sta
= STA_EOF
; /* set EOF status */
653 case FNC_FSR
: /* space forward */
654 if (st
= sim_tape_sprecf (uptr
, &tbc
)) /* space rec fwd, err? */
655 r
= ms_map_err (uptr
, st
); /* map error */
656 if (tbc
& 1) msc_sta
= msc_sta
| STA_ODD
;
657 else msc_sta
= msc_sta
& ~STA_ODD
;
660 case FNC_BSR
: /* space reverse */
661 if (st
= sim_tape_sprecr (uptr
, &tbc
)) /* space rec rev, err? */
662 r
= ms_map_err (uptr
, st
); /* map error */
663 if (tbc
& 1) msc_sta
= msc_sta
| STA_ODD
;
664 else msc_sta
= msc_sta
& ~STA_ODD
;
667 case FNC_FSF
: /* space fwd file */
668 while ((st
= sim_tape_sprecf (uptr
, &tbc
)) == MTSE_OK
) {
669 if (sim_tape_eot (uptr
)) break; /* EOT stops */
671 r
= ms_map_err (uptr
, st
); /* map error */
674 case FNC_BSF
: /* space rev file */
675 while ((st
= sim_tape_sprecr (uptr
, &tbc
)) == MTSE_OK
) ;
676 r
= ms_map_err (uptr
, st
); /* map error */
679 case FNC_RFF
: /* diagnostic read */
680 case FNC_RC
: /* read */
681 if (msc_1st
) { /* first svc? */
682 msc_1st
= ms_ptr
= ms_max
= 0; /* clr 1st flop */
683 st
= sim_tape_rdrecf (uptr
, msxb
, &ms_max
, DBSIZE
); /* read rec */
684 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
686 ">>MSC svc: Unit %d read %d word record\n",
688 if (st
== MTSE_RECE
) msc_sta
= msc_sta
| STA_PAR
; /* rec in err? */
689 else if (st
!= MTSE_OK
) { /* other error? */
690 r
= ms_map_err (uptr
, st
); /* map error */
691 if (r
== SCPE_OK
) { /* recoverable? */
692 sim_activate (uptr
, msc_itime
); /* sched IRG */
693 uptr
->FNC
|= FNC_CMPL
; /* set completion */
696 break; /* err, done */
698 if (ms_ctype
) msc_sta
= msc_sta
| STA_ODD
; /* set ODD for 13183A */
700 if (CTL (devd
) && (ms_ptr
< ms_max
)) { /* DCH on, more data? */
701 if (FLG (devd
)) msc_sta
= msc_sta
| STA_TIM
| STA_PAR
;
702 msd_buf
= ((uint16
) msxb
[ms_ptr
] << 8) |
703 ((ms_ptr
+ 1 == ms_max
) ? 0 : msxb
[ms_ptr
+ 1]);
705 setFSR (devd
); /* set dch flg */
706 sim_activate (uptr
, msc_xtime
); /* re-activate */
709 if (ms_max
& 1) msc_sta
= msc_sta
| STA_ODD
; /* set ODD by rec len */
710 else msc_sta
= msc_sta
& ~STA_ODD
;
711 sim_activate (uptr
, msc_itime
); /* sched IRG */
712 if (uptr
->FNC
== FNC_RFF
) msc_1st
= 1; /* diagnostic? */
713 else uptr
->FNC
|= FNC_CMPL
; /* set completion */
716 case FNC_RFF
| FNC_CMPL
: /* diagnostic read completion */
717 case FNC_RC
| FNC_CMPL
: /* read completion */
720 case FNC_WC
: /* write */
721 if (msc_1st
) { /* first service? */
722 msc_1st
= ms_ptr
= 0; /* no data xfer on first svc */
723 if ((ms_timing
== 0) && sim_tape_bot (uptr
)) { /* realistic timing + BOT? */
724 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
726 ">>MSC svc: Unit %d wrote initial gap\n",
728 if (st
= ms_write_gap (uptr
)) { /* write initial gap; error? */
729 r
= ms_map_err (uptr
, st
); /* map error */
730 break; /* terminate operation */
734 else { /* not 1st, next char */
735 if (ms_ptr
< DBSIZE
) { /* room in buffer? */
736 msxb
[ms_ptr
] = msd_buf
>> 8; /* store 2 char */
737 msxb
[ms_ptr
+ 1] = msd_buf
& 0377;
740 else msc_sta
= msc_sta
| STA_PAR
;
742 if (CTL (devd
)) { /* xfer flop set? */
743 setFSR (devd
); /* set dch flag */
744 sim_activate (uptr
, msc_xtime
); /* re-activate */
747 if (ms_ptr
) { /* any data? write */
748 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
750 ">>MSC svc: Unit %d wrote %d word record\n",
752 if (st
= sim_tape_wrrecf (uptr
, msxb
, ms_ptr
)) { /* write, err? */
753 r
= ms_map_err (uptr
, st
); /* map error */
757 sim_activate (uptr
, msc_itime
); /* sched IRG */
758 uptr
->FNC
|= FNC_CMPL
; /* set completion */
761 case FNC_WC
| FNC_CMPL
: /* write completion */
764 case FNC_RRR
: /* not supported */
765 default: /* unknown command */
766 if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
768 ">>MSC svc: Unit %d command %03o is unknown (NOP)\n",
773 setFSR (devc
); /* set cch flg */
774 msc_sta
= msc_sta
& ~STA_BUSY
; /* update status */
775 if (DEBUG_PRI (msc_dev
, DEB_CMDS
))
777 ">>MSC svc: Unit %d command %03o (%s) complete\n",
778 unum
, uptr
->FNC
& 0377, ms_cmd_name (uptr
->FNC
));
782 /* Write an erase gap */
784 t_stat
ms_write_gap (UNIT
*uptr
)
787 uint32 gap_len
= ms_ctype
? GAP_13183
: GAP_13181
; /* establish gap length */
788 uint32 tape_bpi
= ms_ctype
? BPI_13183
: BPI_13181
; /* establish nominal bpi */
790 if (st
= sim_tape_wrgap (uptr
, gap_len
, tape_bpi
)) /* write gap */
791 return ms_map_err (uptr
, st
); /* map error if failure */
796 /* Map tape error status */
798 t_stat
ms_map_err (UNIT
*uptr
, t_stat st
)
800 int32 unum
= uptr
- msc_dev
.units
; /* get unit number */
802 if (DEBUG_PRI (msc_dev
, DEB_RWS
))
804 ">>MSC err: Unit %d tape library status = %d\n",
809 case MTSE_FMT
: /* illegal fmt */
810 msc_sta
= msc_sta
| STA_REJ
; /* reject cmd */
811 return SCPE_FMT
; /* format error */
813 case MTSE_UNATT
: /* unattached */
814 msc_detach (uptr
); /* resync status (ignore rtn) */
815 msc_sta
= msc_sta
| STA_REJ
; /* reject cmd */
816 return SCPE_UNATT
; /* unit unattached */
818 case MTSE_OK
: /* no error */
819 return SCPE_IERR
; /* never get here! */
821 case MTSE_EOM
: /* end of medium */
822 case MTSE_TMK
: /* end of file */
823 msc_sta
= msc_sta
| STA_EOF
| (ms_ctype
? 0 : STA_ODD
);
824 break; /* EOF also sets ODD for 13181A */
826 case MTSE_INVRL
: /* invalid rec lnt */
827 msc_sta
= msc_sta
| STA_PAR
;
830 case MTSE_IOERR
: /* IO error */
831 msc_sta
= msc_sta
| STA_PAR
; /* error */
832 if (msc_stopioe
) return SCPE_IOERR
;
835 case MTSE_RECE
: /* record in error */
836 msc_sta
= msc_sta
| STA_PAR
; /* error */
839 case MTSE_WRP
: /* write protect */
840 msc_sta
= msc_sta
| STA_REJ
; /* reject */
849 t_stat
msc_reset (DEVICE
*dptr
)
854 hp_enbdis_pair (dptr
, /* make pair cons */
855 (dptr
== &msd_dev
)? &msc_dev
: &msd_dev
);
856 msc_buf
= msd_buf
= 0;
857 msc_sta
= msc_usl
= 0;
859 msc_dib
.cmd
= msd_dib
.cmd
= 0; /* clear cmd */
860 msc_dib
.ctl
= msd_dib
.ctl
= 0; /* clear ctl */
861 msc_dib
.flg
= msd_dib
.flg
= 1; /* set flg */
862 msc_dib
.fbf
= msd_dib
.fbf
= 1; /* set fbf */
863 msc_dib
.srq
= msd_dib
.srq
= 1; /* srq follows flg */
864 for (i
= 0; i
< MS_NUMDR
; i
++) {
865 uptr
= msc_dev
.units
+ i
;
866 sim_tape_reset (uptr
);
876 t_stat
msc_attach (UNIT
*uptr
, char *cptr
)
880 r
= sim_tape_attach (uptr
, cptr
); /* attach unit */
882 uptr
->flags
= uptr
->flags
& ~UNIT_OFFLINE
; /* set online */
888 t_stat
msc_detach (UNIT
* uptr
)
890 uptr
->UST
= 0; /* clear status */
891 uptr
->flags
= uptr
->flags
| UNIT_OFFLINE
; /* set offline */
892 return sim_tape_detach (uptr
); /* detach unit */
897 t_stat
msc_online (UNIT
*uptr
, int32 value
, char *cptr
, void *desc
)
899 if (uptr
->flags
& UNIT_ATT
) return SCPE_OK
;
900 else return SCPE_UNATT
;
903 /* Configure timing */
905 void ms_config_timing (void)
909 tset
= (ms_timing
<< 1) | (ms_timing
? 0 : ms_ctype
); /* select timing set */
910 for (i
= 0; i
< (sizeof (timers
) / sizeof (timers
[0])); i
++)
911 *timers
[i
] = msc_times
[tset
][i
]; /* assign times */
914 /* Set controller timing */
916 t_stat
ms_set_timing (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
918 if ((val
< 0) || (val
> 1) || (cptr
!= NULL
)) return SCPE_ARG
;
924 /* Show controller timing */
926 t_stat
ms_show_timing (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
928 if (ms_timing
) fputs ("fast timing", st
);
929 else fputs ("realistic timing", st
);
933 /* Set controller type */
935 t_stat
ms_settype (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
939 if ((val
< 0) || (val
> 1) || (cptr
!= NULL
)) return SCPE_ARG
;
940 for (i
= 0; i
< MS_NUMDR
; i
++) {
941 if (msc_unit
[i
].flags
& UNIT_ATT
) return SCPE_ALATT
;
944 ms_config_timing (); /* update for new type */
948 /* Show controller type */
950 t_stat
ms_showtype (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
952 if (ms_ctype
) fprintf (st
, "13183A");
953 else fprintf (st
, "13181A");
957 /* Set unit reel size
959 val = 0 -> SET MSCn CAPACITY=n
960 val = 1 -> SET MSCn REEL=n */
962 t_stat
ms_set_reelsize (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
968 status
= sim_tape_set_capac (uptr
, val
, cptr
, desc
);
969 if (status
== SCPE_OK
) uptr
->REEL
= 0;
973 if (cptr
== NULL
) return SCPE_ARG
;
974 reel
= (int32
) get_uint (cptr
, 10, 2400, &status
);
975 if (status
!= SCPE_OK
) return status
;
979 uptr
->REEL
= 0; /* type 0 = unlimited/custom */
983 uptr
->REEL
= 1; /* type 1 = 600 foot */
987 uptr
->REEL
= 2; /* type 2 = 1200 foot */
991 uptr
->REEL
= 3; /* type 3 = 2400 foot */
998 uptr
->capac
= uptr
->REEL
? (TCAP
<< uptr
->REEL
) << ms_ctype
: 0;
1002 /* Show unit reel size
1004 val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY
1005 val = 1 -> SHOW MSCn REEL */
1007 t_stat
ms_show_reelsize (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1009 t_stat status
= SCPE_OK
;
1011 if (uptr
->REEL
== 0) status
= sim_tape_show_capac (st
, uptr
, val
, desc
);
1012 else fprintf (st
, "%4d foot reel", 300 << uptr
->REEL
);
1013 if (val
== 1) fputc ('\n', st
); /* MTAB_NMO omits \n */
1017 /* Translate command to mnemonic for debug logging
1019 The command names and descriptions are taken from the 13181 interface
1022 char *ms_cmd_name (uint32 cmd
)
1025 switch (cmd
& 0377) {
1026 case FNC_WC
: return "WCC"; /* Write command */
1027 case FNC_WFM
: return "WFM"; /* Write file mark */
1028 case FNC_RC
: return "RRF"; /* Read record forward */
1029 case FNC_FSR
: return "FSR"; /* Forward space record */
1030 case FNC_FSF
: return "FSF"; /* Forward space file */
1031 case FNC_GAP
: return "GAP"; /* Write gap */
1032 case FNC_BSR
: return "BSR"; /* Backspace record */
1033 case FNC_BSF
: return "BSF"; /* Backspace file */
1034 case FNC_REW
: return "REW"; /* Rewind */
1035 case FNC_RWS
: return "RWO"; /* Rewind off-line */
1036 case FNC_CLR
: return "CLR"; /* Clear controller */
1037 case FNC_GFM
: return "GFM"; /* Gap file mark */
1038 case FNC_RFF
: return "RFF"; /* Read forward until file mark (diag) */
1039 case FNC_RRR
: return "RRR"; /* Read record in reverse (diag) */
1041 default: return "???"; /* Unknown command */
1045 /* 7970B/7970E bootstrap routine (HP 12992D ROM) */
1047 const uint16 ms_rom
[IBL_LNT
] = {
1048 0106501, /*ST LIB 1 ; read sw */
1049 0006011, /* SLB,RSS ; bit 0 set? */
1050 0027714, /* JMP RD ; no read */
1051 0003004, /* CMA,INA ; A is ctr */
1052 0073775, /* STA WC ; save */
1053 0067772, /* LDA SL0RW ; sel 0, rew */
1054 0017762, /*FF JSB CMD ; do cmd */
1055 0102311, /* SFS CC ; done? */
1056 0027707, /* JMP *-1 ; wait */
1057 0067774, /* LDB FFC ; get file fwd */
1058 0037775, /* ISZ WC ; done files? */
1059 0027706, /* JMP FF ; no */
1060 0067773, /*RD LDB RDCMD ; read cmd */
1061 0017762, /* JSB CMD ; do cmd */
1062 0103710, /* STC DC,C ; start dch */
1063 0102211, /* SFC CC ; read done? */
1064 0027752, /* JMP STAT ; no, get stat */
1065 0102310, /* SFS DC ; any data? */
1066 0027717, /* JMP *-3 ; wait */
1067 0107510, /* LIB DC,C ; get rec cnt */
1068 0005727, /* BLF,BLF ; move to lower */
1069 0007000, /* CMB ; make neg */
1070 0077775, /* STA WC ; save */
1071 0102211, /* SFC CC ; read done? */
1072 0027752, /* JMP STAT ; no, get stat */
1073 0102310, /* SFS DC ; any data? */
1074 0027727, /* JMP *-3 ; wait */
1075 0107510, /* LIB DC,C ; get load addr */
1076 0074000, /* STB 0 ; start csum */
1077 0077762, /* STA CMD ; save address */
1078 0027742, /* JMP *+4 */
1079 0177762, /*NW STB CMD,I ; store data */
1080 0040001, /* ADA 1 ; add to csum */
1081 0037762, /* ISZ CMD ; adv addr ptr */
1082 0102310, /* SFS DC ; any data? */
1083 0027742, /* JMP *-1 ; wait */
1084 0107510, /* LIB DC,C ; get word */
1085 0037775, /* ISZ WC ; done? */
1086 0027737, /* JMP NW ; no */
1087 0054000, /* CPB 0 ; csum ok? */
1088 0027717, /* JMP RD+3 ; yes, cont */
1089 0102011, /* HLT 11 ; no, halt */
1090 0102511, /*ST LIA CC ; get status */
1091 0001727, /* ALF,ALF ; get eof bit */
1092 0002020, /* SSA ; set? */
1093 0102077, /* HLT 77 ; done */
1094 0001727, /* ALF,ALF ; put status back */
1095 0001310, /* RAR,SLA ; read ok? */
1096 0102000, /* HLT 0 ; no */
1097 0027714, /* JMP RD ; read next */
1099 0106611, /* OTB CC ; output cmd */
1100 0102511, /* LIA CC ; check for reject */
1101 0001323, /* RAR,RAR */
1102 0001310, /* RAR,SLA */
1103 0027763, /* JMP CMD+1 ; try again */
1104 0103711, /* STC CC,C ; start command */
1105 0127762, /* JMP CMD,I ; exit */
1106 0001501, /*SL0RW 001501 ; select 0, rewind */
1107 0001423, /*RDCMD 001423 ; read record */
1108 0000203, /*FFC 000203 ; space forward file */
1109 0000000, /*WC 000000 */
1114 t_stat
msc_boot (int32 unitno
, DEVICE
*dptr
)
1117 extern uint32 saved_AR
;
1119 if (unitno
!= 0) return SCPE_NOFNC
; /* only unit 0 */
1120 dev
= msd_dib
.devno
; /* get data chan dev */
1121 if (ibl_copy (ms_rom
, dev
)) return SCPE_IERR
; /* copy boot to memory */
1122 SR
= (SR
& IBL_OPT
) | IBL_MS
| (dev
<< IBL_V_DEV
); /* set SR */
1123 if ((sim_switches
& SWMASK ('S')) && saved_AR
) SR
= SR
| 1; /* skip? */