1 /* hp2100_ms.c: HP 2100 13181B/13183B Digital Magnetic Tape Unit Interface simulator
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    AUTHOR 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    MS           13181B Digital Magnetic Tape Unit Interface
28                 13183B Digital Magnetic Tape Unit Interface
29 
30    18-Mar-19    JDB     Reordered SCP includes
31    24-Jan-19    JDB     Removed DEV_TAPE from DEVICE flags
32    27-Dec-18    JDB     Added fall through comments in msc_svc
33    05-Jun-18    JDB     Revised I/O model
34    28-Feb-18    JDB     Added the BMTL
35    23-Feb-18    JDB     Eliminated "msc_boot" references to A and S registers
36    20-Jul-17    JDB     Removed "msc_stopioe" variable and register
37    11-Jul-17    JDB     Renamed "ibl_copy" to "cpu_ibl"
38    15-Mar-17    JDB     Trace flags are now global
39                         Changed DEBUG_PRI calls to tprintfs
40    13-Mar-17    JDB     Deprecated LOCKED/WRITEENABLED for ATTACH -R
41    10-Mar-17    JDB     Added IOBUS to the debug table
42    27-Feb-17    JDB     ibl_copy no longer returns a status code
43    17-Jan-17    JDB     Modified to use "odd_parity" array in hp2100_sys.c
44    13-May-16    JDB     Modified for revised SCP API function parameter types
45    30-Dec-14    JDB     Added S-register parameters to ibl_copy
46    24-Dec-14    JDB     Use T_ADDR_FMT with t_addr values for 64-bit compatibility
47                         Added casts for explicit downward conversions
48    11-Dec-14    JDB     Updated for new erase gap API, added CRCC/LRCC support
49    10-Jan-13    MP      Added DEV_TAPE to DEVICE flags
50    09-May-12    JDB     Separated assignments from conditional expressions
51    10-Feb-12    JDB     Deprecated DEVNO in favor of SC
52                         Added CNTLR_TYPE cast to ms_settype
53    28-Mar-11    JDB     Tidied up signal handling
54    26-Oct-10    JDB     Changed I/O signal handler for revised signal model
55    11-Aug-08    JDB     Revised to use AR instead of saved_AR in boot
56    26-Jun-08    JDB     Rewrote device I/O to model backplane signals
57    28-Dec-06    JDB     Added ioCRS state to I/O decoders
58    18-Sep-06    JDB     Fixed 2nd CLR after WC causing another write
59                         Improve debug reporting, add debug flags
60    14-Sep-06    JDB     Removed local BOT flag, now uses sim_tape_bot
61    30-Aug-06    JDB     Added erase gap support, improved tape lib err reporting
62    07-Jul-06    JDB     Added CAPACITY as alternate for REEL
63                         Fixed EOT test for unlimited reel size
64    16-Feb-06    RMS     Revised for new EOT test
65    22-Jul-05    RMS     Fixed compiler warning on Solaris (from Doug Glyn)
66    01-Mar-05    JDB     Added SET OFFLINE; rewind/offline now does not detach
67    07-Oct-04    JDB     Fixed enable/disable from either device
68    14-Aug-04    JDB     Fixed many functional and timing problems (from Dave Bryan)
69                         - fixed erroneous execution of rejected command
70                         - fixed erroneous execution of select-only command
71                         - fixed erroneous execution of clear command
72                         - fixed odd byte handling for read
73                         - fixed spurious odd byte status on 13183A EOF
74                         - modified handling of end of medium
75                         - added detailed timing, with fast and realistic modes
76                         - added reel sizes to simulate end of tape
77                         - added debug printouts
78    06-Jul-04    RMS     Fixed spurious timing error after CLC (found by Dave Bryan)
79    26-Apr-04    RMS     Fixed SFS x,C and SFC x,C
80                         Fixed SR setting in IBL
81                         Revised IBL loader
82                         Implemented DMA SRQ (follows FLG)
83    25-Apr-03    RMS     Revised for extended file support
84    28-Mar-03    RMS     Added multiformat support
85    28-Feb-03    RMS     Revised for magtape library
86    18-Oct-02    RMS     Added BOOT command, added 13183A support
87    30-Sep-02    RMS     Revamped error handling
88    29-Aug-02    RMS     Added end of medium support
89    30-May-02    RMS     Widened POS to 32b
90    22-Apr-02    RMS     Added maximum record length test
91 
92    References:
93      - 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
94          (13181-90901, November 1982)
95      - 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
96          (13183-90901, November 1983)
97      - SIMH Magtape Representation and Handling
98          (Bob Supnik, 30-Aug-2006)
99 */
100 
101 
102 
103 #include "sim_defs.h"
104 #include "sim_tape.h"
105 
106 #include "hp2100_defs.h"
107 #include "hp2100_io.h"
108 
109 
110 
111 #define UNIT_V_OFFLINE  (MTUF_V_UF + 0)         /* unit offline */
112 #define UNIT_OFFLINE    (1 << UNIT_V_OFFLINE)
113 
114 #define MS_NUMDR        4                       /* number of drives */
115 #define DB_N_SIZE       16                      /* max data buf */
116 #define DBSIZE          (1 << DB_N_SIZE)        /* max data cmd */
117 #define FNC             u3                      /* function */
118 #define UST             u4                      /* unit status */
119 #define REEL            u5                      /* tape reel size */
120 
121 #define BPI_13181       MT_DENS_800             /* 800 bpi for 13181 cntlr */
122 #define BPI_13183       MT_DENS_1600            /* 1600 bpi for 13183 cntlr */
123 #define GAP_13181       48                      /* gap is 4.8 inches for 13181 cntlr */
124 #define GAP_13183       30                      /* gap is 3.0 inches for 13183 cntlr */
125 #define TCAP            (300 * 12 * 800)        /* 300 ft capacity at 800 bpi */
126 
127 /* Command - msc_fnc */
128 
129 #define FNC_CLR         00110                   /* clear */
130 #define FNC_GAP         00015                   /* write gap */
131 #define FNC_GFM         00215                   /* gap+file mark */
132 #define FNC_RC          00023                   /* read */
133 #define FNC_WC          00031                   /* write */
134 #define FNC_FSR         00003                   /* forward space */
135 #define FNC_BSR         00041                   /* backward space */
136 #define FNC_FSF         00203                   /* forward file */
137 #define FNC_BSF         00241                   /* backward file */
138 #define FNC_REW         00101                   /* rewind */
139 #define FNC_RWS         00105                   /* rewind and offline */
140 #define FNC_WFM         00211                   /* write file mark */
141 #define FNC_RFF         00223                   /* read file fwd (diag) */
142 #define FNC_RRR         00061                   /* read record rev (diag) */
143 #define FNC_CMPL        00400                   /* completion state */
144 #define FNC_V_SEL       9                       /* select */
145 #define FNC_M_SEL       017
146 #define FNC_GETSEL(x)   (((x) >> FNC_V_SEL) & FNC_M_SEL)
147 
148 #define FNF_MOT         00001                   /* motion */
149 #define FNF_OFL         00004
150 #define FNF_WRT         00010                   /* write */
151 #define FNF_REV         00040                   /* reverse */
152 #define FNF_RWD         00100                   /* rewind */
153 #define FNF_CHS         00400                   /* change select */
154 
155 #define FNC_SEL         ((FNC_M_SEL << FNC_V_SEL) | FNF_CHS)
156 
157 /* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */
158 
159 #define STA_PE          0100000                 /* 1600 bpi (d) */
160 #define STA_V_SEL       13                      /* unit sel (d) */
161 #define STA_M_SEL       03
162 #define STA_SEL         (STA_M_SEL << STA_V_SEL)
163 #define STA_ODD         0004000                 /* odd bytes */
164 #define STA_REW         0002000                 /* rewinding (u) */
165 #define STA_TBSY        0001000                 /* transport busy (d) */
166 #define STA_BUSY        0000400                 /* ctrl busy */
167 #define STA_EOF         0000200                 /* end of file */
168 #define STA_BOT         0000100                 /* beg of tape (d) */
169 #define STA_EOT         0000040                 /* end of tape (d) */
170 #define STA_TIM         0000020                 /* timing error */
171 #define STA_REJ         0000010                 /* programming error */
172 #define STA_WLK         0000004                 /* write locked (d) */
173 #define STA_PAR         0000002                 /* parity error */
174 #define STA_LOCAL       0000001                 /* local (d) */
175 #define STA_DYN         (STA_PE  | STA_SEL | STA_TBSY | STA_BOT | \
176                          STA_EOT | STA_WLK | STA_LOCAL)
177 
178 /* Controller types */
179 
180 typedef enum {
181     A13181,
182     A13183
183     } CNTLR_TYPE;
184 
185 /* Interface state */
186 
187 typedef struct {
188     FLIP_FLOP  control;                         /* control flip-flop */
189     FLIP_FLOP  flag;                            /* flag flip-flop */
190     FLIP_FLOP  flag_buffer;                     /* flag buffer flip-flop */
191     } CARD_STATE;
192 
193 static CARD_STATE msd;                          /* data per-card state */
194 static CARD_STATE msc;                          /* command per-card state */
195 
196 static CNTLR_TYPE ms_ctype  = A13181;           /* ctrl type */
197 static int32      ms_timing = 1;                /* timing type */
198 
199 static int32 msc_sta = 0;                       /* status */
200 static int32 msc_buf = 0;                       /* buffer */
201 static int32 msc_usl = 0;                       /* unit select */
202 static int32 msc_1st = 0;                       /* first service */
203 
204 static int32    msd_buf = 0;                    /* data buffer */
205 static uint8    msxb [DBSIZE] = { 0 };          /* data buffer */
206 static t_mtrlnt ms_ptr = 0;                     /* buffer ptrs */
207 static t_mtrlnt ms_max = 0;                     /* buffer ptrs */
208 static t_bool   ms_crc = FALSE;                 /* buffer ready for CRC calc */
209 
210 
211 /* Hardware timing at 45 IPS                  13181                  13183
212    (based on 1580 instr/msec)          instr   msec    SCP   instr    msec    SCP
213                                       --------------------   --------------------
214    - BOT start delay        : btime = 161512  102.22   184   252800  160.00   288
215    - motion cmd start delay : ctime =  14044    8.89    16    17556   11.11    20
216    - GAP traversal time     : gtime = 175553  111.11   200   105333   66.67   120
217    - IRG traversal time     : itime =  24885   15.75     -    27387   17.33     -
218    - rewind initiation time : rtime =    878    0.56     1      878    0.56     1
219    - data xfer time / word  : xtime =     88   55.56us   -       44  27.78us    -
220 
221    NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with
222          "E116 BYTE TIME SHORT" if the correct data transfer time is used for
223           13181A interface.  Set "xtime" to 115 (instructions) to pass that
224           diagnostic.  Rev. 2040 of the tape diagnostic fixes this problem and
225           passes with the correct data transfer time.
226 */
227 
228 static int32 msc_btime = 0;                     /* BOT start delay */
229 static int32 msc_ctime = 0;                     /* motion cmd start delay */
230 static int32 msc_gtime = 0;                     /* GAP traversal time */
231 static int32 msc_itime = 0;                     /* IRG traversal time */
232 static int32 msc_rtime = 0;                     /* rewind initiation time */
233 static int32 msc_xtime = 0;                     /* data xfer time / word */
234 
235 typedef int32 TIMESET[6];                       /* set of controller times */
236 
237 static int32 * const timers [] = { &msc_btime, &msc_ctime, &msc_gtime,
238                                    &msc_itime, &msc_rtime, &msc_xtime };
239 
240 static const TIMESET msc_times [3] = {
241     { 161512, 14044, 175553, 24885, 878,  88 },         /* 13181B */
242     { 252800, 17556, 105333, 27387, 878,  44 },         /* 13183B */
243     {      1,  1000,      1,     1, 100,  10 }          /* FAST */
244     };
245 
246 static INTERFACE msd_interface;
247 static INTERFACE msc_interface;
248 
249 static t_stat msc_svc (UNIT *uptr);
250 static t_stat ms_reset (DEVICE *dptr);
251 static t_stat msc_attach (UNIT *uptr, char *cptr);
252 static t_stat msc_detach (UNIT *uptr);
253 static t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc);
254 static t_stat msc_boot (int32 unitno, DEVICE *dptr);
255 static t_stat ms_write_gap (UNIT *uptr);
256 static t_stat ms_map_err (UNIT *uptr, t_stat st);
257 static t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
258 static t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
259 static t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc);
260 static t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);
261 static t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc);
262 static t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc);
263 static void ms_config_timing (void);
264 static char *ms_cmd_name (uint32 cmd);
265 static t_stat ms_clear (void);
266 static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length);
267 
268 
269 /* Device information blocks */
270 
271 static DIB ms_dib [] = {
272     { &msd_interface,                                                       /* the device's I/O interface function pointer */
273       MSD,                                                                  /* the device's select code (02-77) */
274       0,                                                                    /* the card index */
275       "13181B/13183B Digital Magnetic Tape Unit Interface Data Channel",    /* the card description */
276       NULL },                                                               /* the ROM description */
277 
278     { &msc_interface,                                                       /* the device's I/O interface function pointer */
279       MSC,                                                                  /* the device's select code (02-77) */
280       0,                                                                    /* the card index */
281       "13181B/13183B Digital Magnetic Tape Unit Interface Command Channel", /* the card description */
282       "12992D 7970 Magnetic Tape Loader" }                                  /* the ROM description */
283     };
284 
285 #define msd_dib             ms_dib [0]
286 #define msc_dib             ms_dib [1]
287 
288 
289 /* Data card SCP data structures */
290 
291 
292 /* Unit list */
293 
294 static UNIT msd_unit [] = {
295 /*           Event Routine  Unit Flags  Capacity  Delay */
296 /*           -------------  ----------  --------  ----- */
297     { UDATA (NULL,              0,          0)          }
298     };
299 
300 
301 /* Register list */
302 
303 static REG msd_reg [] = {
304     { ORDATA (BUF, msd_buf, 16) },
305     { FLDATA (CTL, msd.control, 0) },
306     { FLDATA (FLG, msd.flag, 0) },
307     { FLDATA (FBF, msd.flag_buffer, 0) },
308     { BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
309     { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
310     { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
311 
312       DIB_REGS (msd_dib),
313 
314     { NULL }
315     };
316 
317 
318 /* Modifier list */
319 
320 static MTAB msd_mod [] = {
321 /*    Entry Flags          Value  Print String  Match String  Validation    Display        Descriptor       */
322 /*    -------------------  -----  ------------  ------------  ------------  -------------  ---------------- */
323     { MTAB_XDV,              2u,  "SC",         "SC",         &hp_set_dib,  &hp_show_dib,  (void *) &ms_dib },
324     { MTAB_XDV | MTAB_NMO,  ~2u,  "DEVNO",      "DEVNO",      &hp_set_dib,  &hp_show_dib,  (void *) &ms_dib },
325     { 0 }
326     };
327 
328 
329 /* Debugging trace list */
330 
331 static DEBTAB msd_deb [] = {
332     { "IOBUS", TRACE_IOBUS },                   /* interface I/O bus signals and data words */
333     { NULL,    0           }
334     };
335 
336 
337 /* Device descriptor */
338 
339 DEVICE msd_dev = {
340     "MSD",                                      /* device name */
341     msd_unit,                                   /* unit array */
342     msd_reg,                                    /* register array */
343     msd_mod,                                    /* modifier array */
344     1,                                          /* number of units */
345     10,                                         /* address radix */
346     DB_N_SIZE,                                  /* address width */
347     1,                                          /* address increment */
348     8,                                          /* data radix */
349     8,                                          /* data width */
350     NULL,                                       /* examine routine */
351     NULL,                                       /* deposit routine */
352     &ms_reset,                                  /* reset routine */
353     NULL,                                       /* boot routine */
354     NULL,                                       /* attach routine */
355     NULL,                                       /* detach routine */
356     &msd_dib,                                   /* device information block pointer */
357     DEV_DISABLE | DEV_DEBUG,                    /* device flags */
358     0,                                          /* debug control flags */
359     msd_deb,                                    /* debug flag name array */
360     NULL,                                       /* memory size change routine */
361     NULL                                        /* logical device name */
362     };
363 
364 
365 /* Command card SCP data structures */
366 
367 
368 /* Unit list */
369 
370 #define UNIT_FLAGS          (UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_OFFLINE)
371 
372 static UNIT msc_unit [] = {
373 /*           Event Routine  Unit Flags  Capacity  Delay */
374 /*           -------------  ----------  --------  ----- */
375     { UDATA (&msc_svc,      UNIT_FLAGS,    0)           },
376     { UDATA (&msc_svc,      UNIT_FLAGS,    0)           },
377     { UDATA (&msc_svc,      UNIT_FLAGS,    0)           },
378     { UDATA (&msc_svc,      UNIT_FLAGS,    0)           }
379     };
380 
381 
382 /* Register list */
383 
384 static REG msc_reg [] = {
385     { ORDATA (STA, msc_sta, 12) },
386     { ORDATA (BUF, msc_buf, 16) },
387     { ORDATA (USEL, msc_usl, 2) },
388     { FLDATA (FSVC, msc_1st, 0) },
389     { FLDATA (CTL, msc.control, 0) },
390     { FLDATA (FLG, msc.flag, 0) },
391     { FLDATA (FBF, msc.flag_buffer, 0) },
392     { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) },
393     { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) },
394     { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) },
395     { URDATA (REEL, msc_unit[0].REEL, 10, 2, 0, MS_NUMDR, REG_HRO) },
396     { DRDATA (BTIME, msc_btime, 24), REG_NZ + PV_LEFT },
397     { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT },
398     { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT },
399     { DRDATA (ITIME, msc_itime, 24), REG_NZ + PV_LEFT },
400     { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT },
401     { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT },
402     { FLDATA (TIMING, ms_timing, 0), REG_HRO },
403     { FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
404 
405       DIB_REGS (msc_dib),
406 
407     { NULL }
408     };
409 
410 
411 /* Modifier list.
412 
413    The LOCKED and WRITEENABLED modifiers are deprecated.  The supported method
414    of write-protecting a tape drive is to attach the tape image with the -R
415    (read-only) switch or by setting the host operating system's read-only
416    attribute on the tape image file.  This simulates removing the write ring
417    from the tape reel before mounting it on the drive.  There is no hardware
418    method of write-protecting a mounted and positioned tape reel.
419 
420 
421    Implementation notes:
422 
423     1. The UNIT_RO modifier displays "write ring" if the flag is not set.  There
424        is no corresponding entry for the opposite condition because "read only"
425        is automatically printed after the attached filename.
426 */
427 
428 static MTAB msc_mod [] = {
429 /*    Mask Value     Match Value    Print String      Match String     Validation    Display  Descriptor */
430 /*    -------------  -------------  ----------------  ---------------  ------------  -------  ---------- */
431     { UNIT_RO,       0,             "write ring",     NULL,            NULL,         NULL,    NULL       },
432 
433     { UNIT_OFFLINE,  UNIT_OFFLINE,  "offline",        "OFFLINE",       NULL,         NULL,    NULL       },
434     { UNIT_OFFLINE,  0,             "online",         "ONLINE",        &msc_online,  NULL,    NULL       },
435 
436     { MTUF_WLK,      0,             NULL,             "WRITEENABLED",  NULL,         NULL,    NULL       },
437     { MTUF_WLK,      MTUF_WLK,      NULL,             "LOCKED",        NULL,         NULL,    NULL       },
438 
439 
440 /*    Entry Flags          Value  Print String  Match String  Validation         Display             Descriptor       */
441 /*    -------------------  -----  ------------  ------------  -----------------  ------------------  ---------------- */
442     { MTAB_XUN,              0,   "CAPACITY",   "CAPACITY",   &ms_set_reelsize,  &ms_show_reelsize,  NULL             },
443     { MTAB_XUN | MTAB_NMO,   1,   "REEL",       "REEL",       &ms_set_reelsize,  &ms_show_reelsize,  NULL             },
444     { MTAB_XUN,              0,   "FORMAT",     "FORMAT",     &sim_tape_set_fmt, &sim_tape_show_fmt, NULL             },
445 
446     { MTAB_XDV,              0,   NULL,         "13181A/B",   &ms_settype,       NULL,               NULL             },
447     { MTAB_XDV,              1,   NULL,         "13183A/B",   &ms_settype,       NULL,               NULL             },
448     { MTAB_XDV,              0,   "TYPE",       NULL,         NULL,              &ms_showtype,       NULL             },
449 
450     { MTAB_XDV,              0,   NULL,         "REALTIME",   &ms_set_timing,    NULL,               NULL             },
451     { MTAB_XDV,              1,   NULL,         "FASTTIME",   &ms_set_timing,    NULL,               NULL             },
452     { MTAB_XDV,              0,   "TIMING",     NULL,         NULL,              &ms_show_timing,    NULL             },
453 
454     { MTAB_XDV,              2u,  "SC",         "SC",         &hp_set_dib,       &hp_show_dib,       (void *) &ms_dib },
455     { MTAB_XDV | MTAB_NMO,  ~2u,  "DEVNO",      "DEVNO",      &hp_set_dib,       &hp_show_dib,       (void *) &ms_dib },
456 
457     { 0 }
458     };
459 
460 
461 /* Debugging trace list */
462 
463 static DEBTAB msc_deb [] = {
464     { "CMDS",  DEB_CMDS    },
465     { "RWS",   DEB_RWS     },
466     { "CPU",   DEB_CPU     },
467     { "IOBUS", TRACE_IOBUS },                   /* interface I/O bus signals and data words */
468     { NULL,    0           }
469     };
470 
471 
472 /* Device descriptor */
473 
474 DEVICE msc_dev = {
475     "MSC",                                      /* device name */
476     msc_unit,                                   /* unit array */
477     msc_reg,                                    /* register array */
478     msc_mod,                                    /* modifier array */
479     MS_NUMDR,                                   /* number of units */
480     10,                                         /* address radix */
481     31,                                         /* address width */
482     1,                                          /* address increment */
483     8,                                          /* data radix */
484     8,                                          /* data width */
485     NULL,                                       /* examine routine */
486     NULL,                                       /* deposit routine */
487     &ms_reset,                                  /* reset routine */
488     &msc_boot,                                  /* boot routine */
489     &msc_attach,                                /* attach routine */
490     &msc_detach,                                /* detach routine */
491     &msc_dib,                                   /* device information block pointer */
492     DEV_DISABLE | DEV_DEBUG,                    /* device flags */
493     0,                                          /* debug control flags */
494     msc_deb,                                    /* debug flag name array */
495     NULL,                                       /* memory size change routine */
496     NULL                                        /* logical device name */
497     };
498 
499 
500 
501 /* Data channel interface */
502 
msd_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)503 static SIGNALS_VALUE msd_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
504 {
505 INBOUND_SIGNAL signal;
506 INBOUND_SET    working_set = inbound_signals;
507 SIGNALS_VALUE  outbound    = { ioNONE, 0 };
508 t_bool         irq_enabled = FALSE;
509 uint32         check;
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             msd.flag_buffer = CLEAR;                    /* reset the flag buffer */
518             msd.flag        = CLEAR;                    /*   and flag flip-flops */
519             break;
520 
521 
522         case ioSTF:                                     /* Set Flag flip-flop */
523             msd.flag_buffer = SET;                      /* set the flag buffer flip-flop */
524             break;
525 
526 
527         case ioENF:                                     /* Enable Flag */
528             if (msd.flag_buffer == SET)                 /* if the flag buffer flip-flop is set */
529                 msd.flag = SET;                         /*   then set the flag flip-flop */
530             break;
531 
532 
533         case ioSFC:                                     /* Skip if Flag is Clear */
534             if (msd.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 (msd.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             if (ms_crc) {                               /* ready for CRC? */
547                 check = calc_crc_lrc (msxb, ms_max);    /* calculate CRCC and LRCC */
548 
549                 msd_buf = TO_WORD (UPPER_WORD (check),  /* position CRCC in upper byte */
550                                    check);              /*   and LRCC in lower byte */
551                 }
552 
553             outbound.value = msd_buf;                   /* return value */
554             break;
555 
556 
557         case ioIOO:                                     /* I/O data output */
558             msd_buf = inbound_value;                    /* store data */
559             break;
560 
561 
562         case ioPOPIO:                                   /* Power-On Preset to I/O */
563             ms_clear ();                                /* issue CLR to controller */
564             break;
565 
566 
567         case ioCRS:                                     /* Control Reset */
568             msd.control     = CLEAR;                    /* clear the control flip-flop */
569             msd.flag_buffer = SET;                      /*   and set the flag buffer flip-flop */
570             break;
571 
572 
573         case ioCLC:                                     /* Clear Control flip-flop */
574             msd.control = CLEAR;                        /* clear the control flip-flop */
575             break;
576 
577 
578         case ioSTC:                                     /* Set Control flip-flop */
579             msd.control = SET;                          /* set the control flip-flop */
580             ms_crc = FALSE;                             /* reset CRC ready */
581             break;
582 
583 
584         case ioSIR:                                     /* Set Interrupt Request */
585             if (msd.control & msd.flag)                 /* if the control and flag flip-flops are set */
586                 outbound.signals |= cnVALID;            /*   then deny PRL */
587             else                                        /* otherwise */
588                 outbound.signals |= cnPRL | cnVALID;    /*   conditionally assert PRL */
589 
590             if (msd.control & msd.flag & msd.flag_buffer)   /* if the control, flag, and flag buffer flip-flops are set */
591                 outbound.signals |= cnIRQ | cnVALID;        /*   then conditionally assert IRQ */
592 
593             if (msd.flag == SET)                        /* if the flag flip-flop is set */
594                 outbound.signals |= ioSRQ;              /*   then assert SRQ */
595             break;
596 
597 
598         case ioIAK:                                     /* Interrupt Acknowledge */
599             msd.flag_buffer = CLEAR;                    /* clear the flag buffer flip-flop */
600             break;
601 
602 
603         case ioEDT:                                     /* End Data Transfer */
604             msd.flag_buffer = CLEAR;                    /* reset the flag buffer */
605             msd.flag        = CLEAR;                    /*   and flag flip-flops */
606             break;
607 
608 
609         case ioIEN:                                     /* Interrupt Enable */
610             irq_enabled = TRUE;                         /* permit IRQ to be asserted */
611             break;
612 
613 
614         case ioPRH:                                         /* Priority High */
615             if (irq_enabled && outbound.signals & cnIRQ)    /* if IRQ is enabled and conditionally asserted */
616                 outbound.signals |= ioIRQ | ioFLG;          /*   then assert IRQ and FLG */
617 
618             if (!irq_enabled || outbound.signals & cnPRL)   /* if IRQ is disabled or PRL is conditionally asserted */
619                 outbound.signals |= ioPRL;                  /*   then assert it unconditionally */
620             break;
621 
622 
623         case ioPON:                                     /* not used by this interface */
624             break;
625         }
626 
627     IOCLEARSIG (working_set, signal);                   /* remove the current signal from the set */
628     }                                                   /*   and continue until all signals are processed */
629 
630 return outbound;                                        /* return the outbound signals and value */
631 }
632 
633 
634 /* Command channel interface.
635 
636    Implementation notes:
637 
638     1. Commands are usually initiated with an STC cc,C instruction.  The CLR
639        command completes immediately and sets the flag.  This requires that we
640        ignore the CLF part (but still process the SIR).
641 
642     2. The command channel card clears its flag and flag buffer on EDT, but as
643        it never asserts SRQ, it will never get EDT.  Under simulation, we omit
644        the EDT handler.
645 
646     3. In hardware, the command channel card passes PRH to PRL.  The data card
647        actually drives PRL with both channels' control and flag states.  That
648        is, the priority chain is broken at the data card, even when the command
649        card is interrupting.  This works in hardware, but we must break PRL at
650        the command card under simulation to allow the command card to interrupt.
651 */
652 
msc_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)653 static SIGNALS_VALUE msc_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
654 {
655 static const uint8 map_sel [16] = {
656     0, 0, 1, 1, 2, 2, 2, 2,
657     3, 3, 3, 3, 3, 3, 3, 3
658     };
659 int32          sched_time;
660 UNIT           *uptr = msc_dev.units + msc_usl;
661 INBOUND_SIGNAL signal;
662 INBOUND_SET    working_set = inbound_signals;
663 SIGNALS_VALUE  outbound    = { ioNONE, 0 };
664 t_bool         irq_enabled = FALSE;
665 
666 while (working_set) {                                   /* while signals remain */
667     signal = IONEXTSIG (working_set);                   /*   isolate the next signal */
668 
669     switch (signal) {                                   /* dispatch the I/O signal */
670 
671         case ioCLF:                                     /* Clear Flag flip-flop */
672             msc.flag_buffer = CLEAR;                    /* reset the flag buffer */
673             msc.flag        = CLEAR;                    /*   and flag flip-flops */
674             break;
675 
676 
677         case ioSTF:                                     /* Set Flag flip-flop */
678             msc.flag_buffer = SET;                      /* set the flag buffer flip-flop */
679             break;
680 
681 
682         case ioENF:                                     /* Enable Flag */
683             if (msc.flag_buffer == SET)                 /* if the flag buffer flip-flop is set */
684                 msc.flag = SET;                         /*   then set the flag flip-flop */
685             break;
686 
687 
688         case ioSFC:                                     /* Skip if Flag is Clear */
689             if (msc.flag == CLEAR)                      /* if the flag flip-flop is clear */
690                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
691             break;
692 
693 
694         case ioSFS:                                     /* Skip if Flag is Set */
695             if (msc.flag == SET)                        /* if the flag flip-flop is set */
696                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
697             break;
698 
699 
700         case ioIOI:                                         /* I/O data input */
701             outbound.value = (HP_WORD) msc_sta & ~STA_DYN;  /* get card status */
702 
703             if ((uptr->flags & UNIT_OFFLINE) == 0) {    /* online? */
704                 outbound.value |= (HP_WORD) uptr->UST;  /* add unit status */
705 
706                 if (sim_tape_bot (uptr))                /* BOT? */
707                     outbound.value |= STA_BOT;
708 
709                 if (sim_is_active (uptr) &&             /* TBSY unless RWD at BOT */
710                     !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr)))
711                     outbound.value |= STA_TBSY;
712 
713                 if (sim_tape_wrp (uptr))                /* write prot? */
714                     outbound.value |= STA_WLK;
715 
716                 if (sim_tape_eot (uptr))                /* EOT? */
717                     outbound.value |= STA_EOT;
718                 }
719 
720             else
721                 outbound.value |= STA_TBSY | STA_LOCAL;
722 
723             if (ms_ctype == A13183)                     /* 13183? */
724                 outbound.value |= STA_PE | (HP_WORD) msc_usl << STA_V_SEL;
725 
726             tprintf (msc_dev, DEB_CPU, "Status = %06o\n", outbound.value);
727             break;
728 
729 
730         case ioIOO:                                         /* I/O data output */
731             msc_buf = inbound_value;                        /* clear supplied status */
732 
733             tprintf (msc_dev, DEB_CPU, "Command = %06o\n", msc_buf);
734 
735             msc_sta = msc_sta & ~STA_REJ;                   /* clear reject */
736 
737             if ((msc_buf & 0377) == FNC_CLR)                /* clear always ok */
738                 break;
739 
740             if (msc_sta & STA_BUSY) {                       /* busy? reject */
741                 msc_sta = msc_sta | STA_REJ;                /* dont chg select */
742                 break;
743                 }
744 
745             if (msc_buf & FNF_CHS) {                        /* select change */
746                 msc_usl = map_sel [FNC_GETSEL (msc_buf)];   /* is immediate */
747                 uptr = msc_dev.units + msc_usl;
748                 tprintf (msc_dev, DEB_CMDS, "Unit %d selected\n", msc_usl);
749                 }
750 
751             if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) ||
752                 ((msc_buf & FNF_REV) && sim_tape_bot (uptr)) ||
753                 ((msc_buf & FNF_WRT) && sim_tape_wrp (uptr)))
754                 msc_sta = msc_sta | STA_REJ;                /* reject? */
755             break;
756 
757 
758         case ioCRS:                                     /* Control Reset */
759             msc.control     = CLEAR;                    /* clear the control flip-flop */
760             msc.flag_buffer = SET;                      /*   and set the flag buffer flip-flop */
761             break;
762 
763 
764         case ioCLC:                                     /* Clear Control flip-flop */
765             msc.control = CLEAR;                        /* clear the control flip-flop */
766             break;
767 
768 
769         case ioSTC:                                     /* Set Control flip-flop */
770             if (!(msc_sta & STA_REJ)) {                 /* last cmd rejected? */
771                 if ((msc_buf & 0377) == FNC_CLR) {      /* clear? */
772                     ms_clear ();                        /* issue CLR to controller */
773 
774                     msc.control     = SET;              /* set CTL for STC */
775                     msc.flag_buffer = SET;              /* set flag and flag buffer */
776                     msc.flag        = SET;              /*   for immediate completion */
777 
778                     working_set = working_set & ~ioCLF; /* eliminate possible CLF */
779 
780                     tprintf (msc_dev, DEB_CMDS, "Controller cleared\n");
781 
782                     break;                              /* command completes immediately */
783                     }
784 
785                 uptr->FNC = msc_buf & 0377;             /* save function */
786 
787                 if (uptr->FNC & FNF_RWD) {              /* rewind? */
788                     if (!sim_tape_bot (uptr))           /* not at BOT? */
789                         uptr->UST = STA_REW;            /* set rewinding */
790 
791                     sched_time = msc_rtime;             /* set response time */
792                     }
793 
794                 else {
795                     if (sim_tape_bot (uptr))            /* at BOT? */
796                         sched_time = msc_btime;         /* use BOT start time */
797 
798                     else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM))
799                         sched_time = msc_gtime;         /* use gap traversal time */
800 
801                     else sched_time = 0;
802 
803                     if (uptr->FNC != FNC_GAP)
804                         sched_time += msc_ctime;        /* add base command time */
805                     }
806 
807                 if (msc_buf & ~FNC_SEL) {               /* NOP for unit sel alone */
808                     sim_activate (uptr, sched_time);    /* else schedule op */
809 
810                     tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o (%s) scheduled, "
811                                                 "pos = %" T_ADDR_FMT "d, time = %d\n",
812                              msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
813                              uptr->pos, sched_time);
814                     }
815 
816                 else
817                     tprintf (msc_dev, DEB_CMDS, "Unit select (NOP)\n");
818 
819                 msc_sta = STA_BUSY;                     /* ctrl is busy */
820                 msc_1st = 1;
821                 msc.control = SET;                      /* go */
822                 }
823             break;
824 
825 
826         case ioSIR:                                     /* Set Interrupt Request */
827             if (msc.control & msc.flag)                 /* if the control and flag flip-flops are set */
828                 outbound.signals |= cnVALID;            /*   then deny PRL */
829             else                                        /* otherwise */
830                 outbound.signals |= cnPRL | cnVALID;    /*   conditionally assert PRL */
831 
832             if (msc.control & msc.flag & msc.flag_buffer)   /* if the control, flag, and flag buffer flip-flops are set */
833                 outbound.signals |= cnIRQ | cnVALID;        /*   then conditionally assert IRQ */
834 
835             if (msc.flag == SET)                        /* if the flag flip-flop is set */
836                 outbound.signals |= ioSRQ;              /*   then assert SRQ */
837             break;
838 
839 
840         case ioIAK:                                     /* Interrupt Acknowledge */
841             msc.flag_buffer = CLEAR;                    /* clear the flag buffer flip-flop */
842             break;
843 
844 
845         case ioIEN:                                     /* Interrupt Enable */
846             irq_enabled = TRUE;                         /* permit IRQ to be asserted */
847             break;
848 
849 
850         case ioPRH:                                         /* Priority High */
851             if (irq_enabled && outbound.signals & cnIRQ)    /* if IRQ is enabled and conditionally asserted */
852                 outbound.signals |= ioIRQ | ioFLG;          /*   then assert IRQ and FLG */
853 
854             if (!irq_enabled || outbound.signals & cnPRL)   /* if IRQ is disabled or PRL is conditionally asserted */
855                 outbound.signals |= ioPRL;                  /*   then assert it unconditionally */
856             break;
857 
858 
859         case ioEDT:                                     /* not used by this interface */
860         case ioPON:                                     /* not used by this interface */
861         case ioPOPIO:                                   /* not used by this interface */
862             break;
863         }
864 
865     IOCLEARSIG (working_set, signal);                   /* remove the current signal from the set */
866     }                                                   /*   and continue until all signals are processed */
867 
868 return outbound;                                        /* return the outbound signals and value */
869 }
870 
871 
872 /* Unit service
873 
874    If rewind done, reposition to start of tape, set status
875    else, do operation, set done, interrupt.
876 
877    In addition to decreasing the timing intervals, the FASTTIME option enables
878    two additional optimizations: WFM for GFM substitution, and BOT gap
879    elimination.  If FASTTIME is selected, gap and file mark (GFM) commands are
880    processed as WFM (write file mark) commands.  That is, the preceding GAP is
881    not performed.  Also, the initial gap that normally precedes the first data
882    record or EOF mark at the beginning of the tape is omitted.  These omissions
883    result in smaller tape image files.  If REALTIME is selected, the gaps are
884    included.  Note that the gaps (and realistic timing) are necessary to pass
885    the 7970 diagnostics.
886 */
887 
msc_svc(UNIT * uptr)888 static t_stat msc_svc (UNIT *uptr)
889 {
890 int32 unum;
891 t_mtrlnt tbc;
892 t_stat st, r = SCPE_OK;
893 
894 unum = uptr - msc_unit;                                 /* get unit number */
895 
896 if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) {  /* offline? */
897     msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY;          /* reject */
898 
899     msc.flag_buffer = SET;                              /* set the flag buffer */
900     io_assert (&msc_dev, ioa_ENF);                      /*   and the flag */
901     return SCPE_OK;
902     }
903 
904 switch (uptr->FNC) {                                    /* case on function */
905 
906     case FNC_RWS:                                       /* rewind offline */
907         sim_tape_rewind (uptr);                         /* rewind tape */
908         uptr->flags = uptr->flags | UNIT_OFFLINE;       /* set offline */
909         uptr->UST = 0;                                  /* clear REW status */
910         break;                                          /* we're done */
911 
912     case FNC_REW:                                       /* rewind */
913         if (uptr->UST & STA_REW) {                      /* rewind in prog? */
914             uptr->FNC |= FNC_CMPL;                      /* set compl state */
915             sim_activate (uptr, msc_ctime);             /* sched completion */
916             }
917         break;                                          /* anyway, ctrl done */
918 
919     case FNC_REW | FNC_CMPL:                            /* complete rewind */
920         sim_tape_rewind (uptr);                         /* rewind tape */
921         uptr->UST = 0;                                  /* clear REW status */
922         return SCPE_OK;                                 /* drive is free */
923 
924     case FNC_GFM:                                       /* gap + file mark */
925         if (ms_timing == 1)                             /* fast timing? */
926             goto DO_WFM;                                /* do plain file mark */
927 
928     /* fall through into GAP */
929 
930     case FNC_GAP:                                       /* erase gap */
931         tprintf (msc_dev, DEB_RWS, "Unit %d wrote gap\n", unum);
932 
933         r = ms_write_gap (uptr);                        /* write tape gap*/
934 
935         if (r || (uptr->FNC != FNC_GFM))                /* if error or not GFM */
936             break;                                      /*   then bail out now */
937 
938     /* fall through into WFM */
939 
940     case FNC_WFM:                                       /* write file mark */
941         if ((ms_timing == 0) && sim_tape_bot (uptr)) {  /* realistic timing + BOT? */
942             tprintf (msc_dev, DEB_RWS, "Unit %d wrote initial gap\n", unum);
943 
944             st = ms_write_gap (uptr);                   /* write initial gap*/
945             if (st != MTSE_OK) {                        /* error? */
946                 r = ms_map_err (uptr, st);              /* map error */
947                 break;                                  /* terminate operation */
948                 }
949             }
950     DO_WFM:
951         tprintf (msc_dev, DEB_RWS, "Unit %d wrote file mark\n", unum);
952 
953         st = sim_tape_wrtmk (uptr);                     /* write tmk */
954         if (st != MTSE_OK)                              /* error? */
955             r = ms_map_err (uptr, st);                  /* map error */
956         msc_sta = STA_EOF;                              /* set EOF status */
957         break;
958 
959     case FNC_FSR:                                       /* space forward */
960         st = sim_tape_sprecf (uptr, &tbc);              /* space rec fwd */
961         if (st != MTSE_OK)                              /* error? */
962             r = ms_map_err (uptr, st);                  /* map error */
963         if (tbc & 1)
964             msc_sta = msc_sta | STA_ODD;
965         else msc_sta = msc_sta & ~STA_ODD;
966         break;
967 
968     case FNC_BSR:                                       /* space reverse */
969         st = sim_tape_sprecr (uptr, &tbc);              /* space rec rev*/
970         if (st != MTSE_OK)                              /* error? */
971             r = ms_map_err (uptr, st);                  /* map error */
972         if (tbc & 1)
973             msc_sta = msc_sta | STA_ODD;
974         else msc_sta = msc_sta & ~STA_ODD;
975         break;
976 
977     case FNC_FSF:                                       /* space fwd file */
978         while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) {
979             if (sim_tape_eot (uptr)) break;             /* EOT stops */
980             }
981         r = ms_map_err (uptr, st);                      /* map error */
982         break;
983 
984     case FNC_BSF:                                       /* space rev file */
985         while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
986         r = ms_map_err (uptr, st);                      /* map error */
987         break;
988 
989     case FNC_RFF:                                       /* diagnostic read */
990     case FNC_RC:                                        /* read */
991         if (msc_1st) {                                  /* first svc? */
992             msc_1st = ms_ptr = ms_max = 0;              /* clr 1st flop */
993             st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
994             tprintf (msc_dev, DEB_RWS, "Unit %d read %d word record\n",
995                      unum, ms_max / 2);
996             if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR;   /* rec in err? */
997             else if (st != MTSE_OK) {                   /* other error? */
998                 r = ms_map_err (uptr, st);              /* map error */
999                 if (r == SCPE_OK) {                     /* recoverable? */
1000                     sim_activate (uptr, msc_itime);     /* sched IRG */
1001                     uptr->FNC |= FNC_CMPL;              /* set completion */
1002                     return SCPE_OK;
1003                     }
1004                 break;                                  /* err, done */
1005                 }
1006             if (ms_ctype == A13183)
1007                 msc_sta = msc_sta | STA_ODD;            /* set ODD for 13183 */
1008             }
1009         if (msd.control && (ms_ptr < ms_max)) {         /* DCH on, more data? */
1010             if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR;
1011             msd_buf = ((uint16) msxb[ms_ptr] << 8) |
1012                       ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]);
1013             ms_ptr = ms_ptr + 2;
1014 
1015             msd.flag_buffer = SET;                      /* set the flag buffer */
1016             io_assert (&msd_dev, ioa_ENF);              /*   and the flag */
1017 
1018             sim_activate (uptr, msc_xtime);             /* re-activate */
1019             return SCPE_OK;
1020             }
1021         if (ms_max & 1)                                 /* set ODD by rec len */
1022             msc_sta = msc_sta | STA_ODD;
1023         else msc_sta = msc_sta & ~STA_ODD;
1024         sim_activate (uptr, msc_itime);                 /* sched IRG */
1025         if (uptr->FNC == FNC_RFF)                       /* diagnostic? */
1026             msc_1st = 1;                                /* restart */
1027         else {
1028             uptr->FNC |= FNC_CMPL;                      /* set completion */
1029             ms_crc = TRUE;                              /*   and CRC ready */
1030             }
1031         return SCPE_OK;
1032 
1033     case FNC_RFF | FNC_CMPL:                            /* diagnostic read completion */
1034     case FNC_RC  | FNC_CMPL:                            /* read completion */
1035         break;
1036 
1037     case FNC_WC:                                        /* write */
1038         if (msc_1st) {                                  /* first service? */
1039             msc_1st = ms_ptr = 0;                       /* no data xfer on first svc */
1040             if ((ms_timing == 0) && sim_tape_bot (uptr)) {  /* realistic timing + BOT? */
1041                 tprintf (msc_dev, DEB_RWS, "Unit %d wrote initial gap\n", unum);
1042 
1043                 st = ms_write_gap (uptr);               /* write initial gap */
1044                 if (st != MTSE_OK) {                    /* error? */
1045                     r = ms_map_err (uptr, st);          /* map error */
1046                     break;                              /* terminate operation */
1047                     }
1048                 }
1049             }
1050         else {                                          /* not 1st, next char */
1051             if (ms_ptr < DBSIZE) {                      /* room in buffer? */
1052                 msxb[ms_ptr] = (uint8) (msd_buf >> 8);  /* store 2 char */
1053                 msxb[ms_ptr + 1] = msd_buf & 0377;
1054                 ms_ptr = ms_ptr + 2;
1055                 }
1056             else msc_sta = msc_sta | STA_PAR;
1057            }
1058         if (msd.control) {                              /* xfer flop set? */
1059             msd.flag_buffer = SET;                      /* set the flag buffer */
1060             io_assert (&msd_dev, ioa_ENF);              /*   and the flag */
1061 
1062             sim_activate (uptr, msc_xtime);             /* re-activate */
1063             return SCPE_OK;
1064             }
1065         if (ms_ptr) {                                   /* any data? write */
1066             tprintf (msc_dev, DEB_RWS, "Unit %d wrote %d word record\n",
1067                      unum, ms_ptr / 2);
1068             st = sim_tape_wrrecf (uptr, msxb, ms_ptr);  /* write */
1069             if (st != MTSE_OK) {
1070                 r = ms_map_err (uptr, st);              /* map error */
1071                 break;
1072                 }
1073             }
1074         sim_activate (uptr, msc_itime);                 /* sched IRG */
1075         uptr->FNC |= FNC_CMPL;                          /* set completion */
1076         ms_max = ms_ptr;                                /* indicate buffer complete */
1077         ms_crc = TRUE;                                  /*   and CRC may be generated */
1078         return SCPE_OK;
1079 
1080     case FNC_WC | FNC_CMPL:                             /* write completion */
1081         break;
1082 
1083     case FNC_RRR:                                       /* not supported */
1084     default:                                            /* unknown command */
1085         tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o is unknown (NOP)\n",
1086                  unum, uptr->FNC);
1087         break;
1088         }
1089 
1090 msc.flag_buffer = SET;                                  /* set the flag buffer */
1091 io_assert (&msc_dev, ioa_ENF);                          /*   and the flag */
1092 
1093 msc_sta = msc_sta & ~STA_BUSY;                          /* update status */
1094 
1095 tprintf (msc_dev, DEB_CMDS, "Unit %d command %03o (%s) complete\n",
1096          unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC));
1097 return r;
1098 }
1099 
1100 
1101 /* Write an erase gap */
1102 
ms_write_gap(UNIT * uptr)1103 static t_stat ms_write_gap (UNIT *uptr)
1104 {
1105 t_stat st;
1106 uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181;      /* establish gap length */
1107 
1108 st = sim_tape_wrgap (uptr, gap_len);                    /* write gap */
1109 
1110 if (st != MTSE_OK)
1111     return ms_map_err (uptr, st);                       /* map error if failure */
1112 else
1113     return SCPE_OK;
1114 }
1115 
1116 
1117 /* Map tape error status */
1118 
ms_map_err(UNIT * uptr,t_stat st)1119 static t_stat ms_map_err (UNIT *uptr, t_stat st)
1120 {
1121 int32 unum = uptr - msc_unit;                           /* get unit number */
1122 
1123 tprintf (msc_dev, DEB_RWS, "Unit %d tape library status = %d\n", unum, st);
1124 
1125 switch (st) {
1126 
1127     case MTSE_FMT:                                      /* illegal fmt */
1128         msc_sta = msc_sta | STA_REJ;                    /* reject cmd */
1129         return SCPE_FMT;                                /* format error */
1130 
1131     case MTSE_UNATT:                                    /* unattached */
1132         msc_detach (uptr);                              /* resync status (ignore rtn) */
1133         msc_sta = msc_sta | STA_REJ;                    /* reject cmd */
1134         return SCPE_UNATT;                              /* unit unattached */
1135 
1136     case MTSE_OK:                                       /* no error */
1137         return SCPE_IERR;                               /* never get here! */
1138 
1139     case MTSE_EOM:                                      /* end of medium */
1140     case MTSE_TMK:                                      /* end of file */
1141         msc_sta = msc_sta | STA_EOF;
1142 
1143         if (ms_ctype == A13181)
1144             msc_sta = msc_sta | STA_ODD;                /* EOF also sets ODD for 13181B */
1145         break;
1146 
1147     case MTSE_INVRL:                                    /* invalid rec lnt */
1148         msc_sta = msc_sta | STA_PAR;
1149         return SCPE_MTRLNT;
1150 
1151     case MTSE_IOERR:                                    /* IO error */
1152         msc_sta = msc_sta | STA_PAR;                    /* error */
1153         return SCPE_IOERR;
1154 
1155     case MTSE_RECE:                                     /* record in error */
1156         msc_sta = msc_sta | STA_PAR;                    /* error */
1157         break;
1158 
1159     case MTSE_WRP:                                      /* write protect */
1160         msc_sta = msc_sta | STA_REJ;                    /* reject */
1161         break;
1162         }
1163 
1164 return SCPE_OK;
1165 }
1166 
1167 
1168 /* Controller clear */
1169 
ms_clear(void)1170 static t_stat ms_clear (void)
1171 {
1172 int32 i;
1173 t_stat st;
1174 UNIT *uptr;
1175 
1176 for (i = 0; i < MS_NUMDR; i++) {                        /* look for write in progr */
1177     uptr = &msc_unit [i];                               /* get pointer to unit */
1178 
1179     if (sim_is_active (uptr) &&                         /* unit active? */
1180         (uptr->FNC == FNC_WC) &&                        /*   and last cmd write? */
1181         (ms_ptr > 0)) {                                 /*   and partial buffer? */
1182         tprintf (msc_dev, DEB_RWS, "Unit %d wrote %d word partial record\n", i, ms_ptr / 2);
1183 
1184         st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF);
1185 
1186         if (st != MTSE_OK)
1187             ms_map_err (uptr, st);                      /* discard any error */
1188 
1189         ms_ptr = 0;                                     /* clear partial */
1190         }
1191 
1192     if ((uptr->UST & STA_REW) == 0)
1193         sim_cancel (uptr);                              /* stop if not rew */
1194     }
1195 
1196 msc_sta = msc_1st = 0;                                  /* clr ctlr status */
1197 
1198 return SCPE_OK;
1199 }
1200 
1201 
1202 /* Reset routine */
1203 
ms_reset(DEVICE * dptr)1204 static t_stat ms_reset (DEVICE *dptr)
1205 {
1206 int32 i;
1207 UNIT *uptr;
1208 
1209 hp_enbdis_pair (dptr,                                   /* make pair cons */
1210     (dptr == &msd_dev) ? &msc_dev : &msd_dev);
1211 
1212 if (sim_switches & SWMASK ('P'))                        /* initialization reset? */
1213     ms_config_timing ();
1214 
1215 io_assert (dptr, ioa_POPIO);                            /* PRESET the device */
1216 
1217 msc_buf = msd_buf = 0;
1218 msc_sta = msc_usl = 0;
1219 msc_1st = 0;
1220 
1221 for (i = 0; i < MS_NUMDR; i++) {
1222     uptr = msc_dev.units + i;
1223     sim_tape_reset (uptr);
1224     sim_cancel (uptr);
1225     uptr->UST = 0;
1226 
1227     if (sim_switches & SWMASK ('P'))                    /* if this is an initialization reset */
1228         sim_tape_set_dens (uptr,                        /*   then tell the tape library the density in use */
1229                            ms_ctype ? BPI_13183 : BPI_13181,
1230                            NULL, NULL);
1231     }
1232 
1233 return SCPE_OK;
1234 }
1235 
1236 
1237 /* Attach routine */
1238 
msc_attach(UNIT * uptr,char * cptr)1239 static t_stat msc_attach (UNIT *uptr, char *cptr)
1240 {
1241 t_stat r;
1242 
1243 r = sim_tape_attach (uptr, cptr);                       /* attach unit */
1244 if (r == SCPE_OK)
1245     uptr->flags = uptr->flags & ~UNIT_OFFLINE;          /* set online */
1246 return r;
1247 }
1248 
1249 /* Detach routine */
1250 
msc_detach(UNIT * uptr)1251 static t_stat msc_detach (UNIT* uptr)
1252 {
1253 uptr->UST = 0;                                          /* clear status */
1254 uptr->flags = uptr->flags | UNIT_OFFLINE;               /* set offline */
1255 return sim_tape_detach (uptr);                          /* detach unit */
1256 }
1257 
1258 /* Online routine */
1259 
msc_online(UNIT * uptr,int32 value,char * cptr,void * desc)1260 static t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc)
1261 {
1262 if (uptr->flags & UNIT_ATT) return SCPE_OK;
1263 else return SCPE_UNATT;
1264 }
1265 
1266 /* Configure timing */
1267 
ms_config_timing(void)1268 static void ms_config_timing (void)
1269 {
1270 uint32 i, tset;
1271 
1272 tset = (ms_timing << 1) | (ms_timing ? 0 : ms_ctype);   /* select timing set */
1273 for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++)
1274     *timers[i] = msc_times[tset][i];                    /* assign times */
1275 }
1276 
1277 /* Set controller timing */
1278 
ms_set_timing(UNIT * uptr,int32 val,char * cptr,void * desc)1279 static t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc)
1280 {
1281 if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
1282 ms_timing = val;
1283 ms_config_timing ();
1284 return SCPE_OK;
1285 }
1286 
1287 /* Show controller timing */
1288 
ms_show_timing(FILE * st,UNIT * uptr,int32 val,void * desc)1289 static t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc)
1290 {
1291 if (ms_timing) fputs ("fast timing", st);
1292 else fputs ("realistic timing", st);
1293 return SCPE_OK;
1294 }
1295 
1296 /* Set controller type */
1297 
ms_settype(UNIT * uptr,int32 val,char * cptr,void * desc)1298 static t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
1299 {
1300 int32 i;
1301 
1302 if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
1303 for (i = 0; i < MS_NUMDR; i++) {
1304     if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT;
1305     }
1306 ms_ctype = (CNTLR_TYPE) val;
1307 ms_config_timing ();                                    /* update for new type */
1308 
1309 sim_tape_set_dens (uptr, ms_ctype ? BPI_13183 : BPI_13181,  /* tell the tape library the density in use */
1310                    NULL, NULL);
1311 
1312 return SCPE_OK;
1313 }
1314 
1315 /* Show controller type */
1316 
ms_showtype(FILE * st,UNIT * uptr,int32 val,void * desc)1317 static t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
1318 {
1319 if (ms_ctype == A13183)
1320     fprintf (st, "13183B");
1321 else
1322     fprintf (st, "13181B");
1323 return SCPE_OK;
1324 }
1325 
1326 /* Set unit reel size
1327 
1328    val = 0 -> SET MSCn CAPACITY=n
1329    val = 1 -> SET MSCn REEL=n */
1330 
ms_set_reelsize(UNIT * uptr,int32 val,char * cptr,void * desc)1331 static t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc)
1332 {
1333 int32 reel;
1334 t_stat status;
1335 
1336 if (val == 0) {
1337     status = sim_tape_set_capac (uptr, val, cptr, desc);
1338 
1339     if (status == SCPE_OK)
1340         uptr->REEL = 0;
1341 
1342     return status;
1343     }
1344 
1345 if (cptr == NULL)
1346     return SCPE_ARG;
1347 
1348 reel = (int32) get_uint (cptr, 10, 2400, &status);
1349 
1350 if (status != SCPE_OK)
1351     return status;
1352 else
1353     switch (reel) {
1354         case 0:
1355             uptr->REEL = 0;                             /* type 0 = unlimited/custom */
1356             break;
1357 
1358         case 600:
1359             uptr->REEL = 1;                             /* type 1 = 600 foot */
1360             break;
1361 
1362         case 1200:
1363             uptr->REEL = 2;                             /* type 2 = 1200 foot */
1364             break;
1365 
1366         case 2400:
1367             uptr->REEL = 3;                             /* type 3 = 2400 foot */
1368             break;
1369 
1370         default:
1371             return SCPE_ARG;
1372         }
1373 
1374 uptr->capac = uptr->REEL ? (TCAP << uptr->REEL) << ms_ctype : 0;
1375 return SCPE_OK;
1376 }
1377 
1378 /* Show unit reel size
1379 
1380    val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY
1381    val = 1 -> SHOW MSCn REEL */
1382 
ms_show_reelsize(FILE * st,UNIT * uptr,int32 val,void * desc)1383 static t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc)
1384 {
1385 t_stat status = SCPE_OK;
1386 
1387 if (uptr->REEL == 0)
1388     status = sim_tape_show_capac (st, uptr, val, desc);
1389 else
1390     fprintf (st, "%4d foot reel", 300 << uptr->REEL);
1391 
1392 if (val == 1)
1393     fputc ('\n', st);                         /* MTAB_NMO omits \n */
1394 
1395 return status;
1396 }
1397 
1398 /* Translate command to mnemonic for debug logging
1399 
1400    The command names and descriptions are taken from the 13181 interface
1401    manual.
1402 */
1403 
ms_cmd_name(uint32 cmd)1404 static char *ms_cmd_name (uint32 cmd)
1405 {
1406 switch (cmd & 0377) {
1407     case FNC_WC:  return "WCC";         /* Write command */
1408     case FNC_WFM: return "WFM";         /* Write file mark */
1409     case FNC_RC:  return "RRF";         /* Read record forward */
1410     case FNC_FSR: return "FSR";         /* Forward space record */
1411     case FNC_FSF: return "FSF";         /* Forward space file */
1412     case FNC_GAP: return "GAP";         /* Write gap */
1413     case FNC_BSR: return "BSR";         /* Backspace record */
1414     case FNC_BSF: return "BSF";         /* Backspace file */
1415     case FNC_REW: return "REW";         /* Rewind */
1416     case FNC_RWS: return "RWO";         /* Rewind off-line */
1417     case FNC_CLR: return "CLR";         /* Clear controller */
1418     case FNC_GFM: return "GFM";         /* Gap file mark */
1419     case FNC_RFF: return "RFF";         /* Read forward until file mark (diag) */
1420     case FNC_RRR: return "RRR";         /* Read record in reverse (diag) */
1421 
1422     default:      return "???";         /* Unknown command */
1423     }
1424 }
1425 
1426 
1427 /* 7970B/7970E bootstrap loaders (BMTL and 12992D).
1428 
1429    The Basic Magnetic Tape Loader (BMTL) reads an absolute binary program from
1430    tape into memory.  Before execution, the S register must be set as follows:
1431 
1432       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
1433      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1434      | -   -   -   -   -   -   -   -   -   - |      file number      |
1435      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1436 
1437    If S-register bits 5-0 are zero, the file located at the current tape
1438    position is read.  If the bits are non-zero, the tape is rewound, and the
1439    file number (1 - n) specified by the bits is read.
1440 
1441    The 12992D boot loader ROM reads an absolute program from tape into memory.
1442    If S-register bit 0 is 0, the file located at the current tape position is
1443    read.  If bit 0 is 1, the tape is rewound, and the file number (1 - n)
1444    specified by the A-register value is read.
1445 
1446    For either loader, the tape format must be absolute binary, and a tape mark
1447    must end the file.  Loader execution ends with one of the following
1448    instructions:
1449 
1450      * HLT 00 - a tape read (parity) error occurred.
1451      * HLT 11 - a checksum error occurred; A/B = the calculated/tape value.
1452      * HLT 77 - the end of the file was reached with a successful read.
1453 */
1454 
1455 static const LOADER_ARRAY ms_loaders = {
1456     {                               /* HP 21xx Basic Magnetic Tape Loader (BMTL) */
1457       000,                          /*   loader starting index */
1458       IBL_NA,                       /*   DMA index */
1459       IBL_NA,                       /*   FWA index */
1460       { 0102501,                    /*   77700:  MTAPE LIA 1               */
1461         0013775,                    /*   77701:        AND 77775           */
1462         0003007,                    /*   77702:        CMA,INA,SZA,RSS     */
1463         0027714,                    /*   77703:        JMP 77714           */
1464         0073777,                    /*   77704:        STA 77777           */
1465         0067771,                    /*   77705:        LDB 77771           */
1466         0017761,                    /*   77706:        JSB 77761           */
1467         0102311,                    /*   77707:        SFS 11              */
1468         0027707,                    /*   77710:        JMP 77707           */
1469         0067773,                    /*   77711:        LDB 77773           */
1470         0037777,                    /*   77712:        ISZ 77777           */
1471         0027706,                    /*   77713:        JMP 77706           */
1472         0067772,                    /*   77714:        LDB 77772           */
1473         0017761,                    /*   77715:        JSB 77761           */
1474         0103710,                    /*   77716:        STC 10,C            */
1475         0017740,                    /*   77717:        JSB 77740           */
1476         0005727,                    /*   77720:        BLF,BLF             */
1477         0007004,                    /*   77721:        CMB,INB             */
1478         0077777,                    /*   77722:        STB 77777           */
1479         0017740,                    /*   77723:        JSB 77740           */
1480         0074000,                    /*   77724:        STB 0               */
1481         0077776,                    /*   77725:        STB 77776           */
1482         0017740,                    /*   77726:        JSB 77740           */
1483         0177776,                    /*   77727:        STB 77776,I         */
1484         0040001,                    /*   77730:        ADA 1               */
1485         0037776,                    /*   77731:        ISZ 77776           */
1486         0037777,                    /*   77732:        ISZ 77777           */
1487         0027726,                    /*   77733:        JMP 77726           */
1488         0017740,                    /*   77734:        JSB 77740           */
1489         0054000,                    /*   77735:        CPB 0               */
1490         0017740,                    /*   77736:        JSB 77740           */
1491         0102011,                    /*   77737:        HLT 11              */
1492         0000000,                    /*   77740:        NOP                 */
1493         0102310,                    /*   77741:        SFS 10              */
1494         0027745,                    /*   77742:        JMP 77745           */
1495         0107510,                    /*   77743:        LIB 10,C            */
1496         0127740,                    /*   77744:        JMP 77740,I         */
1497         0102311,                    /*   77745:        SFS 11              */
1498         0027741,                    /*   77746:        JMP 77741           */
1499         0102511,                    /*   77747:        LIA 11              */
1500         0013774,                    /*   77750:        AND 77774           */
1501         0067777,                    /*   77751:        LDB 77777           */
1502         0001727,                    /*   77752:        ALF,ALF             */
1503         0002020,                    /*   77753:        SSA                 */
1504         0102077,                    /*   77754:        HLT 77              */
1505         0002003,                    /*   77755:        SZA,RSS             */
1506         0006002,                    /*   77756:        SZB                 */
1507         0102000,                    /*   77757:        HLT 0               */
1508         0027714,                    /*   77760:        JMP 77714           */
1509         0000000,                    /*   77761:        NOP                 */
1510         0106611,                    /*   77762:        OTB 11              */
1511         0102511,                    /*   77763:        LIA 11              */
1512         0001323,                    /*   77764:        RAR,RAR             */
1513         0001310,                    /*   77765:        RAR,SLA             */
1514         0027762,                    /*   77766:        JMP 77762           */
1515         0103711,                    /*   77767:        STC 11,C            */
1516         0127761,                    /*   77770:        JMP 77761,I         */
1517         0001501,                    /*   77771:        OCT 1501            */
1518         0001423,                    /*   77772:        OCT 1423            */
1519         0000203,                    /*   77773:        OCT 203             */
1520         0016263,                    /*   77774:        OCT 16263           */
1521         0000077,                    /*   77775:        OCT 77              */
1522         0000000,                    /*   77776:        NOP                 */
1523         0000000 } },                /*   77777:        NOP                 */
1524 
1525     {                               /* HP 1000 Loader ROM (12992D) */
1526       IBL_START,                    /*   loader starting index */
1527       IBL_DMA,                      /*   DMA index */
1528       IBL_FWA,                      /*   FWA index */
1529       { 0106501,                    /*   77700:  ST    LIB 1              ; read sw */
1530         0006011,                    /*   77701:        SLB,RSS            ; bit 0 set? */
1531         0027714,                    /*   77702:        JMP RD             ; no read */
1532         0003004,                    /*   77703:        CMA,INA            ; A is ctr */
1533         0073775,                    /*   77704:        STA WC             ; save */
1534         0067772,                    /*   77705:        LDA SL0RW          ; sel 0, rew */
1535         0017762,                    /*   77706:  FF    JSB CMD            ; do cmd */
1536         0102311,                    /*   77707:        SFS CC             ; done? */
1537         0027707,                    /*   77710:        JMP *-1            ; wait */
1538         0067774,                    /*   77711:        LDB FFC            ; get file fwd */
1539         0037775,                    /*   77712:        ISZ WC             ; done files? */
1540         0027706,                    /*   77713:        JMP FF             ; no */
1541         0067773,                    /*   77714:  RD    LDB RDCMD          ; read cmd */
1542         0017762,                    /*   77715:        JSB CMD            ; do cmd */
1543         0103710,                    /*   77716:        STC DC,C           ; start dch */
1544         0102211,                    /*   77717:        SFC CC             ; read done? */
1545         0027752,                    /*   77720:        JMP STAT           ; no, get stat */
1546         0102310,                    /*   77721:        SFS DC             ; any data? */
1547         0027717,                    /*   77722:        JMP *-3            ; wait */
1548         0107510,                    /*   77723:        LIB DC,C           ; get rec cnt */
1549         0005727,                    /*   77724:        BLF,BLF            ; move to lower */
1550         0007000,                    /*   77725:        CMB                ; make neg */
1551         0077775,                    /*   77726:        STA WC             ; save */
1552         0102211,                    /*   77727:        SFC CC             ; read done? */
1553         0027752,                    /*   77730:        JMP STAT           ; no, get stat */
1554         0102310,                    /*   77731:        SFS DC             ; any data? */
1555         0027727,                    /*   77732:        JMP *-3            ; wait */
1556         0107510,                    /*   77733:        LIB DC,C           ; get load addr */
1557         0074000,                    /*   77734:        STB 0              ; start csum */
1558         0077762,                    /*   77735:        STA CMD            ; save address */
1559         0027742,                    /*   77736:        JMP *+4            */
1560         0177762,                    /*   77737:  NW    STB CMD,I          ; store data */
1561         0040001,                    /*   77740:        ADA 1              ; add to csum */
1562         0037762,                    /*   77741:        ISZ CMD            ; adv addr ptr */
1563         0102310,                    /*   77742:        SFS DC             ; any data? */
1564         0027742,                    /*   77743:        JMP *-1            ; wait */
1565         0107510,                    /*   77744:        LIB DC,C           ; get word */
1566         0037775,                    /*   77745:        ISZ WC             ; done? */
1567         0027737,                    /*   77746:        JMP NW             ; no */
1568         0054000,                    /*   77747:        CPB 0              ; csum ok? */
1569         0027717,                    /*   77750:        JMP RD+3           ; yes, cont */
1570         0102011,                    /*   77751:        HLT 11             ; no, halt */
1571         0102511,                    /*   77752:  ST    LIA CC             ; get status */
1572         0001727,                    /*   77753:        ALF,ALF            ; get eof bit */
1573         0002020,                    /*   77754:        SSA                ; set? */
1574         0102077,                    /*   77755:        HLT 77             ; done */
1575         0001727,                    /*   77756:        ALF,ALF            ; put status back */
1576         0001310,                    /*   77757:        RAR,SLA            ; read ok? */
1577         0102000,                    /*   77760:        HLT 0              ; no */
1578         0027714,                    /*   77761:        JMP RD             ; read next */
1579         0000000,                    /*   77762:  CMD   NOP                */
1580         0106611,                    /*   77763:        OTB CC             ; output cmd */
1581         0102511,                    /*   77764:        LIA CC             ; check for reject */
1582         0001323,                    /*   77765:        RAR,RAR            */
1583         0001310,                    /*   77766:        RAR,SLA            */
1584         0027763,                    /*   77767:        JMP CMD+1          ; try again */
1585         0103711,                    /*   77770:        STC CC,C           ; start command */
1586         0127762,                    /*   77771:        JMP CMD,I          ; exit */
1587         0001501,                    /*   77772:  SL0RW OCT 1501           ; select 0, rewind */
1588         0001423,                    /*   77773:  RDCMD OCT 1423           ; read record */
1589         0000203,                    /*   77774:  FFC   OCT 203            ; space forward file */
1590         0000000,                    /*   77775:  WC    NOP                */
1591         0000000,                    /*   77776:        NOP                */
1592         0000000 } }                 /*   77777:        NOP                */
1593     };
1594 
1595 
1596 /* Device boot routine.
1597 
1598    This routine is called directly by the BOOT MSC and LOAD MSC commands to copy
1599    the device bootstrap into the upper 64 words of the logical address space.
1600    It is also called indirectly by a BOOT CPU or LOAD CPU command when the
1601    specified HP 1000 loader ROM socket contains a 12992D ROM.
1602 
1603    When called in response to a BOOT MSC or LOAD MSC command, the "unitno"
1604    parameter indicates the unit number specified in the BOOT command or is zero
1605    for the LOAD command, and "dptr" points at the MSC device structure.  The
1606    bootstrap supports loading only from unit 0, and the command will be rejected
1607    if another unit is specified (e.g., BOOT MSC1).  Otherwise, depending on the
1608    current CPU model, the BMTL or 12992D loader ROM will be copied into memory
1609    and configured for the MSD/MSC select code pair.  If the CPU is a 1000, the S
1610    register will be set as it would be by the front-panel microcode.
1611 
1612    When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
1613    select code to be used for configuration, and "dptr" will be NULL.  As above,
1614    the BMTL or 12992D loader ROM will be copied into memory and configured for
1615    the specified select code.  The S register is assumed to be set correctly on
1616    entry and is not modified.
1617 
1618    For the 12992D boot loader ROM for the HP 1000, the S register is set as
1619    follows:
1620 
1621       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
1622      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1623      | ROM # | 0   0 |      select code      | 0   0   0   0   0 | F |
1624      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1625 
1626    Where:
1627 
1628      F = Read current/specified file (0/1)
1629 
1630    If bit 0 is 0, the file located at the current tape position is read.  If bit
1631    0 is 1, the tape is rewound, and the file number (1 - n) specified by the
1632    A-register content is read.
1633 */
1634 
msc_boot(int32 unitno,DEVICE * dptr)1635 static t_stat msc_boot (int32 unitno, DEVICE *dptr)
1636 {
1637 static const HP_WORD ms_preserved  = 0000000u;              /* no S-register bits are preserved */
1638 static const HP_WORD ms_reposition = 0000001u;              /* S-register bit 0 set for a repositioning boot */
1639 uint32 start;
1640 
1641 if (dptr == NULL)                                           /* if we are being called for a BOOT/LOAD CPU */
1642     start = cpu_copy_loader (ms_loaders, unitno,            /*   then copy the boot loader to memory */
1643                              IBL_S_NOCLEAR, IBL_S_NOSET);   /*     but do not alter the S register */
1644 
1645 else if (unitno != 0)                                       /* otherwise a BOOT MSC for a non-zero unit */
1646     return SCPE_NOFNC;                                      /*   is rejected as unsupported */
1647 
1648 else                                                            /* otherwise this is a BOOT/LOAD MSC */
1649     start = cpu_copy_loader (ms_loaders, msd_dib.select_code,   /*   so copy the boot loader to memory */
1650                              ms_preserved,                      /*     and configure the S register if 1000 CPU */
1651                              sim_switches & SWMASK ('S') ? ms_reposition : 0);
1652 
1653 if (start == 0)                                         /* if the copy failed */
1654     return SCPE_NOFNC;                                  /*   then reject the command */
1655 else                                                    /* otherwise */
1656     return SCPE_OK;                                     /*   the boot loader was successfully copied */
1657 }
1658 
1659 
1660 /* Calculate tape record CRC and LRC characters */
1661 
calc_crc_lrc(uint8 * buffer,t_mtrlnt length)1662 static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length)
1663 {
1664 uint32 i;
1665 HP_WORD byte, crc, lrc;
1666 
1667 lrc = crc = 0;
1668 
1669 for (i = 0; i < length; i++) {
1670     byte = odd_parity [buffer [i]] | buffer [i];
1671 
1672     crc = crc ^ byte;
1673     lrc = lrc ^ byte;
1674 
1675     if (crc & 1)
1676         crc = crc >> 1 ^ 0474;
1677     else
1678         crc = crc >> 1;
1679     }
1680 
1681 crc = crc ^ 0727;
1682 lrc = lrc ^ crc;
1683 
1684 return (uint32) crc << 16 | lrc;
1685 }
1686