1 /* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator
2 
3    Copyright (c) 2004-2012, Robert M. Supnik
4    Copyright (c) 2012       J. David Bryan
5 
6    Permission is hereby granted, free of charge, to any person obtaining a
7    copy of this software and associated documentation files (the "Software"),
8    to deal in the Software without restriction, including without limitation
9    the rights to use, copy, modify, merge, publish, distribute, sublicense,
10    and/or sell copies of the Software, and to permit persons to whom the
11    Software is 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
19    THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION 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    DS           13037D/13175D disc controller/interface
28 
29    29-Mar-12    JDB     Rewritten to use the MAC/ICD disc controller library
30                         ioIOO now notifies controller service of parameter output
31    14-Feb-12    JDB     Corrected SRQ generation and FIFO under/overrun detection
32                         Corrected Clear command to conform to the hardware
33                         Fixed Request Status to return Unit Unavailable if illegal
34                         Seek and Cold Load Read now Seek Check if seek in progress
35                         Remodeled command wait for seek completion
36    10-Feb-12    JDB     Deprecated DEVNO in favor of SC
37    21-Jun-11    JDB     Corrected status returns for disabled drive, auto-seek
38                         beyond drive limits, Request Sector Address and Wakeup
39                         with invalid or offline unit
40                         Address verification reenabled if auto-seek during
41                         Read Without Verify
42    28-Mar-11    JDB     Tidied up signal handling
43    26-Oct-10    JDB     Changed I/O signal handler for revised signal model
44    26-Jun-08    JDB     Rewrote device I/O to model backplane signals
45    31-Dec-07    JDB     Corrected and verified ioCRS action
46    20-Dec-07    JDB     Corrected DPTR register definition from FLDATA to DRDATA
47    28-Dec-06    JDB     Added ioCRS state to I/O decoders
48    03-Aug-06    JDB     Fixed REQUEST STATUS command to clear status-1
49                         Removed redundant attached test in "ds_detach"
50    18-Mar-05    RMS     Added attached test to detach routine
51    01-Mar-05    JDB     Added SET UNLOAD/LOAD
52 
53    References:
54    - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980)
55    - 7925D Disc Drive Service Manual (07925-90913, Apr-1984)
56    - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986)
57    - DVR32 RTE Moving Head Driver source (92084-18711, Revision 5000)
58 
59 
60    The 13037D multiple-access (MAC) disc controller supports from one to eight
61    HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives
62    accessed by one to eight CPUs.  The controller hardware consists of a 16-bit
63    microprogrammed processor constructed from 74S181 bit slices operating at 5
64    MHz, a device controller providing the interconnections to the drives and CPU
65    interfaces, and an error correction controller that enables the correction of
66    up to 32-bit error bursts.  1024 words of 24-bit firmware are stored in ROM.
67 
68    The 13175D disc interface is used to connect the HP 1000 CPU to the 13037
69    device controller.  In a multiple-CPU system, one interface is strapped to
70    reset the controller when the CPU's front panel PRESET button is pressed.
71 
72    This module simulates a 13037D connected to a single 13175D interface.  From
73    one to eight drives may be connected, and drive types may be freely
74    intermixed.  A unit that is enabled but not attached appears to be a
75    connected drive that does not have a disc pack in place.  A unit that is
76    disabled appears to be disconnected.
77 
78    This simulator is an adaptation of the code originally written by Bob Supnik.
79    The functions of the controller have been separated from the functions of the
80    interface, with the former placed into a separate disc controller library.
81    This allows the library to support other CPU interfaces, such as the 12821A
82    HP-IB disc interface, that use substantially different communication
83    protocols.  The library functions implement the controller command set for
84    the drive units.  The interface functions handle the transfer of commands and
85    data to and from the CPU.
86 
87    In hardware, the controller runs continuously in one of three states: in the
88    Poll Loop (idle state), in the Command Wait Loop (wait state), or in command
89    execution (busy state).  In simulation, the controller is run only when a
90    command is executing or when a transition into or out of the two loops might
91    occur.  Internally, the controller handles these transitions:
92 
93     - when a command other than End terminates (busy => wait)
94     - when the End command terminates (busy => idle)
95     - when a command timeout occurs (wait => idle)
96     - when a parameter timeout occurs (busy => idle)
97     - when a seek completes (if idle and interrupts are enabled, idle => wait)
98 
99    The interface must call the controller library to handle these transitions:
100 
101     - when a command is received from the CPU (idle or wait => busy)
102     - when interrupts are enabled (if idle and drive Attention, idle => wait)
103 
104    In addition, each transition to the wait state must check for a pending
105    command, and each transition to the idle state must check for both a pending
106    command and a drive with Attention status asserted.
107 
108 
109    Implementation notes:
110 
111     1. Although the 13175D has a 16-word FIFO, the "full" level is set at 5
112        entries in hardware to avoid a long DCPC preemption time at the start of
113        a disc write as the FIFO fills.
114 */
115 
116 
117 
118 #include "hp2100_defs.h"
119 #include "hp_disclib.h"
120 
121 
122 
123 /* Program constants */
124 
125 #define DS_DRIVES       (DL_MAXDRIVE + 1)               /* number of disc drive units */
126 #define DS_UNITS        (DS_DRIVES + DL_AUXUNITS)       /* total number of units */
127 
128 #define ds_cntlr        ds_unit [DL_MAXDRIVE + 1]       /* controller unit alias */
129 
130 #define FIFO_SIZE       16                              /* FIFO depth */
131 
132 #define FIFO_EMPTY      (ds.fifo_count == 0)            /* FIFO empty test */
133 #define FIFO_STOP       (ds.fifo_count >= 5)            /* FIFO stop filling test */
134 #define FIFO_FULL       (ds.fifo_count == FIFO_SIZE)    /* FIFO full test */
135 
136 #define PRESET_ENABLE   TRUE                            /* Preset Jumper (W4) is enabled */
137 
138 
139 /* Debug flags */
140 
141 #define DEB_CPU         (1 << 0)                        /* words received from and sent to the CPU */
142 #define DEB_CMDS        (1 << 1)                        /* interface commands received from the CPU */
143 #define DEB_BUF         (1 << 2)                        /* data read from and written to the card FIFO */
144 #define DEB_RWSC        (1 << 3)                        /* device read/write/status/control commands */
145 #define DEB_SERV        (1 << 4)                        /* unit service scheduling calls */
146 
147 
148 
149 /* Per-card state variables */
150 
151 typedef struct {
152     FLIP_FLOP control;                                  /* control flip-flop */
153     FLIP_FLOP flag;                                     /* flag flip-flop */
154     FLIP_FLOP flagbuf;                                  /* flag buffer flip-flop */
155     FLIP_FLOP srq;                                      /* SRQ flip-flop */
156     FLIP_FLOP edt;                                      /* EDT flip-flop */
157     FLIP_FLOP cmfol;                                    /* command follows flip-flop */
158     FLIP_FLOP cmrdy;                                    /* command ready flip-flop */
159     uint16    fifo [FIFO_SIZE];                         /* FIFO buffer */
160     uint32    fifo_count;                               /* FIFO occupancy counter */
161     REG      *fifo_reg;                                 /* FIFO register pointer */
162     } CARD_STATE;
163 
164 
165 /* MAC disc state variables */
166 
167 static UNIT ds_unit [DS_UNITS];                         /* unit array */
168 
169 static CARD_STATE ds;                                   /* card state */
170 
171 static uint16 buffer [DL_BUFSIZE];                      /* command/status/sector buffer */
172 
173 static CNTLR_VARS mac_cntlr =                           /* MAC controller */
174     { CNTLR_INIT (MAC, buffer, &ds_cntlr) };
175 
176 
177 
178 /* MAC disc global VM routines */
179 
180 IOHANDLER ds_io;
181 t_stat    ds_service_drive      (UNIT   *uptr);
182 t_stat    ds_service_controller (UNIT   *uptr);
183 t_stat    ds_service_timer      (UNIT   *uptr);
184 t_stat    ds_reset              (DEVICE *dptr);
185 t_stat    ds_attach             (UNIT   *uptr,  char   *cptr);
186 t_stat    ds_detach             (UNIT   *uptr);
187 t_stat    ds_boot               (int32  unitno, DEVICE *dptr);
188 
189 /* MAC disc global SCP routines */
190 
191 t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);
192 
193 /* MAC disc local utility routines */
194 
195 static void   start_command     (void);
196 static void   poll_interface    (void);
197 static void   poll_drives       (void);
198 static void   fifo_load         (uint16 data);
199 static uint16 fifo_unload       (void);
200 static void   fifo_clear        (void);
201 static t_stat activate_unit     (UNIT *uptr);
202 
203 
204 
205 /* MAC disc VM data structures.
206 
207    ds_dib       DS device information block
208    ds_unit      DS unit list
209    ds_reg       DS register list
210    ds_mod       DS modifier list
211    ds_deb       DS debug table
212    ds_dev       DS device descriptor
213 
214    For the drive models, the modifiers provide this SHOW behavior:
215 
216     - when detached and autosized, prints "autosize"
217     - when detached and not autosized, prints the model number
218     - when attached, prints the model number (regardless of autosizing)
219 
220 
221    Implementation notes:
222 
223     1. The validation routine does not allow the model number or autosizing
224        option to be changed when the unit is attached.  Therefore, specifying
225        UNIT_ATT in the mask field has no adverse effect.
226 
227     2. The modifier DEVNO is deprecated in favor of SC but is retained for
228        compatibility.
229 */
230 
231 
232 DEVICE ds_dev;
233 
234 static DIB ds_dib = { &ds_io, DS };
235 
236 #define UNIT_FLAGS  (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD)
237 
238 static UNIT ds_unit [] = {
239     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 0 */
240     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 1 */
241     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 2 */
242     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 3 */
243     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 4 */
244     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 5 */
245     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 6 */
246     { UDATA (&ds_service_drive,      UNIT_FLAGS | MODEL_7905, D7905_WORDS) },   /* drive unit 7 */
247     { UDATA (&ds_service_controller, UNIT_DIS,                0)           },   /* controller unit */
248     { UDATA (&ds_service_timer,      UNIT_DIS,                0)           }    /* timer unit */
249     };
250 
251 static REG ds_reg [] = {
252     { FLDATA (CMFOL,  ds.cmfol,                0)                           },
253     { FLDATA (CMRDY,  ds.cmrdy,                0)                           },
254     { DRDATA (FCNT,   ds.fifo_count,           5)                           },
255     { BRDATA (FIFO,   ds.fifo,                 8, 16, FIFO_SIZE), REG_CIRC  },
256     { ORDATA (FREG,   ds.fifo_reg,            32), REG_HRO                  },
257 
258     { ORDATA (CNTYPE, mac_cntlr.type,          2), REG_HRO                  },
259     { ORDATA (STATE,  mac_cntlr.state,         2)                           },
260     { ORDATA (OPCODE, mac_cntlr.opcode,        6)                           },
261     { ORDATA (STATUS, mac_cntlr.status,        6)                           },
262     { FLDATA (EOC,    mac_cntlr.eoc,           0)                           },
263     { FLDATA (EOD,    mac_cntlr.eod,           0)                           },
264     { ORDATA (SPDU,   mac_cntlr.spd_unit,     16)                           },
265     { ORDATA (FLMASK, mac_cntlr.file_mask,     4)                           },
266     { ORDATA (RETRY,  mac_cntlr.retry,         4), REG_HRO                  },
267     { ORDATA (CYL,    mac_cntlr.cylinder,     16)                           },
268     { ORDATA (HEAD,   mac_cntlr.head,          6)                           },
269     { ORDATA (SECTOR, mac_cntlr.sector,        8)                           },
270     { ORDATA (VFYCNT, mac_cntlr.verify_count, 16)                           },
271     { ORDATA (LASPOL, mac_cntlr.poll_unit,     3)                           },
272     { HRDATA (BUFPTR, mac_cntlr.buffer,       32), REG_HRO                  },
273     { BRDATA (BUFFER, buffer,              8, 16, DL_BUFSIZE)               },
274     { DRDATA (INDEX,  mac_cntlr.index,         8)                           },
275     { DRDATA (LENGTH, mac_cntlr.length,        8)                           },
276     { HRDATA (AUXPTR, mac_cntlr.aux,          32), REG_HRO                  },
277     { DRDATA (STIME,  mac_cntlr.seek_time,    24), PV_LEFT | REG_NZ         },
278     { DRDATA (ITIME,  mac_cntlr.sector_time,  24), PV_LEFT | REG_NZ         },
279     { DRDATA (CTIME,  mac_cntlr.cmd_time,     24), PV_LEFT | REG_NZ         },
280     { DRDATA (DTIME,  mac_cntlr.data_time,    24), PV_LEFT | REG_NZ         },
281     { DRDATA (WTIME,  mac_cntlr.wait_time,    31), PV_LEFT | REG_NZ         },
282 
283     { FLDATA (CTL,    ds.control,              0)                           },
284     { FLDATA (FLG,    ds.flag,                 0)                           },
285     { FLDATA (FBF,    ds.flagbuf,              0)                           },
286     { FLDATA (SRQ,    ds.srq,                  0)                           },
287     { FLDATA (EDT,    ds.edt,                  0)                           },
288 
289     { URDATA (UCYL,   ds_unit[0].CYL,   10, 10,       0, DS_UNITS, PV_LEFT) },
290     { URDATA (UOP,    ds_unit[0].OP,     8,  6,       0, DS_UNITS, PV_RZRO) },
291     { URDATA (USTAT,  ds_unit[0].STAT,   2,  8,       0, DS_UNITS, PV_RZRO) },
292     { URDATA (UPHASE, ds_unit[0].PHASE,  8,  3,       0, DS_UNITS, PV_RZRO) },
293     { URDATA (UPOS,   ds_unit[0].pos,    8, T_ADDR_W, 0, DS_UNITS, PV_LEFT) },
294     { URDATA (UWAIT,  ds_unit[0].wait,   8, 32,       0, DS_UNITS, PV_LEFT) },
295 
296     { ORDATA (SC,     ds_dib.select_code, 6), REG_HRO },
297     { ORDATA (DEVNO,  ds_dib.select_code, 6), REG_HRO },
298     { NULL }
299     };
300 
301 static MTAB ds_mod [] = {
302 /*    mask         match        pstring            mstring         valid            disp  desc */
303     { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded",  "UNLOADED",     &ds_load_unload, NULL, NULL },
304     { UNIT_UNLOAD, 0,           "heads loaded",    "LOADED",       &ds_load_unload, NULL, NULL },
305 
306     { UNIT_WLK,    UNIT_WLK,    "write locked",    "LOCKED",       NULL,            NULL, NULL },
307     { UNIT_WLK,    0,           "write enabled",   "WRITEENABLED", NULL,            NULL, NULL },
308 
309     { UNIT_FMT,    UNIT_FMT,    "format enabled",  "FORMAT",       NULL,            NULL, NULL },
310     { UNIT_FMT,    0,           "format disabled", "NOFORMAT",     NULL,            NULL, NULL },
311 
312 /*    mask                               match                  pstring     mstring     valid          disp  desc */
313     { UNIT_AUTO | UNIT_ATT,              UNIT_AUTO,             "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL },
314     { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905,            "7905",     "7905",     &dl_set_model, NULL, NULL },
315     { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906,            "7906",     "7906",     &dl_set_model, NULL, NULL },
316     { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7920,            "7920",     "7920",     &dl_set_model, NULL, NULL },
317     { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7925,            "7925",     "7925",     &dl_set_model, NULL, NULL },
318     { UNIT_ATT | UNIT_MODEL,             UNIT_ATT | MODEL_7905, "7905",     NULL,       NULL,          NULL, NULL },
319     { UNIT_ATT | UNIT_MODEL,             UNIT_ATT | MODEL_7906, "7906",     NULL,       NULL,          NULL, NULL },
320     { UNIT_ATT | UNIT_MODEL,             UNIT_ATT | MODEL_7920, "7920",     NULL,       NULL,          NULL, NULL },
321     { UNIT_ATT | UNIT_MODEL,             UNIT_ATT | MODEL_7925, "7925",     NULL,       NULL,          NULL, NULL },
322 
323     { MTAB_XTD | MTAB_VDV,            0, "SC",    "SC",    &hp_setsc,  &hp_showsc,  &ds_dev },
324     { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ds_dev },
325     { 0 }
326     };
327 
328 static DEBTAB ds_deb [] = {
329     { "CPU",  DEB_CPU  },
330     { "CMDS", DEB_CMDS },
331     { "BUF",  DEB_BUF  },
332     { "RWSC", DEB_RWSC },
333     { "SERV", DEB_SERV },
334     { NULL,   0 }
335     };
336 
337 DEVICE ds_dev = {
338     "DS",                                               /* device name */
339     ds_unit,                                            /* unit array */
340     ds_reg,                                             /* register array */
341     ds_mod,                                             /* modifier array */
342     DS_UNITS,                                           /* number of units */
343     8,                                                  /* address radix */
344     27,                                                 /* address width = 128 MB */
345     1,                                                  /* address increment */
346     8,                                                  /* data radix */
347     16,                                                 /* data width */
348     NULL,                                               /* examine routine */
349     NULL,                                               /* deposit routine */
350     &ds_reset,                                          /* reset routine */
351     &ds_boot,                                           /* boot routine */
352     &ds_attach,                                         /* attach routine */
353     &ds_detach,                                         /* detach routine */
354     &ds_dib,                                            /* device information block */
355     DEV_DEBUG | DEV_DISABLE,                            /* device flags */
356     0,                                                  /* debug control flags */
357     ds_deb,                                             /* debug flag name table */
358     NULL,                                               /* memory size change routine */
359     NULL                                                /* logical device name */
360     };
361 
362 
363 
364 /* MAC disc global VM routines */
365 
366 
367 /* I/O signal handler.
368 
369    The 13175D disc interface data path consists of an input multiplexer/latch
370    and a 16-word FIFO buffer.  The FIFO source may be either the CPU's I/O
371    input bus or the controller's interface data bus.  The output of the FIFO may
372    be enabled either to the CPU's I/O output bus or the interface data bus.
373 
374    The control path consists of the usual control, flag buffer, flag, and SRQ
375    flip-flops, although flag and SRQ are decoupled to allow the full DCPC
376    transfer rate through the FIFO (driving SRQ from the flag limits transfers to
377    every other cycle).  SRQ is based on the FIFO level: if data or room in the
378    FIFO is available, SRQ is set to initiate a transfer.  The flag is only used
379    to signal an interrupt at the end of a command.
380 
381    One unusual aspect is that SFC and SFS test different things, rather than
382    complementary states of the same thing.  SFC tests the controller busy state,
383    and SFS tests the flag flip-flop.
384 
385    In addition, the card contains end-of-data-transfer, command-follows, and
386    command-ready flip-flops.  EDT is set when the DCPC EDT signal is asserted
387    and is used in conjunction with the FIFO level to assert the end-of-data
388    signal to the controller.  The command-follows flip-flop is set by a CLC to
389    indicate that the next data word output from the CPU is a disc command.  The
390    command-ready flip-flop is set when a command is received to schedule an
391    interface poll.
392 
393 
394    Implementation notes:
395 
396     1. In hardware, SRQ is enabled only when the controller is reading or
397        writing the disc (IFIN or IFOUT functions are asserted) and set when the
398        FIFO is not empty (read) or not full (write).  In simulation, SRQ is set
399        by the unit service read/write data phase transfers and cleared in the
400        IOI and IOO signal handlers when the FIFO is empty (read) or full
401        (write).
402 
403     2. The DCPC EDT signal cannot set the controller's end-of-data flag directly
404        because a write EOD must occur only after the FIFO has been drained.
405 
406     3. Polling the interface or drives must be deferred to the end of I/O signal
407        handling.  If they are performed in the IOO/STC handlers themselves, an
408        associated CLF might clear the flag that was set by the poll.
409 
410     4. Executing a CLC sets the controller's end-of-data flag, which will abort
411        a read or write data transfer in progress.  Parameter transfers are not
412        affected.  If a command is received when a parameter is expected, the
413        word is interpreted as data, even though the command-ready flip-flop is
414        set.  The controller firmware only checks DTRDY for a parameter transfer,
415        and DTRDY is asserted whenever the FIFO is not empty.
416 
417     5. The hardware Interface Function and Flag Buses are not implemented
418        explicitly.  Instead, interface functions and signals are inferred by the
419        interface from the current command operation and phase.
420 */
421 
ds_io(DIB * dibptr,IOCYCLE signal_set,uint32 stat_data)422 uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
423 {
424 static const char * const output_state [] = { "Data", "Command" };
425 const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : "");
426 
427 uint16   data;
428 t_stat   status;
429 IOSIGNAL signal;
430 IOCYCLE  working_set = IOADDSIR (signal_set);           /* add ioSIR if needed */
431 t_bool   command_issued = FALSE;
432 t_bool   interrupt_enabled = FALSE;
433 
434 while (working_set) {
435     signal = IONEXT (working_set);                      /* isolate the next signal */
436 
437     switch (signal) {                                   /* dispatch the I/O signal */
438 
439         case ioCLF:                                     /* clear flag flip-flop */
440             ds.flag = CLEAR;                            /* clear the flag */
441             ds.flagbuf = CLEAR;                         /*   and flag buffer */
442 
443             if (DEBUG_PRI (ds_dev, DEB_CMDS))
444                 fputs (">>DS cmds: [CLF] Flag cleared\n", sim_deb);
445             break;
446 
447 
448         case ioSTF:                                     /* set flag flip-flop */
449         case ioENF:                                     /* enable flag */
450             ds.flag = SET;                              /* set the flag */
451             ds.flagbuf = SET;                           /*   and flag buffer */
452 
453             if (DEBUG_PRI (ds_dev, DEB_CMDS))
454                 fputs (">>DS cmds: [STF] Flag set\n", sim_deb);
455             break;
456 
457 
458         case ioSFC:                                     /* skip if flag is clear */
459             setSKF (mac_cntlr.state != cntlr_busy);     /* skip if the controller is not busy */
460             break;
461 
462 
463         case ioSFS:                                     /* skip if flag is set */
464             setstdSKF (ds);                             /* assert SKF if the flag is set */
465             break;
466 
467 
468         case ioIOI:                                         /* I/O data input */
469             data = fifo_unload ();                          /* unload the next word from the FIFO */
470             stat_data = IORETURN (SCPE_OK, data);           /* merge in the return status */
471 
472             if (DEBUG_PRI (ds_dev, DEB_CPU))
473                 fprintf (sim_deb, ">>DS cpu:  [LIx%s] Data = %06o\n", hold_or_clear, data);
474 
475             if (FIFO_EMPTY) {                               /* is the FIFO now empty? */
476                 if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS))
477                     fprintf (sim_deb, ">>DS cmds: [LIx%s] SRQ cleared\n", hold_or_clear);
478 
479                 ds.srq = CLEAR;                             /* clear SRQ */
480 
481                 if (ds_cntlr.PHASE == data_phase) {         /* is this an outbound parameter? */
482                     ds_cntlr.wait = mac_cntlr.data_time;    /* activate the controller */
483                     activate_unit (&ds_cntlr);              /*   to acknowledge the data */
484                     }
485                 }
486             break;
487 
488 
489         case ioIOO:                                         /* I/O data output */
490             data = IODATA (stat_data);                      /* mask to just the data word */
491 
492             if (DEBUG_PRI (ds_dev, DEB_CPU))
493                 fprintf (sim_deb, ">>DS cpu:  [OTx%s] %s = %06o\n",
494                          hold_or_clear, output_state [ds.cmfol], data);
495 
496             fifo_load (data);                               /* load the word into the FIFO */
497 
498             if (ds.cmfol == SET) {                          /* are we expecting a command? */
499                 ds.cmfol = CLEAR;                           /* clear the command follows flip-flop */
500                 ds.cmrdy = SET;                             /* set the command ready flip-flop */
501                 command_issued = TRUE;                      /*   and request an interface poll */
502                 }
503 
504             else {                                          /* not a command */
505                 if (ds_cntlr.PHASE == data_phase) {         /* is this an inbound parameter? */
506                     ds_cntlr.wait = mac_cntlr.data_time;    /* activate the controller */
507                     activate_unit (&ds_cntlr);              /*   to receive the data */
508                     }
509 
510                 if (FIFO_STOP) {                            /* is the FIFO now full enough? */
511                     if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS))
512                         fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear);
513 
514                     ds.srq = CLEAR;                         /* clear SRQ to stop filling */
515                     }
516                 }
517             break;
518 
519 
520         case ioPOPIO:                                   /* power-on preset to I/O */
521             ds.flag = SET;                              /* set the flag */
522             ds.flagbuf = SET;                           /*   and flag buffer */
523             ds.cmrdy = CLEAR;                           /* clear the command ready flip-flop */
524 
525             if (DEBUG_PRI (ds_dev, DEB_CMDS))
526                 fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb);
527             break;
528 
529 
530         case ioCRS:                                         /* control reset */
531             if (DEBUG_PRI (ds_dev, DEB_CMDS))
532                 fputs (">>DS cmds: [CRS] Master reset\n", sim_deb);
533 
534             ds.control = CLEAR;                             /* clear the control */
535             ds.cmfol = CLEAR;                               /*   and command follows flip-flops */
536 
537             if (PRESET_ENABLE) {                            /* is preset enabled for this interface? */
538                 fifo_clear ();                              /* clear the FIFO */
539 
540                 status = dl_clear_controller (&mac_cntlr,   /* do a hard clear of the controller */
541                                               ds_unit, hard_clear);
542 
543                 stat_data = IORETURN (status, 0);           /* return the status from the controller */
544                 }
545             break;
546 
547 
548         case ioCLC:                                     /* clear control flip-flop */
549             if (DEBUG_PRI (ds_dev, DEB_CMDS))
550                 fprintf (sim_deb, ">>DS cmds: [CLC%s] Control cleared\n", hold_or_clear);
551 
552             ds.control = CLEAR;                         /* clear the control */
553             ds.edt = CLEAR;                             /*   and EDT flip-flops */
554             ds.cmfol = SET;                             /* set the command follows flip-flop */
555             mac_cntlr.eod = SET;                        /* set the controller's EOD flag */
556 
557             fifo_clear ();                              /* clear the FIFO */
558             break;
559 
560 
561         case ioSTC:                                     /* set control flip-flop */
562             ds.control = SET;                           /* set the control flip-flop */
563 
564             interrupt_enabled = TRUE;                   /* check for drive attention */
565 
566             if (DEBUG_PRI (ds_dev, DEB_CMDS))
567                 fprintf (sim_deb, ">>DS cmds: [STC%s] Control set\n", hold_or_clear);
568             break;
569 
570 
571         case ioEDT:                                     /* end data transfer */
572             ds.edt = SET;                               /* set the EDT flip-flop */
573 
574             if (DEBUG_PRI (ds_dev, DEB_CPU))
575                 fputs (">>DS cpu:  [EDT] DCPC transfer ended\n", sim_deb);
576             break;
577 
578 
579         case ioSIR:                                     /* set interrupt request */
580             setstdPRL (ds);                             /* set the standard PRL signal */
581             setstdIRQ (ds);                             /* set the standard IRQ signal */
582             setSRQ (dibptr->select_code, ds.srq);       /* set the SRQ signal */
583             break;
584 
585 
586         case ioIAK:                                     /* interrupt acknowledge */
587             ds.flagbuf = CLEAR;                         /* clear the flag */
588             break;
589 
590 
591         default:                                        /* all other signals */
592             break;                                      /*   are ignored */
593         }
594 
595     working_set = working_set & ~signal;                /* remove the current signal from the set */
596     }
597 
598 
599 if (command_issued)                                     /* was a command received? */
600     poll_interface ();                                  /* poll the interface for the next command */
601 else if (interrupt_enabled)                             /* were interrupts enabled? */
602     poll_drives ();                                     /* poll the drives for Attention */
603 
604 return stat_data;
605 }
606 
607 
608 /* Service the disc drive unit.
609 
610    The unit service routine is called to execute scheduled controller commands
611    for the specified unit.  The actions to be taken depend on the current state
612    of the controller and the unit.
613 
614    Generally, the controller library service routine handles all of the disc
615    operations except data transfer to and from the interface.  Read transfers
616    are responsible for loading words from the sector buffer into the FIFO and
617    enabling SRQ.  If the current sector transfer is complete, either due to EDT
618    assertion or buffer exhaustion, the controller is moved to the end phase to
619    complete or continue the read with the next sector.  In either case, the unit
620    is rescheduled.  If the FIFO overflows, the read terminates with a data
621    overrun error.
622 
623    Write transfers set the initial SRQ to request words from the CPU.  As each
624    word arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is
625    enabled.  If the current sector transfer is complete, the controller is moved
626    to the end phase.  If the FIFO underflows, the write terminates with a data
627    overrun error.
628 
629    The synchronous nature of the disc drive requires that data be supplied or
630    accepted continuously by the CPU.  DCPC generally assures that this occurs,
631    and the FIFO allows for some latency before an overrun or underrun occurs.
632 
633    The other operation the interface must handle is seek completion.  The
634    controller handles seek completion by setting Attention status in the drive's
635    status word.  The interface is responsible for polling the drives if the
636    controller is idle and interrupts are enabled.
637 
638 
639    Implementation notes:
640 
641     1. Every command except Seek, Recalibrate, and End sets the flag when the
642        command completes.  A command completes when the controller is no longer
643        busy (it becomes idle for Seek, Recalibrate, and End, or it becomes
644        waiting for all others).  Seek and Recalibrate may generate errors (e.g.,
645        heads unloaded), in which case the flag must be set.  But in these cases,
646        the controller state is waiting, not idle.
647 
648        However, it is insufficient simply to check that the controller has moved
649        to the wait state, because a seek may complete while the controller is
650        waiting for the next command.  For example, a Seek is started on unit 0,
651        and the controller moves to the idle state.  But before the seek
652        completes, another command is issued that attempts to access unit 1,
653        which is not ready.  The command fails with a Status-2 error, and the
654        controller moves to the wait state.  When the seek completes, the
655        controller is waiting with error status.  We must determine whether the
656        seek completed successfully or not, as we must interrupt in the latter
657        case.
658 
659        Therefore, we determine seek completion by checking if the Attention
660        status was set.  Attention sets only if the seek completes successfully.
661 
662        (Actually, Attention sets if a seek check occurs, but in that case, the
663        command terminated before the seek ever started.  Also, a seek may
664        complete while the controller is busy, waiting, or idle.)
665 
666     2. For debug printouts, we want to print the name of the command that has
667        completed when the controller returns to the idle or wait state.
668        Normally, we would use the controller's "opcode" field to identify the
669        command that completed.  However, while waiting for Seek or Recalibrate
670        completion, "opcode" may be set to another command if that command does
671        not access this drive.  For example, it might be set to a Read of another
672        unit, or a Request Status for this unit.  So we can't rely on "opcode" to
673        report the correct name of the completed positioning command.
674 
675        However, we cannot rely on "uptr->OP" either, as that can be changed
676        during the course of a command.  For example, Read Without Verify is
677        changed to Read after a track crossing.
678 
679        Instead, we have to determine whether a seek is completing.  If it is,
680        then we report "uptr->OP"; otherwise, we report "opcode".
681 
682     3. The initial write SRQ must set only at the transition from the start
683        phase to the data phase.  If a write command begins with an auto-seek,
684        the drive service will be entered twice in the start phase (the first
685        entry performs the seek, and the second begins the write).  In hardware,
686        SRQ does not assert until the write begins.
687 
688     4. The DCPC EDT signal cannot set the controller's end-of-data flag
689        directly because a write EOD must only occur after the FIFO has been
690        drained.
691 */
692 
ds_service_drive(UNIT * uptr)693 t_stat ds_service_drive (UNIT *uptr)
694 {
695 static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n";
696 t_stat result;
697 t_bool seek_completion;
698 int32 unit;
699 FLIP_FLOP entry_srq = ds.srq;                           /* get the SRQ state on entry */
700 CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE;    /* get the operation phase on entry */
701 uint32 entry_status = uptr->STAT;                       /* get the drive status on entry */
702 
703 result = dl_service_drive (&mac_cntlr, uptr);           /* service the drive */
704 
705 if ((CNTLR_PHASE) uptr->PHASE == data_phase)            /* is the drive in the data phase? */
706     switch ((CNTLR_OPCODE) uptr->OP) {                  /* dispatch the current operation */
707 
708         case read:                                      /* read operations */
709         case read_full_sector:
710         case read_with_offset:
711         case read_without_verify:
712             if (mac_cntlr.length == 0 || ds.edt == SET) {   /* is the data phase complete? */
713                 mac_cntlr.eod = ds.edt;                     /* set EOD if DCPC is done */
714                 uptr->PHASE = end_phase;                    /* set the end phase */
715                 uptr->wait = mac_cntlr.cmd_time;            /*   and schedule the controller */
716                 }
717 
718             else if (FIFO_FULL)                             /* is the FIFO already full? */
719                 dl_end_command (&mac_cntlr, data_overrun);  /* terminate the command with an overrun */
720 
721             else {
722                 fifo_load (buffer [mac_cntlr.index++]);     /* load the next word into the FIFO */
723                 mac_cntlr.length--;                         /* count it */
724                 ds.srq = SET;                               /* ask DCPC to pick it up */
725                 ds_io (&ds_dib, ioSIR, 0);                  /*   and recalculate the interrupts */
726                 uptr->wait = mac_cntlr.data_time;           /* schedule the next data transfer */
727                 }
728 
729             break;
730 
731 
732         case write:                                     /* write operations */
733         case write_full_sector:
734         case initialize:
735             if (entry_phase == start_phase) {           /* is this the phase transition? */
736                 ds.srq = SET;                           /* start the DCPC transfer */
737                 ds_io (&ds_dib, ioSIR, 0);              /*   and recalculate the interrupts */
738                 }
739 
740             else if (FIFO_EMPTY)                            /* is the FIFO empty? */
741                 dl_end_command (&mac_cntlr, data_overrun);  /* terminate the command with an underrun */
742 
743             else {
744                 buffer [mac_cntlr.index++] = fifo_unload ();    /* unload the next word from the FIFO */
745                 mac_cntlr.length--;                             /* count it */
746 
747                 if (ds.edt == SET && FIFO_EMPTY)                /* if DCPC is complete and the FIFO is empty */
748                     mac_cntlr.eod = SET;                        /*   then set the end-of-data flag */
749 
750                 if (mac_cntlr.length == 0 || mac_cntlr.eod == SET) {    /* is the data phase complete? */
751                     uptr->PHASE = end_phase;                            /* set the end phase */
752                     uptr->wait = mac_cntlr.cmd_time;                    /*   and schedule the controller */
753                     }
754 
755                 else {
756                     if (ds.edt == CLEAR) {              /* if DCPC is still transferring */
757                         ds.srq = SET;                   /*   then request the next word */
758                         ds_io (&ds_dib, ioSIR, 0);      /*   and recalculate the interrupts */
759                         }
760 
761                     uptr->wait = mac_cntlr.data_time;   /* schedule the next data transfer */
762                     }
763                 }
764 
765             break;
766 
767 
768         default:                                        /* we were entered with an invalid state */
769             result = SCPE_IERR;                         /* return an internal (programming) error */
770             break;
771         }                                               /* end of data phase operation dispatch */
772 
773 
774 if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq)
775     fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared");
776 
777 
778 if (uptr->wait)                                             /* was service requested? */
779     activate_unit (uptr);                                   /* schedule the next event */
780 
781 seek_completion = ~entry_status & uptr->STAT & DL_S2ATN;    /* seek is complete when Attention sets */
782 
783 if (mac_cntlr.state != cntlr_busy) {                        /* is the command complete? */
784     if (mac_cntlr.state == cntlr_wait && !seek_completion)  /* is it command but not seek completion? */
785         ds_io (&ds_dib, ioENF, 0);                          /* set the data flag to interrupt the CPU */
786 
787     poll_interface ();                                      /* poll the interface for the next command */
788     poll_drives ();                                         /* poll the drives for Attention */
789     }
790 
791 
792 if (DEBUG_PRI (ds_dev, DEB_RWSC)) {
793     unit = uptr - ds_unit;                                  /* get the unit number */
794 
795     if (result == SCPE_IERR)                                /* did an internal error occur? */
796         fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n",
797                  unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP),
798                  dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
799 
800     else if (seek_completion)                               /* if a seek has completed */
801         fprintf (sim_deb, completion_message,               /*   report the unit command */
802                  unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP));
803 
804     else if (mac_cntlr.state == cntlr_wait)                 /* if the controller has stopped */
805         fprintf (sim_deb, completion_message,               /*   report the controller command */
806                  unit, dl_opcode_name (MAC, mac_cntlr.opcode));
807     }
808 
809 return result;                                              /* return the result of the service */
810 }
811 
812 
813 /* Service the controller unit.
814 
815    The controller service routine is called to execute scheduled controller
816    commands that do not access drive units.  It is also called to obtain command
817    parameters from the interface and to return command result values to the
818    interface.
819 
820    Most controller commands are handled completely in the library's service
821    routine, so we call that first.  Commands that neither accept nor supply
822    parameters are complete when the library routine returns, so all we have to
823    do is set the interface flag if required.
824 
825    For parameter transfers in the data phase, the interface is responsible for
826    moving words between the sector buffer and the FIFO and setting the flag to
827    notify the CPU.
828 
829 
830    Implementation notes:
831 
832     1. In hardware, the Read With Offset command sets the data flag after the
833        offset parameter has been read and the head positioner has been moved by
834        the indicated amount.  The intent is to delay the DCPC start until the
835        drive is ready to supply data from the disc.
836 
837        In simulation, the flag is set as soon as the parameter is received.
838 */
839 
ds_service_controller(UNIT * uptr)840 t_stat ds_service_controller (UNIT *uptr)
841 {
842 t_stat result;
843 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP;
844 
845 result = dl_service_controller (&mac_cntlr, uptr);      /* service the controller */
846 
847 switch ((CNTLR_PHASE) uptr->PHASE) {                    /* dispatch the current phase */
848 
849     case start_phase:                                   /* most controller operations */
850     case end_phase:                                     /*   start and end on the same phase */
851         switch (opcode) {                               /* dispatch the current operation */
852 
853             case request_status:
854             case request_sector_address:
855             case address_record:
856             case request_syndrome:
857             case load_tio_register:
858             case request_disc_address:
859             case end:
860                 break;                                  /* complete the operation without setting the flag */
861 
862 
863             case clear:
864             case set_file_mask:
865             case wakeup:
866                 ds_io (&ds_dib, ioENF, 0);              /* complete the operation and set the flag */
867                 break;
868 
869 
870             default:                                    /* we were entered with an invalid state */
871                 result = SCPE_IERR;                     /* return an internal (programming) error */
872                 break;
873             }                                           /* end of operation dispatch */
874         break;                                          /* end of start and end phase handlers */
875 
876 
877     case data_phase:
878         switch (opcode) {                               /* dispatch the current operation */
879 
880             case seek:                                  /* operations that accept parameters */
881             case verify:
882             case address_record:
883             case read_with_offset:
884             case load_tio_register:
885                 buffer [mac_cntlr.index++] = fifo_unload ();    /* unload the next word from the FIFO */
886                 mac_cntlr.length--;                             /* count it */
887 
888                 if (mac_cntlr.length)                           /* are there more words to transfer? */
889                     ds_io (&ds_dib, ioENF, 0);                  /* set the flag to request the next one */
890 
891                 else {                                          /* all parameters have been received */
892                     uptr->PHASE = end_phase;                    /* set the end phase */
893 
894                     if (opcode == read_with_offset)             /* a Read With Offset command sets the flag */
895                         ds_io (&ds_dib, ioENF, 0);              /*   to indicate that offsetting is complete */
896 
897                     start_command ();                           /* the command is now ready to execute */
898                     }
899                 break;
900 
901 
902             case request_status:                        /* operations that supply parameters */
903             case request_sector_address:
904             case request_syndrome:
905             case request_disc_address:
906                 if (mac_cntlr.length) {                         /* are there more words to return? */
907                     fifo_load (buffer [mac_cntlr.index++]);     /* load the next word into the FIFO */
908                     mac_cntlr.length--;                         /* count it */
909 
910                     ds_io (&ds_dib, ioENF, 0);                  /* set the flag to request pickup by the CPU */
911                     }
912 
913                 else {                                  /* all parameters have been sent */
914                     uptr->PHASE = end_phase;            /* set the end phase */
915                     uptr->wait = mac_cntlr.cmd_time;    /* schedule the controller */
916                     activate_unit (uptr);               /*   to complete the command */
917                     }
918                 break;
919 
920 
921             default:                                    /* we were entered with an invalid state */
922                 result = SCPE_IERR;                     /* return an internal (programming) error */
923                 break;
924             }                                           /* end of operation dispatch */
925         break;                                          /* end of data phase handlers */
926     }                                                   /* end of phase dispatch */
927 
928 
929 if (result == SCPE_IERR && DEBUG_PRI (ds_dev, DEB_RWSC))    /* did an internal error occur? */
930     fprintf (sim_deb, ">>DS rwsc: Controller %s command %s phase service not handled\n",
931              dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->PHASE));
932 
933 
934 if (mac_cntlr.state != cntlr_busy) {                    /* has the controller stopped? */
935     poll_interface ();                                  /* poll the interface for the next command */
936     poll_drives ();                                     /* poll the drives for Attention status */
937 
938     if (DEBUG_PRI (ds_dev, DEB_RWSC))
939         fprintf (sim_deb, ">>DS rwsc: Controller %s command completed\n",
940                  dl_opcode_name (MAC, opcode));
941     }
942 
943 return result;                                          /* return the result of the service */
944 }
945 
946 
947 /* Service the command wait timer unit.
948 
949    The command wait timer service routine is called if the command wait timer
950    expires.  The library is called to reset the file mask and idle the
951    controller.  Then the interface is polled for a command and the drives are
952    polled for Attention status.
953 */
954 
ds_service_timer(UNIT * uptr)955 t_stat ds_service_timer (UNIT *uptr)
956 {
957 t_stat result;
958 
959 result = dl_service_timer (&mac_cntlr, uptr);           /* service the timer */
960 
961 poll_interface ();                                      /* poll the interface for the next command */
962 poll_drives ();                                         /* poll the drives for Attention status */
963 
964 return result;                                          /* return the result of the service */
965 }
966 
967 
968 /* Reset the simulator.
969 
970    In hardware, the PON signal clears the Interface Selected flip-flop,
971    disconnecting the interface from the disc controller.  In simulation, the
972    interface always remains connected to the controller, so no special action is
973    needed.
974 
975 
976    Implementation notes:
977 
978     1. During a power-on reset, a pointer to the FIFO simulation register is
979        saved to allow access to the "qptr" field during FIFO loading and
980        unloading.  This enables SCP to view the FIFO as a circular queue, so
981        that the bottom word of the FIFO is always displayed as FIFO[0],
982        regardless of where it is in the actual FIFO array.
983 
984     2. SRQ is denied because neither IFIN nor IFOUT is asserted when the
985        interface is not selected.
986 */
987 
ds_reset(DEVICE * dptr)988 t_stat ds_reset (DEVICE *dptr)
989 {
990 uint32 unit;
991 
992 if (sim_switches & SWMASK ('P')) {                      /* is this a power-on reset? */
993     ds.fifo_reg = find_reg ("FIFO", NULL, dptr);        /* find the FIFO register entry */
994 
995     if (ds.fifo_reg == NULL)                            /* if it cannot be found, */
996         return SCPE_IERR;                               /*   report a programming error */
997 
998     else {                                              /* found it */
999         ds.fifo_reg->qptr = 0;                          /*   so reset the FIFO bottom index */
1000         ds.fifo_count = 0;                              /*   and clear the FIFO */
1001         }
1002 
1003     for (unit = 0; unit < dptr->numunits; unit++) {     /* loop through all of the units */
1004         sim_cancel (dptr->units + unit);                /* cancel activation */
1005         dptr->units [unit].CYL = 0;                     /* reset the head position to cylinder 0 */
1006         dptr->units [unit].pos = 0;                     /* (irrelevant for the controller and timer) */
1007         }
1008     }
1009 
1010 IOPRESET (&ds_dib);                                     /* PRESET the device */
1011 ds.srq = CLEAR;                                         /* clear SRQ */
1012 
1013 return SCPE_OK;
1014 }
1015 
1016 
1017 /* Attach a drive unit.
1018 
1019    The specified file is attached to the indicated drive unit.  The library
1020    attach routine will load the heads.  This will set the First Status and
1021    Attention bits in the drive status, so we poll the drives to ensure that the
1022    CPU is notified that the drive is now online.
1023 
1024 
1025    Implementation notes:
1026 
1027     1. If we are called during a RESTORE command, the drive status will not be
1028        changed, so polling the drives will have no effect.
1029 */
1030 
ds_attach(UNIT * uptr,char * cptr)1031 t_stat ds_attach (UNIT *uptr, char *cptr)
1032 {
1033 t_stat result;
1034 
1035 result = dl_attach (&mac_cntlr, uptr, cptr);            /* attach the drive */
1036 
1037 if (result == SCPE_OK)                                  /* was the attach successful? */
1038     poll_drives ();                                     /* poll the drives to notify the CPU */
1039 
1040 return result;
1041 }
1042 
1043 
1044 /* Detach a drive unit.
1045 
1046    The specified file is detached from the indicated drive unit.  The library
1047    detach routine will unload the heads.  This will set the Attention bit in the
1048    drive status, so we poll the drives to ensure that the CPU is notified that
1049    the drive is now offline.
1050 */
1051 
ds_detach(UNIT * uptr)1052 t_stat ds_detach (UNIT *uptr)
1053 {
1054 t_stat result;
1055 
1056 result = dl_detach (&mac_cntlr, uptr);                  /* detach the drive */
1057 
1058 if (result == SCPE_OK)                                  /* was the detach successful? */
1059     poll_drives ();                                     /* poll the drives to notify the CPU */
1060 
1061 return result;
1062 }
1063 
1064 
1065 /* Boot a MAC disc drive.
1066 
1067    The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM
1068    into memory, the I/O instructions are configured for the interface card's
1069    select code, and the program is run to boot from the specified unit.  The
1070    loader supports booting from cylinder 0 of drive unit 0 only.  Before
1071    execution, the S register is automatically set as follows:
1072 
1073      15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
1074      ------  ------  ----------------------   ---------   ---------
1075      ROM #    0   1       select code         reserved      head
1076 
1077    The boot routine sets bits 15-6 of the S register to appropriate values.
1078    Bits 5-3 and 1-0 retain their original values, so S should be set before
1079    booting.  These bits are typically set to 0, although bit 5 is set for an RTE
1080    reconfiguration boot, and bits 1-0 may be set if booting from a head other
1081    than 0 is desired.
1082 
1083 
1084    Implementation notes:
1085 
1086     1. The Loader ROMs manual indicates that bits 2-0 select the head to use,
1087        implying that heads 0-7 are valid.  However, Table 5 has entries only for
1088        heads 0-3, and the boot loader code will malfunction if heads 4-7 are
1089        specified.  The code masks the head number to three bits but forms the
1090        Cold Load Read command by shifting the head number six bits to the left.
1091        As the head field in the command is only two bits wide, specifying heads
1092        4-7 will result in bit 2 being shifted into the opcode field, resulting
1093        in a Recalibrate command.
1094 */
1095 
1096 
1097 const BOOT_ROM ds_rom = {
1098     0017727,                    /* START JSB STAT      GET STATUS */
1099     0002021,                    /*       SSA,RSS       IS DRIVE READY ? */
1100     0027742,                    /*       JMP DMA         YES, SET UP DMA */
1101     0013714,                    /*       AND B20         NO, CHECK STATUS BITS */
1102     0002002,                    /*       SZA           IS DRIVE FAULTY OR HARD DOWN ? */
1103     0102030,                    /*       HLT 30B         YES, HALT 30B, "RUN" TO TRY AGAIN */
1104     0027700,                    /*       JMP START       NO, TRY AGAIN FOR DISC READY */
1105     0102011,                    /* ADDR1 OCT 102011    */
1106     0102055,                    /* ADDR2 OCT 102055    */
1107     0164000,                    /* CNT   DEC -6144     */
1108     0000007,                    /* D7    OCT 7         */
1109     0001400,                    /* STCMD OCT 1400      */
1110     0000020,                    /* B20   OCT 20        */
1111     0017400,                    /* STMSK OCT 17400     */
1112     0000000,                    /*       NOP           */
1113     0000000,                    /*       NOP           */
1114     0000000,                    /*       NOP           */
1115     0000000,                    /*       NOP           */
1116     0000000,                    /*       NOP           */
1117     0000000,                    /*       NOP           */
1118     0000000,                    /*       NOP           */
1119     0000000,                    /*       NOP           */
1120     0000000,                    /*       NOP           */
1121     0000000,                    /* STAT  NOP           STATUS CHECK SUBROUTINE */
1122     0107710,                    /*       CLC DC,C      SET STATUS COMMAND MODE */
1123     0063713,                    /*       LDA STCMD     GET STATUS COMMAND */
1124     0102610,                    /*       OTA DC        OUTPUT STATUS COMMAND */
1125     0102310,                    /*       SFS DC        WAIT FOR STATUS#1 WORD */
1126     0027733,                    /*       JMP *-1       */
1127     0107510,                    /*       LIB DC,C         B-REG = STATUS#1 WORD */
1128     0102310,                    /*       SFS DC         WAIT FOR STATUS#2 WORD */
1129     0027736,                    /*       JMP *-1       */
1130     0103510,                    /*       LIA DC,C         A-REG = STATUS#2 WORD */
1131     0127727,                    /*       JMP STAT,I    RETURN */
1132     0067776,                    /* DMA   LDB DMACW     GET DMA CONTROL WORD */
1133     0106606,                    /*       OTB 6         OUTPUT DMA CONTROL WORD */
1134     0067707,                    /*       LDB ADDR1     GET MEMORY ADDRESS */
1135     0106702,                    /*       CLC 2         SET MEMORY ADDRESS INPUT MODE */
1136     0106602,                    /*       OTB 2         OUTPUT MEMORY ADDRESS TO DMA */
1137     0102702,                    /*       STC 2         SET WORD COUNT INPUT MODE */
1138     0067711,                    /*       LDB CNT       GET WORD COUNT */
1139     0106602,                    /*       OTB 2         OUTPUT WORD COUNT TO DMA */
1140     0106710,                    /* CLDLD CLC DC        SET COMMAND INPUT MODE */
1141     0102501,                    /*       LIA 1         LOAD SWITCH */
1142     0106501,                    /*       LIB 1         REGISTER SETTINGS */
1143     0013712,                    /*       AND D7        ISOLATE HEAD NUMBER */
1144     0005750,                    /*       BLF,CLE,SLB   BIT 12=0? */
1145     0027762,                    /*       JMP *+3       NO,MANUAL BOOT */
1146     0002002,                    /*       SZA           YES,RPL BOOT. HEAD#=0? */
1147     0001000,                    /*       ALS           NO,HEAD#1, MAKE HEAD#=2 */
1148     0001720,                    /*       ALF,ALS       FORM COLD LOAD */
1149     0001000,                    /*       ALS           COMMAND WORD */
1150     0103706,                    /*       STC 6,C       ACTIVATE DMA */
1151     0103610,                    /*       OTA DC,C      OUTPUT COLD LOAD COMMAND */
1152     0102310,                    /*       SFS DC        IS COLD LOAD COMPLETED ? */
1153     0027766,                    /*       JMP *-1         NO, WAIT */
1154     0017727,                    /*       JSB STAT        YES, GET STATUS */
1155     0060001,                    /*       LDA 1         */
1156     0013715,                    /*       AND STMSK     A-REG = STATUS BITS OF STATUS#1 WD */
1157     0002002,                    /*       SZA           IS TRANSFER OK ? */
1158     0027700,                    /*       JMP START       NO,TRY AGAIN */
1159     0117710,                    /* EXIT  JSB ADDR2,I     YES, EXEC LOADED PROGRAM _@ 2055B */
1160     0000010,                    /* DMACW ABS DC        */
1161     0170100,                    /*       ABS -START    */
1162     };
1163 
ds_boot(int32 unitno,DEVICE * dptr)1164 t_stat ds_boot (int32 unitno, DEVICE *dptr)
1165 {
1166 if (unitno != 0)                                            /* boot supported on drive unit 0 only */
1167     return SCPE_NOFNC;                                      /* report "Command not allowed" if attempted */
1168 
1169 if (ibl_copy (ds_rom, ds_dib.select_code))                  /* copy the boot ROM to memory and configure */
1170     return SCPE_IERR;                                       /* return an internal error if the copy failed */
1171 
1172 SR = SR & (IBL_OPT | IBL_DS_HEAD)                           /* set S to a reasonable value */
1173   | IBL_DS | IBL_MAN | (ds_dib.select_code << IBL_V_DEV);   /*   before boot execution */
1174 
1175 return SCPE_OK;
1176 }
1177 
1178 
1179 
1180 /* MAC disc global SCP routines */
1181 
1182 
1183 /* Load or unload the drive heads.
1184 
1185    The SCP command SET DSn UNLOADED simulates setting the hardware RUN/STOP
1186    switch to STOP.  The heads are unloaded, and the drive is spun down.
1187 
1188    The SET DSn LOADED command simulates setting the switch to RUN.  The drive is
1189    spun up, and the heads are loaded.
1190 
1191    The library handles command validation and setting the appropriate drive unit
1192    status.
1193 */
1194 
ds_load_unload(UNIT * uptr,int32 value,char * cptr,void * desc)1195 t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)
1196 {
1197 const t_bool load = (value != UNIT_UNLOAD);             /* true if the heads are loading */
1198 
1199 return dl_load_unload (&mac_cntlr, uptr, load);         /* load or unload the heads */
1200 }
1201 
1202 
1203 
1204 /* MAC disc local utility routines */
1205 
1206 
1207 /* Start a command.
1208 
1209    The previously prepared command is executed by calling the corresponding
1210    library routine.  On entry, the controller's opcode field contains the
1211    command to start, and the buffer contains the command word in element 0 and
1212    the parameters required by the command, if any, beginning in element 1.
1213 
1214    If the command started, the returned pointer will point at the unit to
1215    activate (if that unit's "wait" field is non-zero).  If the returned pointer
1216    is NULL, the command failed to start, and the controller status has been set
1217    to indicate the reason.  The interface flag is set to notify the CPU of the
1218    failure.
1219 
1220 
1221    Implementation notes:
1222 
1223     1. If a command that accesses the drive is attempted on a drive currently
1224        seeking, the returned pointer will be valid, but the unit's "wait" time
1225        will be zero.  The unit must not be activated (as it already is active).
1226        When the seek completes, the command will be executed automatically.
1227 
1228        If a Seek or Cold Load Read command is attempted on a drive currently
1229        seeking, seek completion will occur normally, but Seek Check status will
1230        be set.
1231 
1232     2. For debug printouts, we want to print the name of the command (Seek or
1233        Recalibrate) in progress when a new command is started.  However, when
1234        the library routine returns, the unit operation and controller opcode
1235        have been changed to reflect the new command.  Therefore, we must record
1236        the operation in progress before calling the library.
1237 
1238        The problem is in determining which unit's operation code to record.  We
1239        cannot blindly use the unit field from the new command, as recorded in
1240        the controller, as preparation has ensured only that the target unit
1241        number is legal but not necessarily valid.  Therefore, we must validate
1242        the unit number before accessing the unit's operation code.
1243 
1244        If the unit number is invalid, the command will not start, but the
1245        compiler does not know this.  Therefore, we must ensure that the saved
1246        operation code is initialized, or a "variable used uninitialized" warning
1247        will occur.
1248 */
1249 
start_command(void)1250 static void start_command (void)
1251 {
1252 int32 unit, time;
1253 UNIT *uptr;
1254 CNTLR_OPCODE drive_command;
1255 
1256 unit = GET_S1UNIT (mac_cntlr.spd_unit);                 /* get the (prepared) unit from the command */
1257 
1258 if (unit <= DL_MAXDRIVE)                                /* is the unit number valid? */
1259     drive_command = (CNTLR_OPCODE) ds_unit [unit].OP;   /* get the opcode from the unit that will be used */
1260 else                                                    /* the unit is invalid, so the command will not start */
1261     drive_command = end;                                /*   but the compiler doesn't know this! */
1262 
1263 uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */
1264 
1265 if (uptr) {                                             /* did the command start? */
1266     time = uptr->wait;                                  /* save the activation time */
1267 
1268     if (time)                                           /* was the unit scheduled? */
1269         activate_unit (uptr);                           /* activate it (and clear the "wait" field) */
1270 
1271     if (DEBUG_PRI (ds_dev, DEB_RWSC)) {
1272         unit = uptr - ds_unit;                          /* get the unit number */
1273 
1274         if (time == 0)                                  /* was the unit busy? */
1275             fprintf (sim_deb, ">>DS rwsc: Unit %d %s in progress\n",
1276                      unit, dl_opcode_name (MAC, drive_command));
1277 
1278         fputs (">>DS rwsc: ", sim_deb);
1279 
1280         if (unit > DL_MAXDRIVE)
1281             fputs ("Controller ", sim_deb);
1282         else
1283             fprintf (sim_deb, "Unit %d position %d ", unit, uptr->pos);
1284 
1285         fprintf (sim_deb, "%s command initiated\n",
1286                  dl_opcode_name (MAC, mac_cntlr.opcode));
1287         }
1288     }
1289 
1290 else                                                    /* the command failed to start */
1291     ds_io (&ds_dib, ioENF, 0);                          /*   so set the flag to notify the CPU */
1292 
1293 return;
1294 }
1295 
1296 
1297 /* Poll the interface for a new command.
1298 
1299    If a new command is available, and the controller is not busy, prepare the
1300    command for execution.  If preparation succeeded, and the command needs
1301    parameters before executing, set the flag to request the first one from the
1302    CPU.  If no parameters are needed, the command is ready to execute.
1303 
1304    If preparation failed, set the flag to notify the CPU.  The controller
1305    status contains the reason for the failure.
1306 */
1307 
poll_interface(void)1308 static void poll_interface (void)
1309 {
1310 if (ds.cmrdy == SET && mac_cntlr.state != cntlr_busy) {     /* are the interface and controller ready? */
1311     buffer [0] = fifo_unload ();                            /* unload the command into the buffer */
1312 
1313     if (dl_prepare_command (&mac_cntlr, ds_unit, DL_MAXDRIVE)) {    /* prepare the command; did it succeed? */
1314         if (mac_cntlr.length)                                       /* does the command require parameters? */
1315             ds_io (&ds_dib, ioENF, 0);                              /* set the flag to request the first one */
1316         else                                                        /* if not waiting for parameters */
1317             start_command ();                                       /*   start the command */
1318         }
1319 
1320     else                                                /* preparation failed */
1321         ds_io (&ds_dib, ioENF, 0);                      /*   so set the flag to notify the CPU */
1322 
1323     ds.cmrdy = CLEAR;                                   /* flush the command from the interface */
1324     }
1325 
1326 return;
1327 }
1328 
1329 
1330 /* Poll the drives for attention requests.
1331 
1332    If the controller is idle and interrupts are allowed, the drives are polled
1333    to see if any drive is requesting attention.  If one is found, the controller
1334    resets that drive's Attention status, saves the drive's unit number, sets
1335    Drive Attention status, and waits for a command from the CPU.  The interface
1336    sets the flag to notify the CPU.
1337 */
1338 
poll_drives(void)1339 void poll_drives (void)
1340 {
1341 if (mac_cntlr.state == cntlr_idle && ds.control == SET)     /* is the controller idle and interrupts are allowed? */
1342     if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE))  /* poll the drives; was Attention seen? */
1343         ds_io (&ds_dib, ioENF, 0);                          /* request an interrupt */
1344 return;
1345 }
1346 
1347 
1348 /* Load a word into the FIFO.
1349 
1350    A word is loaded into the next available location in the FIFO, and the FIFO
1351    occupancy count is incremented.  If the FIFO is full on entry, the load is
1352    ignored.
1353 
1354 
1355    Implementation notes:
1356 
1357     1. The FIFO is implemented as circular queue to take advantage of REG_CIRC
1358        EXAMINE semantics.  REG->qptr is the index of the first word currently in
1359        the FIFO.  By specifying REG_CIRC, examining FIFO[0-n] will always
1360        display the words in load order, regardless of the actual array index of
1361        the start of the list.  The number of words currently present in the FIFO
1362        is kept in fifo_count (0 = empty, 1-16 = number of words available).
1363 
1364        If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the
1365        index of the new word location.  Loading stores the word there and then
1366        increments fifo_count.
1367 
1368     2. Because the load and unload routines need access to qptr in the REG
1369        structure for the FIFO array, a pointer to the REG is stored in the
1370        fifo_reg variable during device reset.
1371 */
1372 
fifo_load(uint16 data)1373 static void fifo_load (uint16 data)
1374 {
1375 uint32 index;
1376 
1377 if (FIFO_FULL) {                                            /* is the FIFO already full? */
1378     if (DEBUG_PRI (ds_dev, DEB_BUF))
1379         fprintf (sim_deb, ">>DS buf:  Attempted load to full FIFO, data %06o\n", data);
1380 
1381     return;                                                 /* return with the load ignored */
1382     }
1383 
1384 index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE;    /* calculate the index of the next available location */
1385 
1386 ds.fifo [index] = data;                                     /* store the word in the FIFO */
1387 ds.fifo_count = ds.fifo_count + 1;                          /* increment the count of words stored */
1388 
1389 if (DEBUG_PRI (ds_dev, DEB_BUF))
1390     fprintf (sim_deb, ">>DS buf:  Data %06o loaded into FIFO (%d)\n",
1391              data, ds.fifo_count);
1392 
1393 return;
1394 }
1395 
1396 
1397 /* Unload a word from the FIFO.
1398 
1399    A word is unloaded from the first location in the FIFO, and the FIFO
1400    occupancy count is decremented.  If the FIFO is empty on entry, the unload
1401    returns dummy data.
1402 
1403 
1404    Implementation notes:
1405 
1406     1. If fifo_count > 0, REG->qptr is the index of the word to remove.  Removal
1407        gets the word and then increments qptr (mod FIFO_SIZE) and decrements
1408        fifo_count.
1409 */
1410 
fifo_unload(void)1411 static uint16 fifo_unload (void)
1412 {
1413 uint16 data;
1414 
1415 if (FIFO_EMPTY) {                                           /* is the FIFO already empty? */
1416     if (DEBUG_PRI (ds_dev, DEB_BUF))
1417         fputs (">>DS buf:  Attempted unload from empty FIFO\n", sim_deb);
1418 
1419     return 0;                                               /* return with no data */
1420     }
1421 
1422 data = ds.fifo [ds.fifo_reg->qptr];                         /* get the word from the FIFO */
1423 
1424 ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE;    /* update the FIFO queue pointer */
1425 ds.fifo_count = ds.fifo_count - 1;                          /* decrement the count of words stored */
1426 
1427 if (DEBUG_PRI (ds_dev, DEB_BUF))
1428     fprintf (sim_deb, ">>DS buf:  Data %06o unloaded from FIFO (%d)\n",
1429              data, ds.fifo_count);
1430 
1431 return data;
1432 }
1433 
1434 
1435 /* Clear the FIFO.
1436 
1437    The FIFO is cleared by setting the occupancy counter to zero.
1438 */
1439 
fifo_clear(void)1440 static void fifo_clear (void)
1441 {
1442 ds.fifo_count = 0;                                      /* clear the FIFO */
1443 
1444 if (DEBUG_PRI (ds_dev, DEB_BUF))
1445     fputs (">>DS buf:  FIFO cleared\n", sim_deb);
1446 
1447 return;
1448 }
1449 
1450 
1451 /* Activate the unit.
1452 
1453    The specified unit is activated using the unit's "wait" time.  If debugging
1454    is enabled, the activation is logged to the debug file.
1455 */
1456 
activate_unit(UNIT * uptr)1457 static t_stat activate_unit (UNIT *uptr)
1458 {
1459 int32 unit;
1460 t_stat result;
1461 
1462 if (DEBUG_PRI (ds_dev, DEB_SERV)) {
1463     unit = uptr - ds_unit;                              /* calculate the unit number */
1464 
1465     if (uptr == &ds_cntlr)
1466         fprintf (sim_deb, ">>DS serv: Controller delay %d service scheduled\n",
1467                  uptr->wait);
1468     else
1469         fprintf (sim_deb, ">>DS serv: Unit %d delay %d service scheduled\n",
1470                  unit, uptr->wait);
1471     }
1472 
1473 result = sim_activate (uptr, uptr->wait);               /* activate the unit */
1474 uptr->wait = 0;                                         /* reset the activation time */
1475 
1476 return result;                                          /* return the activation status */
1477 }
1478