1 /* hp_disclib.c: HP MAC/ICD disc controller simulator library
2 
3    Copyright (c) 2011-2019, J. David Bryan
4    Copyright (c) 2004-2011, Robert M. Supnik
5 
6    Permission is hereby granted, free of charge, to any person obtaining a copy
7    of this software and associated documentation files (the "Software"), to deal
8    in the Software without restriction, including without limitation the rights
9    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10    copies of the Software, and to permit persons to whom the Software is
11    furnished to do so, subject to the following conditions:
12 
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15 
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23    Except as contained in this notice, the names of the authors shall not be
24    used in advertising or otherwise to promote the sale, use or other dealings
25    in this Software without prior written authorization from the authors.
26 
27    09-Dec-19    JDB     Replaced debugging macros with tracing macros
28    27-Dec-18    JDB     Revised fall through comments to comply with gcc 7
29    22-Apr-17    JDB     A failed sim_fseek call now causes a drive fault
30    10-Oct-16    JDB     Moved "hp3000_defs.h" inclusion from "hp_disclib.h"
31    03-Aug-16    JDB     "fmt_bitset" now allows multiple concurrent calls
32    09-Jun-16    JDB     Added casts for ptrdiff_t to int32 values
33    08-Jun-16    JDB     Corrected %d format to %u for unsigned values
34    16-May-16    JDB     DRIVE_PROPS.name is now a pointer-to-constant
35    13-May-16    JDB     Modified for revised SCP API function parameter types
36    03-May-16    JDB     Added a trace to identify the unit requesting attention
37    24-Mar-16    JDB     Changed the buffer element type from uint16 to DL_BUFFER
38    21-Mar-16    JDB     Changed uint16 types to HP_WORD
39    27-Jul-15    JDB     First revised release version
40    21-Feb-15    JDB     Revised for new controller interface model
41    24-Dec-14    JDB     Added casts for explicit downward conversions
42    27-Oct-14    JDB     Corrected the relative movement calculation in start_seek
43    20-Dec-12    JDB     sim_is_active() now returns t_bool
44    24-Oct-12    JDB     Changed CNTLR_OPCODE to title case to avoid name clash
45    07-May-12    JDB     Corrected end-of-track delay time logic
46    02-May-12    JDB     First release
47    09-Nov-11    JDB     Created disc controller common library from DS simulator
48 
49    References:
50      - 13037 Disc Controller Technical Information Package
51          (13037-90902, August 1980)
52      - HP 13365 Integrated Controller Programming Guide
53          (13365-90901, February 1980)
54      - HP 1000 ICD/MAC Disc Diagnostic Reference Manual
55          (5955-4355, June 1984)
56      - RTE-IVB System Manager's Manual
57          (92068-90006, January 1983)
58      - DVR32 RTE Moving Head Driver Source
59          (92084-18711, Revision 5000)
60 
61 
62    The 13037 multiple-access disc controller (MAC) connects from one to eight HP
63    7905 (15 MB), 7906 (20 MB), 7920 (50 MB), or 7925 (120 MB) disc drives to
64    interfaces installed in from one to eight HP 1000, 2000, or 3000 CPUs.  The
65    drives use a common command set and present data to the controller
66    synchronously at a data rate of 468.75 kilowords per second (2.133
67    microseconds per word).
68 
69    The controller hardware consists of three PCAs: a 16-bit microprogrammed
70    processor constructed from 74S181 bit slices operating at 5 MHz, a device
71    controller that provides the interconnections to the drives and CPU
72    interfaces, and an error correction controller that enables the correction of
73    up to 32-bit error bursts.  1024 words of 24-bit firmware are stored in ROM
74    on the error correction PCA, and the execution time is 200 nanoseconds per
75    instruction.
76 
77    The Integrated Controller Drive (ICD) models include the HP 7906H, 7920H, and
78    7925H.  These drives are identical to the corresponding MAC drives, except
79    that they integrate a single-CPU version of the MAC controller on two PCAs
80    housed within the drive: an 8-bit microprocessor constructed from two 4-bit
81    slices operating at 3.75 MHz, and an 8-bit DMA that handles the data path
82    between the drive and CPU.  Connection to the CPU is via the Hewlett-Packard
83    Interface Bus (HP-IB) -- HP's implementation of the IEEE-488 standard.
84 
85    The ICD command set essentially is the MAC command set modified for
86    single-unit operation.  The unit number and CPU hold bit fields in the opcode
87    words are unused in the ICD implementation.  The Load TIO Register, Wakeup,
88    and Request Syndrome commands are removed, as Load TIO is used with the HP
89    3000, Wakeup is used in a multi-CPU environment, and the simpler ICD
90    controller does not support ECC.  Controller status values 02B (Unit
91    Available) and 27B (Unit Unavailable) are dropped as the controller supports
92    only single units, 12B (I/O Program Error) is reused to indicate HP-IB
93    protocol errors, 13B (Sync Not Received) is added, and 17B (Possibly
94    Correctable Data Error) is removed as error correction is not supported.
95 
96    Some minor redefinitions also occur.  For example, status 14B (End of
97    Cylinder) is expanded to include an auto-seek beyond the drive limits, and
98    37B (Drive Attention) is restricted to just head unloads (from head loads and
99    unloads).
100 
101    The MAC controller offers an HP-IB option: the HP 12745A Disc Controller to
102    HP-IB Adapter Kit.  This card plugs into the 13037's chassis containing the
103    other three controller cards and connects to the CPU interface port of the
104    device controller PCA in place of the multi-CPU-interface cable.  It allows
105    HP-IB 3000s and the HP 64000 Logic Development Station to connect to MAC disc
106    drives; the ICD drives are not supported on these systems.
107 
108    This library provides the common functions required by HP disc controllers.
109    It implements the 13037 MAC and 13365 ICD controller command sets used with
110    the 7905/06/20/25 and 7906H/20H/25H disc drives.
111 
112    The library is an adaptation of the code originally written by Bob Supnik
113    for the HP2100 DS simulator.  DS simulates a 13037 controller connected via a
114    13175 disc interface to an HP 1000 computer.  To create the library, the
115    functions of the controller were separated from the functions of the
116    interface.  This allows the library to work with other CPU interfaces, such
117    as the 12821A HP-IB disc interface, that use substantially different
118    communication protocols.  The library functions implement the controller
119    command set for the drive units.  The interface functions handle the transfer
120    of commands and data to and from the CPU.
121 
122    The original release of this library did not handle the data transfer between
123    the controller and the interface directly.  Instead, data was moved between
124    the interface and a sector buffer by the interface simulator, and then the
125    buffer was passed to the disc library for reading or writing.  This buffer
126    was also used to pass disc commands and parameters to the controller, and to
127    receive status information from the controller.
128 
129    While this approach served to allow the library to be shared between
130    dissimilar interfaces, each interface had to have intimate knowledge of the
131    internal controller state in order to schedule parameter and data transfers.
132    In particular, the unit service routine had to base its actions on specific
133    controller phase and opcode pairs and manipulate the internal state variables
134    of the controller.  As such, the library could not be viewed opaquely.
135 
136    In addition, the HP 3000 interface required channel program support that was
137    not provided by the simulation library although it was present in hardware.
138    Adapting the existing library model would have placed an even larger and more
139    intimate burden on the interface simulation.
140 
141    As a result, the library API was rewritten to model the hardware more
142    closely and provide a more strict separation of controller and interface
143    functions.  Instead of providing separate routines to prepare, start, and end
144    commands, service units, and poll drives for Attention status, the new model
145    provides a single routine that represents the hardware data, flag, and
146    function buses between the interface and controller.  The interface calls
147    this routine whenever the state of the flag bus changes, and the controller
148    responds by potentially changing the data and function buses.  The interface
149    merely responds to those changes without requiring any other knowledge of the
150    internal state of the controller.
151 
152 
153    A device interface simulator interacts with the disc controller simulator via
154    the dl_controller routine, which simulates the command, status, and data
155    interconnection between the interface and controller.  Utility routines are
156    also provided to attach and detach disc image files from drive units, load or
157    unload the drive's heads, set drive model and protection status, select the
158    interface timing mode (real or fast), and enable overriding of disc command
159    status returns for diagnostics.
160 
161    In hardware, the interface and controller are interconnected via a 16-bit
162    bidirectional data bus (IBUS), a 6-bit flag bus and one signal (CLEAR) to
163    the controller, and a 4-bit function bus (IFNBUS) and four signals (ENID,
164    ENIR, IFVLD, and IFCLK) to the interface.  The interface initiates controller
165    action by changing the state of the flag bus, and the controller responds by
166    asserting a function on the function bus.  For example, the interface starts
167    a disc command by asserting CMRDY on the flag bus.  The controller responds
168    by placing the IFGTC (Interface Get Command) function on the function bus and
169    asserting the ENID (Enable Interface Drivers) and IFVLD (Interface Function
170    Valid) signals.  The interface then replies by placing the command on the
171    data bus, where it is read by the controller.  The controller then decodes
172    the command and initiates processing.
173 
174    The controller microprogram runs continuously.  However, command execution
175    pauses in various wait loops whenever the controller must suspend until an
176    external event occurs.  For example, an Address Record command waits first
177    for the CPU to send the cylinder address and then waits again for the CPU to
178    send the head/sector address.  The controller then saves these values in
179    registers before completing the command and then waiting for the CPU to send
180    a new command.
181 
182    In simulation, the dl_controller routine is called with a set of flags and
183    the content of the data bus whenever the flag state changes or a service
184    event occurs.  The routine returns a set of functions and the new content of
185    the data bus.  To use the above example, dl_controller would be called with
186    CMRDY and the command word and would return IFGTC; the data bus return value
187    would not be used in this case.  In hardware, the controller might send a
188    series of individual functions to the interface in response to a single
189    invocation.  In simulation, this series would be collected into a single
190    function set for return.
191 
192    Hardware wait loops are simulated by the dl_controller routine returning to
193    the caller until the expected external event occurs.  In the Address Record
194    example, dl_controller would be called first when the command is issued by
195    the CPU.  The routine would initiate command processing and then return to
196    wait for the cylinder address.  When the CPU provided the address, the
197    interface simulator would call dl_controller again with the cylinder value.
198    The routine would then return to wait for the head/sector address.  When it
199    was available, dl_controller would be called with the value, and the routine
200    would complete the command and return to the caller to wait for a new
201    command.  So, in simulation, the controller only "runs" when it has work to
202    do.
203 
204    A controller instance is represented by a CNTLR_VARS structure, which
205    maintains the controller's internal state.  A MAC interface will have a
206    single controller instance that controls up to eight drive units, whereas an
207    ICD interface will have one controller instance per drive unit.  The minor
208    differences in controller action between the two are handled internally.
209 
210    The interface simulator must declare one unit for each disc drive to be
211    controlled by the library.  For a MAC controller, eight units are required,
212    plus one additional unit for the controller itself.  For an ICD controller,
213    only one unit is required.
214 
215    The controller maintains five values in each drive's unit structure:
216 
217      u3 (CYL)    -- the current drive cylinder
218      u4 (STATUS) -- the drive status (Status-2)
219      u5 (OPCODE) -- the drive current operation in process
220      u6 (PHASE)  -- the drive current operation phase
221      pos         -- the current byte offset into the disc image file
222 
223    Drives maintain their cylinder (head positioner) locations separate from the
224    cylinder location stored in the controller.  This allows the controller to
225    implement sparing by positioning to one location while storing a different
226    location in the sector headers.  It also allows seek retries by issuing a
227    Recalibrate (which moves the positioner to cylinder 0) followed by the
228    original read or write (which repositioned to the cylinder stored in the
229    controller).
230 
231    The drive status field contains only a subset of the status maintained by
232    drives in hardware.  Specifically, the Attention, Read-Only, First Status,
233    Fault, and Seek Check bits are stored in the status field.  The other bits
234    (Format Enabled, Not Ready, and Drive Busy) are set dynamically whenever
235    status is requested.
236 
237    Per-drive opcode and phase values allow seeks to be overlapped.  For example,
238    a Seek issued to unit 0 may be followed by a Read issued to unit 1.  When the
239    seek completes on unit 0, its opcode and phase values will let the controller
240    set the appropriate seek completion status without disturbing the values
241    currently in-use by unit 1.
242 
243    The simulation defines these command phases:
244 
245      Idle        -- the unit is not currently executing a command
246      Parameter   -- the unit is obtaining or returning parameter values
247      Seek        -- the unit is seeking to a new head position
248      Rotate      -- the unit is rotating into position to access a sector
249      Data        -- the unit is obtaining or returning sector data values
250      Intersector -- the unit is rotating between sectors
251      End         -- the unit is completing a command
252 
253    A value represents the current state of the unit.  If a unit is active, the
254    phase will end when the unit is serviced.
255 
256    In addition to the controller structure(s), an interface declares a data
257    buffer to be used for sector transfers.  The buffer is an array containing
258    DL_BUFSIZE 16-bit elements; the address of the buffer is stored in the
259    controller state structure.  The controller maintains the current index into
260    the buffer, as well as the length of valid data stored there.  Only one
261    buffer is needed per interface, regardless of the number of controllers or
262    units handled, as a single interface cannot perform data transfers on one
263    drive concurrently with a command directed to another drive.
264 
265    An interface is also responsible for declaring a structure of type
266    DELAY_PROPS that contains the timing values for the controller when in
267    FASTTIME mode.  The values are event counts for these actions:
268 
269      - track-to-track seek time
270      - full-stroke seek time
271      - full sector rotation time
272      - per-word data transfer time
273      - intersector gap time
274      - controller execution overhead time
275 
276    These values are typically exposed via the interface's register set and so
277    may be altered by the user.  A macro, DELAY_INIT, is provided to initialize
278    the structure.
279 
280    An interface may optionally declare an array of DIAG_ENTRY structures if it
281    wishes to use the diagnostic override capability.  Diagnostic overrides are
282    used to return controller status values that otherwise are not simulated to a
283    diagnostic program.  An example would be a Correctable Data Error or a
284    Head-Sector Miscompare.  If this facility is to be used, a pointer to the
285    array is placed in the CNTLR_VARS structure when it is initialized, and the
286    array itself is initialized with the DL_OVEND value that indicates that no
287    overrides are currently defined.
288 
289    If the pointer is set, then when each command is started, the cylinder, head,
290    sector, and opcode values from the current override entry are checked against
291    the corresponding current controller values.  If a match occurs, then the
292    controller status and Spare/Protected/Defective values are set from the entry
293    rather than being cleared, and the pointer is moved to the next entry.  These
294    values will then be returned as the completion status of the current command.
295 
296    If the command performs address verification, then any SPD value(s) will be
297    used as the result of the verification.  In particular, setting the P bit for
298    a Write will cause a Protected Track error if the FORMAT switch is not on,
299    and any status value other than Normal Completion, Correctable Data Error, or
300    Uncorrectable Data Error will cause a verification abort.
301 
302    In hardware, the errors that may occur during verification are Cylinder
303    Miscompare, Head-Sector Miscompare, Sync Timeout, Illegal Spare Access, and
304    Defective Track; any of these errors may be simulated.  In addition, an
305    Uncorrectable Data Error may occur in hardware if the controller is unable to
306    verify any of the 16 sectors starting at the sector preceding the target
307    sector, but this error cannot be simulated.
308 
309    Specifying either a Correctable Data Error or an Uncorrectable Data Error
310    will cause an abort at the end of the first sector of a read, write, or
311    verify command.
312 
313    Correctable Data Error and Uncorrectable Data Error may also be specified for
314    the Request Syndrome command.  A table entry with the former status value is
315    always followed by an additional entry that contains the values to be
316    returned for the three syndrome words and the displacement.
317 
318    The last defined table entry always contains a special end-of-table value.
319 
320    The controller library provides a macro, DL_MODS, that initializes MTAB
321    entries, and two utility routines, dl_set_diag and dl_show_diag, that provide
322    a user interface for setting up a table of diagnostic overrides.  See the
323    comments for these routines below for the command syntax.
324 
325    A macro, CNTLR_INIT, is provided to initialize the controller structure from
326    the following parameters:
327 
328      - the type of the controller (MAC or ICD)
329      - the simulation DEVICE structure on which the controller operates
330      - the data buffer array
331      - the diagnostic override array or NULL if not used
332      - the structure containing the FASTTIME values
333 
334    A macro, DL_REGS, is also provided that initializes a set of REG structures
335    to provide a user interface to the controller structure.
336 
337    In hardware, disc drives respond to commands issued by the controller.  The
338    only unsolicited status from drives occurs when the heads are loaded or
339    unloaded by the operator.  In simulation, SET <dev> UNLOAD and SET <dev> LOAD
340    commands represent these actions.  The controller must be notified by calling
341    the dl_load_unload routine in response to changes in a disc drive's RUN/STOP
342    switch.
343 
344    Finally, the controller library provides extensive tracing of its internal
345    operations via debug logging.  Six debug flags are declared for use by the
346    interface simulator.  When enabled, these report controller actions at
347    various levels of detail.
348 
349 
350    Implementation notes:
351 
352     1. The library does not simulate sector headers and trailers.  Initialize
353        and Write Full Sector commands ignore the SPD bits and the supplied
354        header and trailer words.  Read Full Sector fills in the header with the
355        current CHS address and sets the SPD bits to zero.  The CRC and ECC words
356        in the trailer are returned as zeros.  Programs that depend on drives
357        retaining the set values will fail.
358 
359     2. The library does not simulate drive hold bits or support multiple CPU
360        interfaces connected to the same controller.  CPU access to a valid drive
361        always succeeds.
362 
363     3. The sector buffer is an array of 16-bit elements.  Byte-oriented
364        interface simulators, such as the 12821A HP-IB Disc Interface, must do
365        their own byte packing and unpacking.
366 
367     4. In hardware, a command pending on an interface (CMRDY asserted) while a
368        previous command is executing will be started as soon as the current
369        command completes.  In simulation, dl_controller will exit when the
370        current command completes and must be called again if CMRDY is asserted.
371        This is necessary to allow the completion status of the prior command to
372        be returned to the interface before the new command is started.
373 */
374 
375 
376 
377 #include <math.h>
378 
379 #include "hp3000_defs.h"                        /* this must reflect the machine used */
380 #include "hp_disclib.h"
381 
382 
383 
384 /* Program constants */
385 
386 #define CNTLR_UNIT          (DL_MAXDRIVE + 1)   /* controller unit number */
387 #define MAX_UNIT            10                  /* last legal unit number */
388 
389 #define WORDS_PER_SECTOR    128                 /* data words per sector */
390 
391 #define UNTALK_DELAY        160                 /* ICD untalk delay (constant instruction count) */
392 #define CNTLR_TIMEOUT       S (1.74)            /* command and parameter wait timeout (1.74 seconds) */
393 
394 #define NO_EVENT            -1                  /* do not schedule an event */
395 
396 #define NO_ACTION           (CNTLR_IFN_IBUS) (NO_FUNCTIONS | NO_DATA)
397 
398 
399 /* Controller unit pointer */
400 
401 #define CNTLR_UPTR          (cvptr->device->units + cvptr->device->numunits - 1)
402 
403 
404 /* Unit flags accessor */
405 
406 #define GET_MODEL(f)        (DRIVE_TYPE) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK)
407 
408 
409 /* Controller clear types */
410 
411 typedef enum {
412     Hard_Clear,                                 /* power-on/preset hard clear */
413     Timeout_Clear,                              /* command or parameter timeout clear */
414     Soft_Clear                                  /* programmed soft clear */
415     } CNTLR_CLEAR;
416 
417 
418 /* Command accessors.
419 
420    Disc commands are passed across the data bus to the controller with the CMRDY
421    flag asserted.  The commands have several forms, depending on the particular
422    opcode:
423 
424        15| 14  13  12| 11  10  9 | 8   7   6 | 5   4   3 | 2   1   0    HP 1000 numbering
425      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
426      | -   -   - |  command opcode   | -   -   -   -   -   -   -   - |  form 1
427      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
428      | -   -   - |  command opcode   | -   -   -   - |  unit number  |  form 2
429      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
430      | -   -   - |  command opcode   | H | -   -   - |  unit number  |  form 3
431      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
432      | S | P | D |  command opcode   | H | -   -   - |  unit number  |  form 4
433      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
434      | -   -   - |  command opcode   |    retries    | D | S | C | A |  form 5
435      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
436      | -   -   - |  command opcode   | head  |        sector         |  form 6
437      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
438        0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15    HP 3000 numbering
439 
440    Form 1 is used by the Address Record, Clear, End, Load TIO Register, Request
441    Disc Address, and Request Syndrome commands.
442 
443    Form 2 is used by the Request Disc Sector and Request Status commands.
444 
445    Form 3 is used by the Read, Read Full Sector, Read With Offset, Read Without
446    Verify, Recalibrate, Seek, Verify, Wakeup, Write, and Write Full Sector
447    commands, where:
448 
449      H = hold the drive
450 
451    Form 4 is used by the Initialize Command, where:
452 
453      S = initialize the track to spare status
454      P = initialize the track to protected status
455      D = initialize the track to defective status
456      H = hold the drive
457 
458    Form 5 is used by the Set File Mask command, where:
459 
460      D = decremental seek
461      S = sparing enabled
462      C = cylinder mode
463      A = auto-seek enabled
464 
465    Form 6 is used by the Cold Load Read command.
466 */
467 
468 #define CM_OPCODE_MASK      0017400u            /* operation code mask */
469 #define CM_UNIT_MASK        0000017u            /* unit number mask */
470 
471 #define CM_SPARE            0100000u            /* spare track */
472 #define CM_PROTECTED        0040000u            /* protected track */
473 #define CM_DEFECTIVE        0020000u            /* defective track */
474 #define CM_SPD_MASK         (CM_SPARE | CM_PROTECTED | CM_DEFECTIVE)
475 
476 #define CM_RETRY_MASK       0000360u            /* retry count mask */
477 #define CM_FILE_MASK_MASK   0000017u            /* file mask mask */
478 
479 #define CM_DECR_SEEK        0000010u            /* 0/1 = incremental/decremental seek */
480 #define CM_SPARE_EN         0000004u            /* sparing enabled */
481 #define CM_CYL_MODE         0000002u            /* 0/1 = surface/cylinder mode */
482 #define CM_AUTO_SEEK_EN     0000001u            /* auto-seek enabled */
483 
484 #define CM_HEAD_MASK        0000300u            /* cold load read head mask */
485 #define CM_SECTOR_MASK      0000077u            /* cold load read sector mask */
486 
487 
488 #define CM_OPCODE_SHIFT     8
489 #define CM_UNIT_SHIFT       0
490 
491 #define CM_RETRY_SHIFT      4
492 #define CM_FILE_MASK_SHIFT  0
493 
494 #define CM_HEAD_SHIFT       6
495 #define CM_SECTOR_SHIFT     0
496 
497 
498 #define CM_SPD(c)           ((c) & CM_SPD_MASK)
499 
500 #define CM_OPCODE(c)        (CNTLR_OPCODE) (((c) & CM_OPCODE_MASK) >> CM_OPCODE_SHIFT)
501 
502 #define CM_UNIT(c)          (((c) & CM_UNIT_MASK)      >> CM_UNIT_SHIFT)
503 
504 #define CM_RETRY(c)         (((c) & CM_RETRY_MASK)     >> CM_RETRY_SHIFT)
505 #define CM_FILE_MASK(c)     (((c) & CM_FILE_MASK_MASK) >> CM_FILE_MASK_SHIFT)
506 
507 #define CM_HEAD(c)          (((c) & CM_HEAD_MASK)      >> CM_HEAD_SHIFT)
508 #define CM_SECTOR(c)        (((c) & CM_SECTOR_MASK)    >> CM_SECTOR_SHIFT)
509 
510 
511 static const BITSET_NAME file_mask_names [] = {     /* File mask word */
512     "\1decremental seek\0incremental seek",         /* bit  3/12 */
513     "sparing",                                      /* bit  2/13 */
514     "\1cylinder mode\0surface mode",                /* bit  1/14 */
515     "autoseek"                                      /* bit  0/15 */
516     };
517 
518 static const BITSET_FORMAT file_mask_format =       /* names, offset, direction, alternates, bar */
519     { FMT_INIT (file_mask_names, 0, msb_first, has_alt, append_bar) };
520 
521 
522 /* Parameter accessors.
523 
524    Parameters are passed across the data bus to the controller with the DTRDY
525    flag asserted.  The parameters have several forms, depending on the commands
526    requesting them:
527 
528        15| 14  13  12| 11  10  9 | 8   7   6 | 5   4   3 | 2   1   0    HP 1000 numbering
529      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
530      |                           cylinder                            |  form 1  (in/out)
531      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
532      |     0     |       head        |            sector             |  form 2  (in/out)
533      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
534      | S | P | D |    status code    | -   -   -   - |  unit number  |  form 3  (out)
535      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
536      | E | -   - |   drive type  | - | A | R | F | L | S | K | N | B |  form 4  (out)
537      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
538      |               0               |            sector             |  form 5  (out)
539      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
540      |                         sector count                          |  form 6  (in)
541      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
542      |                         displacement                          |  form 7  (out)
543      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
544      |                            pattern                            |  form 8  (out)
545      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
546      |                           data word                           |  form 9  (in)
547      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
548      |                       | A | D | S | - | cyl offset magnitude  |  form 10 (in)
549      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
550        0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15    HP 3000 numbering
551 
552    Forms 1 and 2 are used by the Address Record, Request Disc Address, Request
553    Syndrome, and Seek commands.
554 
555    Form 3 is used by the Request Status and Request Syndrome commands, where:
556 
557      S = last track was a spare
558      P = last track was protected
559      D = last track was defective
560 
561    Form 4 is used by the Request Status command, where:
562 
563      E = error present
564      A = attention
565      R = read-only
566      F = format enabled
567      L = drive fault
568      S = first status
569      K = seek check
570      N = not ready
571      B = drive busy
572 
573    Form 5 is used by the Request Sector Address command.
574 
575    Form 6 is used by the Verify command.
576 
577    Forms 7 and 8 are used by the Request Syndrome command.
578 
579    Form 9 is used by the Load TIO Register command.
580 
581    Form 10 is used by the Read With Offset command, where:
582 
583      A = advance the clock (valid for 13037A only)
584      D = delay the clock (valid for 13037A only)
585      S = sign of cylinder offset
586 */
587 
588 #define S1_SPARE            0100000u            /* spare track */
589 #define S1_PROTECTED        0040000u            /* protected track */
590 #define S1_DEFECTIVE        0020000u            /* defective track */
591 #define S1_STATUS_MASK      0017400u            /* encoded termination status mask */
592 #define S1_UNIT_MASK        0000017u            /* unit number mask */
593 
594 #define S1_STATUS_SHIFT     8
595 #define S1_UNIT_SHIFT       0
596 
597 #define S1_STATUS(n)        ((n) << S1_STATUS_SHIFT & S1_STATUS_MASK)
598 #define S1_UNIT(n)          ((n) << S1_UNIT_SHIFT   & S1_UNIT_MASK)
599 
600 
601 #define S2_ERROR            0100000u            /* any error */
602 #define S2_DRIVE_TYPE_MASK  0017000u            /* drive type mask */
603 #define S2_ATTENTION        0000200u            /* attention */
604 #define S2_READ_ONLY        0000100u            /* read-only */
605 #define S2_FORMAT_EN        0000040u            /* format enabled */
606 #define S2_FAULT            0000020u            /* drive fault */
607 #define S2_FIRST_STATUS     0000010u            /* first status */
608 #define S2_SEEK_CHECK       0000004u            /* seek check */
609 #define S2_NOT_READY        0000002u            /* not ready */
610 #define S2_BUSY             0000001u            /* drive busy */
611 
612 #define S2_STOPS            (S2_FAULT \
613                                | S2_SEEK_CHECK \
614                                | S2_NOT_READY)  /* bits that stop drive access */
615 
616 #define S2_ERRORS           (S2_FAULT \
617                                | S2_SEEK_CHECK \
618                                | S2_NOT_READY \
619                                | S2_BUSY)       /* bits that set S2_ERROR */
620 
621 #define S2_CPS              (S2_ATTENTION \
622                                | S2_FAULT \
623                                | S2_FIRST_STATUS \
624                                | S2_SEEK_CHECK) /* bits that are cleared by Controller Preset */
625 
626 #define S2_DRIVE_TYPE_SHIFT 9
627 
628 #define S2_DRIVE_TYPE(n)    ((n) << S2_DRIVE_TYPE_SHIFT & S2_DRIVE_TYPE_MASK)
629 #define S2_TO_DRIVE_TYPE(n) (((n) & S2_DRIVE_TYPE_MASK) >> S2_DRIVE_TYPE_SHIFT)
630 
631 
632 #define PIO_HEAD_MASK       0017400u            /* head mask */
633 #define PIO_SECTOR_MASK     0000377u            /* sector mask */
634 
635 #define PI_ADV_CLOCK        0001000u            /* advance clock */
636 #define PI_DEL_CLOCK        0000400u            /* delay clock */
637 #define PI_NEG_OFFSET       0000200u            /* 0/1 = positive/negative cylinder offset sign */
638 #define PI_OFFSET_MASK      0000077u            /* cylinder offset mask */
639 
640 
641 #define PIO_HEAD_SHIFT      8
642 #define PIO_SECTOR_SHIFT    0
643 
644 #define PI_OFFSET_SHIFT     0
645 
646 
647 #define PI_HEAD(p)          (((p) & PIO_HEAD_MASK)   >> PIO_HEAD_SHIFT)
648 #define PI_SECTOR(p)        (((p) & PIO_SECTOR_MASK) >> PIO_SECTOR_SHIFT)
649 #define PI_OFFSET(p)        (((p) & PI_OFFSET_MASK)  >> PI_OFFSET_SHIFT)
650 
651 #define PO_HEAD(n)          (((n) << PIO_HEAD_SHIFT   & PIO_HEAD_MASK))
652 #define PO_SECTOR(n)        (((n) << PIO_SECTOR_SHIFT & PIO_SECTOR_MASK))
653 
654 
655 static const BITSET_NAME status_1_names [] = {  /* Status-1 word */
656     "spare",                                    /* bit 15/0 */
657     "protected",                                /* bit 14/1 */
658     "defective"                                 /* bit 13/2 */
659     };
660 
661 static const BITSET_FORMAT status_1_format =    /* names, offset, direction, alternates, bar */
662     { FMT_INIT (status_1_names, 13, msb_first, no_alt, append_bar) };
663 
664 static const BITSET_FORMAT initialize_format =  /* names, offset, direction, alternates, bar */
665     { FMT_INIT (status_1_names, 13, msb_first, no_alt, no_bar) };
666 
667 
668 static const BITSET_NAME status_2_names [] = {  /* Status-2 word */
669     "attention",                                /* bit  7/ 8 */
670     "read only",                                /* bit  6/ 9 */
671     "format enabled",                           /* bit  5/10 */
672     "fault",                                    /* bit  4/11 */
673     "first status",                             /* bit  3/12 */
674     "seek check",                               /* bit  2/13 */
675     "not ready",                                /* bit  1/14 */
676     "busy"                                      /* bit  0/15 */
677     };
678 
679 static const BITSET_FORMAT status_2_format =    /* names, offset, direction, alternates, bar */
680     { FMT_INIT (status_2_names, 0, msb_first, no_alt, no_bar) };
681 
682 
683 static const BITSET_NAME offset_names [] = {    /* Read With Offset parameter */
684     "advanced clock",                           /* bit  9/ 6 */
685     "delayed clock"                             /* bit  8/ 7 */
686     };
687 
688 static const BITSET_FORMAT offset_format =      /* names, offset, direction, alternates, bar */
689     { FMT_INIT (offset_names, 8, msb_first, no_alt, append_bar) };
690 
691 
692 /* Drive properties table.
693 
694    In hardware, drives report their drive type numbers to the controller upon
695    receipt of a Request Status tag bus command.  The drive type is used to
696    determine the legal range of head and sector addresses (the drive itself will
697    validate the cylinder address during a Seek command and the head/sector
698    address during an Address Record drive command).
699 
700    In simulation, the model ID number from the unit flags is used as an index
701    into the drive properties table.  The table is used to validate seek
702    parameters and to provide the mapping between CHS addresses and the linear
703    byte addresses required by the host file access routines.
704 
705    The 7905/06(H) drives consist of removable and fixed platters, whereas the
706    7920(H)/25(H) drives have only removable multi-platter packs.  As a result,
707    7905/06 drives are almost always accessed in platter mode, i.e., a given
708    logical disc area is fully contained on either the removable or fixed
709    platter, whereas the 7920/25 drives are almost always accessed in cylinder
710    mode with logical disc areas spanning some or all of the platters.
711 
712    Disc image files are arranged as a linear set of tracks.  To improve
713    locality of access, tracks in the 7905/06 images are grouped per-platter,
714    whereas tracks on the 7920 and 7925 are sequential by cylinder and head
715    number.
716 
717    The simulator maps the tracks on the 7905/06 removable platter (heads 0 and
718    1) to the first half of the disc image, and the tracks on the fixed platter
719    (heads 2 and, for the 7906 only, 3) to the second half of the image.  For the
720    7906(H), the cylinder-head order of the tracks is 0-0, 0-1, 1-0, 1-1, ...,
721    410-0, 410-1, 0-2, 0-3, 1-2, 1-3, ..., 410-2, 410-3.  The 7905 order is the
722    same, except that head 3 tracks are omitted.
723 
724    For the 7920(H)/25(H), all tracks appear in cylinder-head order, e.g., 0-0,
725    0-1, 0-2, 0-3, 0-4, 1-0, 1-1, ..., 822-2, 822-3, 822-4 for the 7920(H).
726 
727    This variable-access geometry is accomplished by defining separate "heads per
728    cylinder" values for the fixed and removable sections of each drive that
729    indicates the number of heads that should be grouped for locality.  The
730    removable values are set to 2 on the 7905 and 7906, indicating that those
731    drives typically use cylinders consisting of two heads.  They are set to the
732    number of heads per drive for the 7920 and 7925, as those typically use
733    cylinders encompassing the entire pack.
734 
735    The Drive Type is reported by the controller in the second status word
736    (Status-2) returned by the Request Status command.
737 */
738 
739 typedef struct {
740     const char  *name;                          /* drive name */
741     uint32      sectors;                        /* sectors per head */
742     uint32      heads;                          /* heads per cylinder*/
743     uint32      cylinders;                      /* cylinders per drive */
744     uint32      words;                          /* words per drive */
745     uint32      remov_heads;                    /* number of removable-platter heads */
746     uint32      fixed_heads;                    /* number of fixed-platter heads */
747     } DRIVE_PROPS;
748 
749 static const DRIVE_PROPS drive_props [] = {     /* indexed by DRIVE_TYPE */
750    /*  drive   sectors    heads   cylinders      words     remov  fixed */
751    /*  name    per trk   per cyl  per drive    per drive   heads  heads */
752    /* -------  -------   -------  ----------  -----------  -----  ----- */
753     { "7906",    48,       4,        411,     WORDS_7906,    2,     2   },     /* drive type 0 */
754     { "7920",    48,       5,        823,     WORDS_7920,    5,     0   },     /* drive type 1 */
755     { "7905",    48,       3,        411,     WORDS_7905,    2,     1   },     /* drive type 2 */
756     { "7925",    64,       9,        823,     WORDS_7925,    9,     0   }      /* drive type 3 */
757     };
758 
759 
760 /* Delay properties table.
761 
762    To support the realistic timing mode, the delay properties table contains
763    timing specifications for the supported disc drives.  The times represent the
764    delays for mechanical and electronic operations.  Delay values are in event
765    tick counts; macros are used to convert from times to ticks.
766 
767    The drive type field differentiates between drive models available on a given
768    controller.  The field is not significant for MAC and ICD controllers because
769    all of the drives supported have the same specifications.
770 
771    The controller overhead values are estimates; they do not appear to be
772    documented for MAC and ICD controllers, although they are published for
773    various CS/80 drives.
774 */
775 
776 static const DELAY_PROPS real_times [] = {
777    /* cntlr   drive     seek     seek       sector        data     intersector   cntlr   */
778    /* type     type    trk-trk   full      rotation     per word       gap      overhead */
779    /* -----  --------  -------  --------  -----------  ----------  -----------  -------- */
780     { MAC,   HP_All,   mS (5),  mS (45),  uS (347.2),  uS (2.13),  uS (27.2),   uS (200) },
781     { ICD,   HP_All,   mS (5),  mS (45),  uS (347.2),  uS (2.13),  uS (27.2),   mS (1.5) }
782     };
783 
784 #define DELAY_COUNT         (sizeof real_times / sizeof real_times [0])
785 
786 
787 /* Estimate the current sector.
788 
789    The sector currently passing under the disc heads is estimated from the
790    current "simulation time," which is the number of event ticks since the
791    simulation run was started, and the simulated disc rotation time.  The
792    computation logic is:
793 
794      current_sector := (simulator_time / per_sector_time) MOD sectors_per_track;
795 */
796 
797 #define CURRENT_SECTOR(cvptr,uptr) \
798             (uint32) fmod (sim_gtime () / cvptr->dlyptr->sector_full, \
799                            drive_props [GET_MODEL (uptr->flags)].sectors)
800 
801 
802 /* Command properties table.
803 
804    The validity of each command for a given controller type is checked against
805    the command properties table when it is prepared for execution.  The table
806    also includes the count of inbound or outbound parameters, the class of the
807    command, and flags that indicate certain common actions that are be taken.
808 
809 
810    Implementation notes:
811 
812     1. The verify field of the Read_Without_Verify property record is set to
813        TRUE so that address verification will be done if a track boundary is
814        crossed.  Initial verification is suppressed by setting the controller's
815        verify field to FALSE during initial Read_Without_Verify processing.
816 */
817 
818 typedef struct {
819     uint32       param_count;                   /* count of input or output parameters */
820     CNTLR_CLASS  classification;                /* command classification */
821     t_bool       valid [CNTLR_COUNT];           /* command validity, indexed by CNTLR_TYPE */
822     t_bool       clear_status;                  /* command clears the controller status */
823     t_bool       unit_field;                    /* command has a unit field */
824     t_bool       unit_check;                    /* command checks the unit number validity */
825     t_bool       unit_access;                   /* command accesses the drive unit */
826     t_bool       seek_wait;                     /* command waits for seek completion */
827     t_bool       verify_address;                /* command does address verification */
828     t_bool       idle_at_end;                   /* command idles the controller at completion */
829     uint32       preamble_size;                 /* size of preamble in words */
830     uint32       transfer_size;                 /* size of data transfer in words */
831     uint32       postamble_size;                /* size of postamble in words */
832     } COMMAND_PROPERTIES;
833 
834 typedef const COMMAND_PROPERTIES *PRPTR;
835 
836 #define T   TRUE
837 #define F   FALSE
838 
839 static const COMMAND_PROPERTIES cmd_props [] = {
840 /*   parm      opcode        valid for    clr  unit unit unit seek addr end  pre  xfer post   */
841 /*   I/O   classification   MAC ICD CS80  stat fld  chk  acc  wait verf idle size size size   */
842 /*   ----  --------------   --- --- ----  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----   */
843     {  0,  Class_Read,     { T,  T,  F },  T,   F,   T,   T,   F,   T,   F,   15, 128,  7  }, /* 00 = Cold_Load_Read */
844     {  0,  Class_Control,  { T,  T,  F },  T,   T,   T,   T,   T,   F,   T,    0,  0,   0  }, /* 01 = Recalibrate */
845     {  2,  Class_Control,  { T,  T,  F },  T,   T,   T,   T,   F,   F,   T,    0,  0,   0  }, /* 02 = Seek */
846     {  2,  Class_Status,   { T,  T,  F },  F,   T,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 03 = Request_Status */
847     {  1,  Class_Status,   { T,  T,  F },  T,   T,   T,   T,   F,   F,   F,    0,  0,   0  }, /* 04 = Request_Sector_Address */
848     {  0,  Class_Read,     { T,  T,  F },  T,   T,   T,   T,   T,   T,   F,   15, 128,  7  }, /* 05 = Read */
849     {  0,  Class_Read,     { T,  T,  F },  T,   T,   T,   T,   T,   F,   F,   12, 138,  0  }, /* 06 = Read_Full_Sector */
850     {  1,  Class_Read,     { T,  T,  F },  T,   T,   T,   T,   T,   T,   F,    0,  0,   0  }, /* 07 = Verify */
851     {  0,  Class_Write,    { T,  T,  F },  T,   T,   T,   T,   T,   T,   F,   15, 128,  7  }, /* 10 = Write */
852     {  0,  Class_Write,    { T,  T,  F },  T,   T,   T,   T,   T,   F,   F,   12, 138,  0  }, /* 11 = Write_Full_Sector */
853     {  0,  Class_Control,  { T,  T,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 12 = Clear */
854     {  0,  Class_Write,    { T,  T,  F },  T,   T,   T,   T,   T,   F,   F,   15, 128,  7  }, /* 13 = Initialize */
855     {  2,  Class_Control,  { T,  T,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 14 = Address_Record */
856     {  7,  Class_Status,   { T,  F,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 15 = Request_Syndrome */
857     {  1,  Class_Read,     { T,  T,  F },  T,   T,   T,   T,   T,   T,   F,   15, 128,  7  }, /* 16 = Read_With_Offset */
858     {  0,  Class_Control,  { T,  T,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 17 = Set_File_Mask */
859     {  0,  Class_Invalid,  { F,  F,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 20 = Invalid_Opcode */
860     {  0,  Class_Invalid,  { F,  F,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 21 = Invalid_Opcode */
861     {  0,  Class_Read,     { T,  T,  F },  T,   T,   T,   T,   T,   T,   F,   15, 128,  7  }, /* 22 = Read_Without_Verify */
862     {  1,  Class_Status,   { T,  F,  F },  T,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 23 = Load_TIO_Register */
863     {  2,  Class_Status,   { T,  T,  F },  F,   F,   F,   F,   F,   F,   F,    0,  0,   0  }, /* 24 = Request_Disc_Address */
864     {  0,  Class_Control,  { T,  T,  F },  T,   F,   F,   F,   F,   F,   T,    0,  0,   0  }, /* 25 = End */
865     {  0,  Class_Control,  { T,  F,  F },  T,   T,   T,   F,   F,   F,   F,    0,  0,   0  }  /* 26 = Wakeup */
866     };
867 
868 
869 /* Command functions table.
870 
871    At each phase of command execution, the controller may return zero or more
872    functions for the interface to perform.  The functions control the transfer
873    of parameters and data to and from the CPU.  Note that commands do not
874    necessarily use all available phases.
875 
876 
877    Implementation notes:
878 
879     1. Commands usually return BUSY and IFGTC functions to begin.  However, the
880        Clear and Set File Mask commands delay the IFGTC function, which requests
881        channel service, to the End Phase to ensure that the WRTIO function
882        completes before the channel program continues.  This ensures that an End
883        I/O order will pick up the correct status value from the interface.
884 
885     2. Invalid commands have WRTIO in their Idle_Phase entries because the
886        diagnostic expects to see Illegal_Opcode status immediately after the SIO
887        program ends.
888 */
889 
890 typedef CNTLR_IFN IFN_ARRAY [7];
891 
892 static const IFN_ARRAY cmd_functions [] = {     /* indexed by CNTLR_OPCODE */
893                                                 /* 00 = Cold_Load_Read */
894     { BUSY | SRTRY | IFGTC,                     /*   Idle Phase */
895       0,                                        /*   Parameter Phase */
896       0,                                        /*   Seek Phase */
897       0,                                        /*   Rotate Phase */
898       IFIN,                                     /*   Data Phase */
899       0,                                        /*   Intersector Phase */
900       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
901 
902                                                 /* 01 = Recalibrate */
903     { BUSY | IFGTC,                             /*   Idle Phase */
904       0,                                        /*   Parameter Phase */
905       0,                                        /*   Seek Phase */
906       0,                                        /*   Rotate Phase */
907       0,                                        /*   Data Phase */
908       0,                                        /*   Intersector Phase */
909       WRTIO | FREE },                           /*   End Phase */
910 
911                                                 /* 02 = Seek */
912     { BUSY  | IFGTC | STDFL,                    /*   Idle Phase */
913       IFOUT | STDFL,                            /*   Parameter Phase */
914       0,                                        /*   Seek Phase */
915       0,                                        /*   Rotate Phase */
916       0,                                        /*   Data Phase */
917       0,                                        /*   Intersector Phase */
918       IFOUT | WRTIO | RQSRV | FREE },           /*   End Phase */
919 
920                                                 /* 03 = Request_Status */
921     { BUSY | IFGTC,                             /*   Idle Phase */
922       IFIN | STDFL,                             /*   Parameter Phase */
923       0,                                        /*   Seek Phase */
924       0,                                        /*   Rotate Phase */
925       0,                                        /*   Data Phase */
926       0,                                        /*   Intersector Phase */
927       WRTIO | FREE | RQSRV },                   /*   End Phase */
928 
929                                                 /* 04 = Request_Sector_Address */
930     { BUSY | IFGTC,                             /*   Idle Phase */
931       IFIN | STDFL,                             /*   Parameter Phase */
932       0,                                        /*   Seek Phase */
933       0,                                        /*   Rotate Phase */
934       0,                                        /*   Data Phase */
935       0,                                        /*   Intersector Phase */
936       WRTIO | RQSRV | FREE },                   /*   End Phase */
937 
938                                                 /* 05 = Read */
939     { BUSY | IFGTC,                             /*   Idle Phase */
940       0,                                        /*   Parameter Phase */
941       0,                                        /*   Seek Phase */
942       0,                                        /*   Rotate Phase */
943       IFIN,                                     /*   Data Phase */
944       0,                                        /*   Intersector Phase */
945       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
946 
947                                                 /* 06 = Read_Full_Sector */
948     { BUSY | IFGTC,                             /*   Idle Phase */
949       0,                                        /*   Parameter Phase */
950       0,                                        /*   Seek Phase */
951       0,                                        /*   Rotate Phase */
952       IFIN,                                     /*   Data Phase */
953       0,                                        /*   Intersector Phase */
954       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
955 
956                                                 /* 07 = Verify */
957     { BUSY | IFGTC | STDFL,                     /*   Idle Phase */
958       IFOUT,                                    /*   Parameter Phase */
959       0,                                        /*   Seek Phase */
960       0,                                        /*   Rotate Phase */
961       0,                                        /*   Data Phase */
962       0,                                        /*   Intersector Phase */
963       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
964 
965                                                 /* 10 = Write */
966     { BUSY | IFGTC,                             /*   Idle Phase */
967       0,                                        /*   Parameter Phase */
968       0,                                        /*   Seek Phase */
969       0,                                        /*   Rotate Phase */
970       IFOUT,                                    /*   Data Phase */
971       0,                                        /*   Intersector Phase */
972       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
973 
974                                                 /* 11 = Write_Full_Sector */
975     { BUSY | IFGTC,                             /*   Idle Phase */
976       0,                                        /*   Parameter Phase */
977       0,                                        /*   Seek Phase */
978       0,                                        /*   Rotate Phase */
979       IFOUT,                                    /*   Data Phase */
980       0,                                        /*   Intersector Phase */
981       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
982 
983                                                 /* 12 = Clear */
984     { BUSY,                                     /*   Idle Phase */
985       0,                                        /*   Parameter Phase */
986       0,                                        /*   Seek Phase */
987       0,                                        /*   Rotate Phase */
988       0,                                        /*   Data Phase */
989       0,                                        /*   Intersector Phase */
990       IFGTC | WRTIO | STDFL | FREE },           /*   End Phase */
991 
992                                                 /* 13 = Initialize */
993     { BUSY | IFGTC,                             /*   Idle Phase */
994       0,                                        /*   Parameter Phase */
995       0,                                        /*   Seek Phase */
996       0,                                        /*   Rotate Phase */
997       IFOUT,                                    /*   Data Phase */
998       0,                                        /*   Intersector Phase */
999       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
1000 
1001                                                 /* 14 = Address_Record */
1002     { BUSY  | IFGTC | STDFL,                    /*   Idle Phase */
1003       IFOUT | STDFL,                            /*   Parameter Phase */
1004       0,                                        /*   Seek Phase */
1005       0,                                        /*   Rotate Phase */
1006       0,                                        /*   Data Phase */
1007       0,                                        /*   Intersector Phase */
1008       IFOUT | WRTIO | RQSRV | FREE },           /*   End Phase */
1009 
1010                                                 /* 15 = Request_Syndrome */
1011     { BUSY | IFGTC,                             /*   Idle Phase */
1012       IFIN | STDFL,                             /*   Parameter Phase */
1013       0,                                        /*   Seek Phase */
1014       0,                                        /*   Rotate Phase */
1015       0,                                        /*   Data Phase */
1016       0,                                        /*   Intersector Phase */
1017       WRTIO | RQSRV | FREE },                   /*   End Phase */
1018 
1019                                                 /* 16 = Read_With_Offset */
1020     { BUSY  | IFGTC | STDFL,                    /*   Idle Phase */
1021       IFOUT,                                    /*   Parameter Phase */
1022       RQSRV | STDFL,                            /*   Seek Phase */
1023       0,                                        /*   Rotate Phase */
1024       IFIN,                                     /*   Data Phase */
1025       0,                                        /*   Intersector Phase */
1026       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
1027 
1028                                                 /* 17 = Set_File_Mask */
1029     { BUSY | SRTRY,                             /*   Idle Phase */
1030       0,                                        /*   Parameter Phase */
1031       0,                                        /*   Seek Phase */
1032       0,                                        /*   Rotate Phase */
1033       0,                                        /*   Data Phase */
1034       0,                                        /*   Intersector Phase */
1035       IFGTC | WRTIO | STDFL | FREE },           /*   End Phase */
1036 
1037                                                 /* 20 = Invalid_Opcode */
1038     { BUSY | IFGTC | WRTIO,                     /*   Idle Phase */
1039       0,                                        /*   Parameter Phase */
1040       0,                                        /*   Seek Phase */
1041       0,                                        /*   Rotate Phase */
1042       0,                                        /*   Data Phase */
1043       0,                                        /*   Intersector Phase */
1044       FREE },                                   /*   End Phase */
1045 
1046                                                 /* 21 = Invalid_Opcode */
1047     { BUSY | IFGTC | WRTIO,                     /*   Idle Phase */
1048       0,                                        /*   Parameter Phase */
1049       0,                                        /*   Seek Phase */
1050       0,                                        /*   Rotate Phase */
1051       0,                                        /*   Data Phase */
1052       0,                                        /*   Intersector Phase */
1053       FREE },                                   /*   End Phase */
1054 
1055                                                 /* 22 = Read_Without_Verify */
1056     { BUSY | IFGTC,                             /*   Idle Phase */
1057       0,                                        /*   Parameter Phase */
1058       0,                                        /*   Seek Phase */
1059       0,                                        /*   Rotate Phase */
1060       IFIN,                                     /*   Data Phase */
1061       0,                                        /*   Intersector Phase */
1062       STDFL | WRTIO | RQSRV | FREE },           /*   End Phase */
1063 
1064                                                 /* 23 = Load_TIO_Register */
1065     { BUSY  | IFGTC | STDFL,                    /*   Idle Phase */
1066       0,                                        /*   Parameter Phase */
1067       0,                                        /*   Seek Phase */
1068       0,                                        /*   Rotate Phase */
1069       0,                                        /*   Data Phase */
1070       0,                                        /*   Intersector Phase */
1071       IFOUT | WRTIO | RQSRV | FREE },           /*   End Phase */
1072 
1073                                                 /* 24 = Request_Disc_Address */
1074     { BUSY | IFGTC,                             /*   Idle Phase */
1075       IFIN | STDFL,                             /*   Parameter Phase */
1076       0,                                        /*   Seek Phase */
1077       0,                                        /*   Rotate Phase */
1078       0,                                        /*   Data Phase */
1079       0,                                        /*   Intersector Phase */
1080       WRTIO | RQSRV | FREE },                   /*   End Phase */
1081 
1082                                                 /* 25 = End */
1083     { IFGTC,                                    /*   Idle Phase */
1084       0,                                        /*   Parameter Phase */
1085       0,                                        /*   Seek Phase */
1086       0,                                        /*   Rotate Phase */
1087       0,                                        /*   Data Phase */
1088       0,                                        /*   Intersector Phase */
1089       0 },                                      /*   End Phase */
1090 
1091                                                 /* 26 = Wakeup */
1092     { BUSY | IFGTC,                             /*   Idle Phase */
1093       0,                                        /*   Parameter Phase */
1094       0,                                        /*   Seek Phase */
1095       0,                                        /*   Rotate Phase */
1096       0,                                        /*   Data Phase */
1097       0,                                        /*   Intersector Phase */
1098       WRTIO | STDFL | FREE }                    /*   End Phase */
1099     };
1100 
1101 
1102 /* Status functions table.
1103 
1104    The End Phase functions above are proper for commands that complete normally.
1105    Commands that return an error status return additional functions that depend
1106    on the particular status code.  An entry in this table is ORed with the End
1107    Phase function to produce the final function set that is returned to the
1108    interface.
1109 */
1110 
1111 static const CNTLR_IFN status_functions [] = {  /* indexed by CNTLR_STATUS */
1112     0,                                          /*   000 = Normal Completion */
1113     STINT | WRTIO | FREE,                       /*   001 = Illegal Opcode */
1114     STDFL | WRTIO | FREE,                       /*   002 = Unit Available */
1115     STINT | WRTIO | FREE,                       /*   003 = Illegal Drive Type */
1116     0,                                          /*   004 = (undefined) */
1117     0,                                          /*   005 = (undefined) */
1118     0,                                          /*   006 = (undefined) */
1119     STINT | WRTIO | FREE,                       /*   007 = Cylinder Miscompare */
1120     DVEND | RQSRV | WRTIO | FREE,               /*   010 = Uncorrectable Data Error */
1121     STINT | WRTIO | FREE,                       /*   011 = Head-Sector Miscompare */
1122     STINT | WRTIO | FREE,                       /*   012 = I/O Program Error */
1123     DVEND | RQSRV | WRTIO | FREE,               /*   013 = Sync Timeout */
1124     STINT | WRTIO | FREE,                       /*   014 = End of Cylinder */
1125     0,                                          /*   015 = (undefined) */
1126     DVEND | RQSRV | WRTIO | FREE,               /*   016 = Data Overrun */
1127     DVEND | RQSRV | WRTIO | FREE,               /*   017 = Correctable Data Error */
1128     STINT | WRTIO | FREE,                       /*   020 = Illegal Spare Access */
1129     STINT | WRTIO | FREE,                       /*   021 = Defective Track */
1130     STINT | WRTIO | FREE,                       /*   022 = Access Not Ready */
1131     STINT | WRTIO | FREE,                       /*   023 = Status-2 Error */
1132     0,                                          /*   024 = (undefined) */
1133     0,                                          /*   025 = (undefined) */
1134     STINT | WRTIO | FREE,                       /*   026 = Protected Track */
1135     STINT | WRTIO | FREE,                       /*   027 = Unit Unavailable */
1136     0,                                          /*   030 = (undefined) */
1137     0,                                          /*   031 = (undefined) */
1138     0,                                          /*   032 = (undefined) */
1139     0,                                          /*   033 = (undefined) */
1140     0,                                          /*   034 = (undefined) */
1141     0,                                          /*   035 = (undefined) */
1142     0,                                          /*   036 = (undefined) */
1143     STINT | WRTIO | FREE                        /*   037 = Drive Attention */
1144     };
1145 
1146 
1147 /* Controller operation names */
1148 
1149 static const BITSET_NAME flag_names [] = {      /* controller flag names, in CNTLR_FLAG order */
1150     "CLEAR",                                    /* 000001 */
1151     "CMRDY",                                    /* 000002 */
1152     "DTRDY",                                    /* 000004 */
1153     "EOD",                                      /* 000010 */
1154     "INTOK",                                    /* 000020 */
1155     "OVRUN",                                    /* 000040 */
1156     "XFRNG"                                     /* 000100 */
1157     };
1158 
1159 static const BITSET_FORMAT flag_format =        /* names, offset, direction, alternates, bar */
1160     { FMT_INIT (flag_names, 0, lsb_first, no_alt, no_bar) };
1161 
1162 
1163 static const BITSET_NAME function_names [] = {  /* interface function names, in CNTLR_IFN order */
1164     "BUSY",                                     /* 000000200000 */
1165     "DSCIF",                                    /* 000000400000 */
1166     "SELIF",                                    /* 000001000000 */
1167     "IFIN",                                     /* 000002000000 */
1168     "IFOUT",                                    /* 000004000000 */
1169     "IFGTC",                                    /* 000010000000 */
1170     "IFPRF",                                    /* 000020000000 */
1171     "RQSRV",                                    /* 000040000000 */
1172     "DVEND",                                    /* 000100000000 */
1173     "SRTRY",                                    /* 000200000000 */
1174     "STDFL",                                    /* 000400000000 */
1175     "STINT",                                    /* 001000000000 */
1176     "WRTIO",                                    /* 002000000000 */
1177     "FREE"                                      /* 004000000000 */
1178     };
1179 
1180 static const BITSET_FORMAT function_format =    /* names, offset, direction, alternates, bar */
1181     { FMT_INIT (function_names, 16, lsb_first, no_alt, no_bar) };
1182 
1183 
1184 static const char invalid_name [] = "Invalid";
1185 
1186 static const char *opcode_name [] = {           /* command opcode names, in CNTLR_OPCODE order */
1187     "Cold Load Read",                           /*   00 */
1188     "Recalibrate",                              /*   01 */
1189     "Seek",                                     /*   02 */
1190     "Request Status",                           /*   03 */
1191     "Request Sector Address",                   /*   04 */
1192     "Read",                                     /*   05 */
1193     "Read Full Sector",                         /*   06 */
1194     "Verify",                                   /*   07 */
1195     "Write",                                    /*   10 */
1196     "Write Full Sector",                        /*   11 */
1197     "Clear",                                    /*   12 */
1198     "Initialize",                               /*   13 */
1199     "Address Record",                           /*   14 */
1200     "Request Syndrome",                         /*   15 */
1201     "Read With Offset",                         /*   16 */
1202     "Set File Mask",                            /*   17 */
1203     invalid_name,                               /*   20 = invalid */
1204     invalid_name,                               /*   21 = invalid */
1205     "Read Without Verify",                      /*   22 */
1206     "Load TIO Register",                        /*   23 */
1207     "Request Disc Address",                     /*   24 */
1208     "End",                                      /*   25 */
1209     "Wakeup"                                    /*   26 */
1210     };
1211 
1212 #define OPCODE_LENGTH       22                  /* length of the longest opcode name */
1213 
1214 
1215 static const char *const status_name [] = {     /* command status names, in CNTLR_STATUS order */
1216     "Normal Completion",                        /*   000 */
1217     "Illegal Opcode",                           /*   001 */
1218     "Unit Available",                           /*   002 */
1219     "Illegal Drive Type",                       /*   003 */
1220     NULL,                                       /*   004 */
1221     NULL,                                       /*   005 */
1222     NULL,                                       /*   006 */
1223     "Cylinder Miscompare",                      /*   007 */
1224     "Uncorrectable Data Error",                 /*   010 */
1225     "Head-Sector Miscompare",                   /*   011 */
1226     "I/O Program Error",                        /*   012 */
1227     "Sync Timeout",                             /*   013 */
1228     "End of Cylinder",                          /*   014 */
1229     NULL,                                       /*   015 */
1230     "Data Overrun",                             /*   016 */
1231     "Correctable Data Error",                   /*   017 */
1232     "Illegal Spare Access",                     /*   020 */
1233     "Defective Track",                          /*   021 */
1234     "Access Not Ready",                         /*   022 */
1235     "Status-2 Error",                           /*   023 */
1236     NULL,                                       /*   024 */
1237     NULL,                                       /*   025 */
1238     "Protected Track",                          /*   026 */
1239     "Unit Unavailable",                         /*   027 */
1240     NULL,                                       /*   030 */
1241     NULL,                                       /*   031 */
1242     NULL,                                       /*   032 */
1243     NULL,                                       /*   033 */
1244     NULL,                                       /*   034 */
1245     NULL,                                       /*   035 */
1246     NULL,                                       /*   036 */
1247     "Drive Attention"                           /*   037 */
1248     };
1249 
1250 #define STATUS_LENGTH       24                  /* length of the longest status name */
1251 
1252 
1253 static const char *state_name [] = {            /* controller state names, in CNTLR_STATE order */
1254     "idle",
1255     "wait",
1256     "busy"
1257     };
1258 
1259 
1260 static const char *phase_name [] = {            /* unit state names, in CNTLR_PHASE order */
1261     "idle",
1262     "parameter",
1263     "seek",
1264     "rotate",
1265     "data",
1266     "intersector",
1267     "end"
1268     };
1269 
1270 
1271 /* Disc library local controller routines */
1272 
1273 static CNTLR_IFN_IBUS start_command    (CVPTR cvptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data);
1274 static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data);
1275 static CNTLR_IFN_IBUS poll_drives      (CVPTR cvptr);
1276 
1277 static void   end_command      (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1278 static t_bool start_seek       (CVPTR cvptr, UNIT *uptr);
1279 static t_bool start_read       (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1280 static void   end_read         (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1281 static t_bool start_write      (CVPTR cvptr, UNIT *uptr);
1282 static void   end_write        (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
1283 static t_bool position_sector  (CVPTR cvptr, UNIT *uptr);
1284 static void   next_sector      (CVPTR cvptr, UNIT *uptr);
1285 static void   io_error         (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1286 static void   set_completion   (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
1287 static void   clear_controller (CVPTR cvptr, CNTLR_CLEAR clear_type);
1288 static void   idle_controller  (CVPTR cvptr);
1289 
1290 /* Disc library local utility routines */
1291 
1292 static void    set_address   (CVPTR cvptr, uint32    index);
1293 static void    wait_timer    (CVPTR cvptr, FLIP_FLOP action);
1294 static HP_WORD drive_status  (UNIT  *uptr);
1295 static t_stat  activate_unit (CVPTR cvptr, UNIT *uptr);
1296 static void    set_rotation  (CVPTR cvptr, UNIT *uptr);
1297 static void    set_file_pos  (CVPTR cvptr, UNIT *uptr, uint32 model);
1298 
1299 
1300 
1301 /* Disc library global controller routines */
1302 
1303 
1304 /* Disc controller interface.
1305 
1306    This routine simulates the hardware interconnection between the disc
1307    controller and the CPU interface.  This routine is called whenever the flag
1308    state changes.  This would be when a new command is to be started, when
1309    command parameters are supplied or status words are retrieved, and when
1310    sector data is read or written.  It must also be called when the unit service
1311    routine is entered.  The caller passes in the set of interface flags and the
1312    contents of the data buffer.  The routine returns a set of functions and, if
1313    IFIN is included in set, the new content of the data buffer.
1314 
1315    In hardware, the controller microcode executes in one of three states:
1316 
1317     1. In the Poll Loop, which looks for commands and drive attention requests.
1318 
1319        In each pass of the loop, the next CPU interface in turn is selected and
1320        checked for a command; if present, it is executed.  If not, the
1321        interface is disconnected, and then all drives are checked in turn until
1322        one is found with Attention status; if none are found, the loop
1323        continues.  If a drive is requesting attention, the associated CPU
1324        interface is selected to check for a command; if present, it is executed.
1325        If not, and the interface allows interrupts, an interrupt request is made
1326        and the Command Wait Loop is entered.  If interrupts are not allowed, the
1327        interface is disconnected, and the Poll Loop continues.
1328 
1329     2. In the Command Wait Loop, which looks for commands.
1330 
1331        In each pass of the loop, the currently selected CPU interface is checked
1332        for a command; if present, it is executed.  If not, the Command Wait Loop
1333        continues.  While in the loop, a 1.74 second timer is running.  If it
1334        expires before a command is received, the file mask is reset, the current
1335        interface is disconnected, and the Poll Loop is entered.
1336 
1337     3. In command execution, which processes the current command.
1338 
1339        While a command is executing, any waits for input parameters, seek
1340        completion, data transfers, or output status words are handled
1341        internally.  Each wait is governed by the 1.74 second timer; if it
1342        expires, the command is aborted, the file mask is reset, the current
1343        interface is disconnected, and the Poll Loop is reentered.
1344 
1345    In simulation, these states are represented by the CNTLR_STATE values
1346    Idle_State, Wait_State, and Busy_State, respectively.
1347 
1348    A MAC controller operates from one to eight drives, represented by an array
1349    of one to eight UNITs.  The unit number present in the command is used to
1350    index to the target unit via the "units" pointer in the DEVICE structure.
1351    One additional unit that represents the controller is required, separate from
1352    the individual drive units.  Commands that do not access the drive, such as
1353    Address Record, are scheduled on the controller unit to allow controller
1354    commands to execute while drive units are seeking.  The command wait timer is
1355    also scheduled on the controller unit to limit the amount of time the
1356    controller will wait for the interface to supply a command or parameter.
1357 
1358    An ICD simulation manages a single unit corresponding to the drive in which
1359    the controller is integrated.  A device interface declares a UNIT array
1360    corresponding to the number of drives supported and passes the unit number to
1361    use during controller initialization.  A controller unit is not used, as all
1362    commands are scheduled on the drive unit associated with a given controller.
1363 
1364    On entry, the flags and controller state are examined to determine if a new
1365    controller command should be initiated or the current command should be
1366    continued.  If this routine is being called as a result of an event service,
1367    "uptr" will point at the unit being serviced.  Otherwise, "uptr" will be NULL
1368    (for example, when starting a new controller command).
1369 
1370    If the CLEARF flag is asserted, then perform a hard clear on the controller.
1371    Otherwise, if a 3000 channel error has occurred, then terminate any command
1372    in progress and return I/O Program Error status.  Otherwise, if the
1373    controller is currently busy with a command, or if this is an event service
1374    entry, then process the next step of the command.  Otherwise, if the CMRDY
1375    flag is asserted, then start a new command.  If none of these cases pertain,
1376    or if the controller is now idle, poll the drives for attention.
1377 
1378    In all cases, return a combined function set and outbound data word to the
1379    caller.
1380 
1381 
1382    Implementation notes:
1383 
1384     1. This routine will be entered when the drive unit event service occurs
1385        for seek completion, and Seek_Phase processing in continue_command will
1386        set the drive's Attention bit.  The drives must then be polled and the
1387        return functions and TIO value set to generate a CPU interrupt.
1388 
1389        A seek command started on one drive while a second drive already has its
1390        Attention bit set would seem to overwrite the first drive's Seek
1391        completion status with the second drive's Attention status.  However,
1392        this won't occur because INTOK will not be set until the first drive's
1393        channel program completes, and so the drive poll is inhibited until then.
1394 */
1395 
dl_controller(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags,CNTLR_IBUS data)1396 CNTLR_IFN_IBUS dl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data)
1397 {
1398 CNTLR_IFN_IBUS outbound;
1399 
1400 tpprintf (cvptr->device, DL_DEB_IOB, "Controller (%s) received data %06o with flags %s\n",
1401           state_name [cvptr->state], data, fmt_bitset (flags, flag_format));
1402 
1403 if (flags & CLEARF) {                                   /* if the CLEAR flag is asserted */
1404     clear_controller (cvptr, Hard_Clear);               /*   then perform a hard clear on the controller */
1405     outbound = NO_ACTION;                               /*     and take no other action on return */
1406 
1407     tpprintf (cvptr->device, DL_DEB_CMD, "Hard clear\n");
1408     }
1409 
1410 else if (flags & XFRNG) {                               /* otherwise if a channel error has occurred */
1411     end_command (cvptr, uptr, IO_Program_Error);        /*   then terminate the command with error status */
1412     cvptr->spd_unit = 0;                                /*     and clear the SPD and unit parts of the status */
1413 
1414     outbound = status_functions [IO_Program_Error]      /* set the Status-1 value for WRTIO */
1415                  | S1_STATUS (IO_Program_Error);
1416     }
1417 
1418 else if (uptr || cvptr->state == Busy_State)                /* otherwise if a command is in process */
1419     outbound = continue_command (cvptr, uptr, flags, data); /*   then continue with command processing */
1420 
1421 else if (flags & CMRDY)                                 /* otherwise if a new command is ready */
1422     outbound = start_command (cvptr, flags, data);      /*   then begin command execution */
1423 
1424 else                                                    /* otherwise there's nothing to do */
1425     outbound = NO_ACTION;                               /*   except possibly poll for attention */
1426 
1427 if (cvptr->state == Idle_State                          /* if the controller is idle */
1428   && cvptr->type == MAC                                 /*   and it's a MAC controller */
1429   && flags & INTOK)                                     /*     and interrupts are allowed */
1430     outbound = poll_drives (cvptr);                     /*       then poll the drives for attention */
1431 
1432 tpprintf (cvptr->device, DL_DEB_IOB, "Controller (%s) returned data %06o with functions %s\n",
1433           state_name [cvptr->state], DLIBUS (outbound),
1434           fmt_bitset (DLIFN (outbound), function_format));
1435 
1436 return outbound;
1437 }
1438 
1439 
1440 /* Start a new command.
1441 
1442    This routine simulates the controller microcode entry into the command
1443    executor corresponding to the command presented by the CPU interface.  It's
1444    called when the controller is waiting for a command and the interface asserts
1445    CMRDY to indicate that a new command is available.  It returns a set of
1446    action functions and a data word to the caller.  For a good command, it also
1447    sets up the next phase of operation on the controller and/or drive unit and
1448    schedules the unit(s) as appropriate.
1449 
1450    On entry, the command word is supplied in the "inbound_data" parameter; this
1451    simulates the microcode issuing an IFPRF (Interface Prefetch) to obtain the
1452    command.  The opcode is isolated from the command word and checked for
1453    validity.  If it's OK, it's used as an index into the command properties
1454    table.  If the command contains a unit number field, it is extracted, checked
1455    for validity, and used to derive a pointer to the corresponding UNIT
1456    structure.  If the command does not access the drive, or if the unit number
1457    is invalid, the unit pointer is set to NULL.  A pointer to the controller
1458    unit is also set up; for ICD controllers, the controller and drive unit are
1459    the same.
1460 
1461    The controller library supports up to eight drives per MAC controller and one
1462    drive per ICD controller.  Unit numbers 0-7 represent valid drive addresses
1463    for a MAC controller.  The unit number field is ignored for an ICD
1464    controller, and unit 0 is always implied.  In simulation, MAC unit numbers
1465    correspond one-for-one with device units, whereas one ICD controller is
1466    associated with each of the several device units that are independently
1467    addressed as unit 0.
1468 
1469    The MAC controller firmware allows access to unit numbers 8-10 without
1470    causing a Unit Unavailable error.  Instead, the controller reports these
1471    legal-but-invalid units as permanently offline.
1472 
1473    If a diagnostic override is defined, and the cylinder, head, sector, and
1474    opcode values from the current override entry match their corresponding
1475    controller values, then the status and SPD values are set from the entry
1476    rather than being cleared, and the pointer is moved to the next entry.  The
1477    controller is then set to the busy state, and the validity of the opcode and
1478    unit are checked.  If any errors are detected, the appropriate status is set,
1479    and the controller unit is scheduled for the End_Phase to simulate the
1480    controller processing overhead.
1481 
1482    If the command and unit are valid, then if the command accesses a drive unit,
1483    the unit's OPCODE field is set, and any pending Attention status is cleared.
1484    If the command takes or returns parameters, then the Parameter_Phase is set
1485    up on the controller unit and the wait timer is started.  Commands that
1486    return parameters temporarily store their parameter values in the sector
1487    buffer at this time for return as the CPU interface requests them.  The Cold
1488    Load Read and Recalibrate commands start their respective seeks at this time,
1489    and commands that complete immediately, e.g., Set File Mask, Wakeup, etc.,
1490    schedule the End_Phase on the controller unit and set up the status value for
1491    return if they end with the WRTIO function.
1492 
1493    Finally, the controller and/or drive units are activated if they were
1494    scheduled.  If a seek is in progress on a drive when a command that
1495    waits for seek completion is started, the unit is not rescheduled.  Instead,
1496    the unit is left in the Seek_Phase, but the unit's OPCODE field is changed to
1497    reflect the new command so that the command will start automatically when the
1498    seek completes.
1499 
1500 
1501    Implementation notes:
1502 
1503     1. A command is started only if the controller is not busy.  Therefore, the
1504        target unit can be only in either the Seek_Phase or the Idle_Phase, as
1505        all other phases will have the controller in the Busy_State.
1506 
1507     2. Commands that access units and take parameters (e.g., Verify) set up the
1508        parameter access on the controller unit but perform the rest of the
1509        operation on the drive unit.  The controller must be used so that
1510        parameters may be read for the next command for a unit that is currently
1511        seeking (stacked commands wait for seek completion after parameters have
1512        been read).
1513 
1514     3. Drive Attention may be still set on a drive that has completed a seek but
1515        has not been able to interrupt the CPU before a new command is started.
1516        Therefore, Attention is always cleared when a command starts.
1517 
1518     4. In hardware, the Recalibrate command waits for a seek-in-progress to
1519        complete before the RCL tag is sent to the drive.  In simulation,
1520        repositioning the heads to cylinder 0 is started immediately, but any
1521        remaining time from a seek-in-progress is added to the time required for
1522        repositioning.  The effect is that recalibration completes in the time it
1523        would have taken for the seek-in-progress to complete followed by
1524        repositioning from that location.
1525 
1526     5. The Cold Load Read command does not check for Access Not Ready before
1527        issuing the seek to cylinder 0, so if a seek or recalibrate is in
1528        progress, the drive will reject it with a Seek Check error.  However, the
1529        command continues, and when the seek in progress completes and the read
1530        begins, the Seek Check error will abort the command at this point with a
1531        Status-2 Error.
1532 
1533     6. ECC is not simulated, so the Request Syndrome command always returns zero
1534        values for the displacement and patterns and Uncorrectable Data Error for
1535        the status.  Correctable Data Error status cannot occur unless a
1536        diagnostic override is in effect.
1537 
1538     7. The Wakeup command references a drive unit but is scheduled on the
1539        controller unit because it may be issued while the drive is seeking.
1540 */
1541 
start_command(CVPTR cvptr,CNTLR_FLAG_SET inbound_flags,CNTLR_IBUS inbound_data)1542 static CNTLR_IFN_IBUS start_command (CVPTR cvptr, CNTLR_FLAG_SET inbound_flags, CNTLR_IBUS inbound_data)
1543 {
1544 UNIT *cuptr, *duptr, *rptr;
1545 uint32 unit;
1546 int32 seek_wait_time;
1547 PRPTR props;
1548 CNTLR_IFN_IBUS outbound;
1549 DIAG_ENTRY *dop = NULL;
1550 
1551 wait_timer (cvptr, CLEAR);                              /* stop the command wait timer */
1552 
1553 cvptr->opcode = CM_OPCODE (inbound_data);               /* get the opcode from the command */
1554 
1555 if (cvptr->opcode > LAST_OPCODE                                 /* if the opcode is undefined */
1556   || cvptr->type > LAST_CNTLR                                   /*   or the controller type is undefined */
1557   || cmd_props [cvptr->opcode].valid [cvptr->type] == FALSE)    /*     or the opcode is not valid for this controller */
1558     cvptr->opcode = Invalid_Opcode;                             /*       then replace it with the invalid opcode */
1559 
1560 props = &cmd_props [cvptr->opcode];                     /* get the properties associated with the opcode */
1561 
1562 if (cvptr->type == MAC) {                               /* if this a MAC controller */
1563     if (props->unit_field)                              /*   then if the unit field is defined */
1564         unit = CM_UNIT (inbound_data);                  /*     then get it from the command */
1565     else                                                /*   otherwise the unit is not specified in the command */
1566         unit = 0;                                       /*     so the unit is always unit 0 */
1567 
1568     cuptr = CNTLR_UPTR;                                 /* set the controller unit pointer */
1569 
1570     if (unit > DL_MAXDRIVE                              /* if the unit number is invalid */
1571       || props->unit_access == FALSE)                   /*   or the command accesses the controller only */
1572         duptr = NULL;                                   /*     then the drive pointer does not correspond to a unit */
1573     else                                                /* otherwise the command accesses a valid drive unit */
1574         duptr = cvptr->device->units + unit;            /*   so set the drive pointer to the unit */
1575     }
1576 
1577 else {                                                  /* otherwise this is an ICD or CS/80 controller */
1578     unit = 0;                                           /*   so the unit value isn't used */
1579     cuptr = duptr =                                     /*     and the unit number was predefined */
1580       cvptr->device->units + cvptr->poll_unit;          /*       when the controller structure was initialized */
1581     }
1582 
1583 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command started\n",
1584           unit, opcode_name [cvptr->opcode]);
1585 
1586 if (cvptr->dop_index >= 0)                              /* if the diagnostic override table is defined */
1587     dop = cvptr->dop_base + cvptr->dop_index;           /*   then point at the current entry */
1588 
1589 if (dop                                                 /* if the table entry exists */
1590   && dop->cylinder == cvptr->cylinder                   /*   and the cylinder, */
1591   && dop->head     == cvptr->head                       /*     head, */
1592   && dop->sector   == cvptr->sector                     /*       sector, */
1593   && dop->opcode   == cvptr->opcode)  {                 /*         and opcode values match the current values */
1594     cvptr->spd_unit = dop->spd | unit;                  /*           then override the Spare/Protected/Defective */
1595     cvptr->status   = dop->status;                      /*             and status values from the override entry */
1596 
1597     cvptr->dop_index++;                                 /* point at the  */
1598     dop++;                                              /*   next table entry */
1599 
1600     tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u cylinder %u head %u sector %u diagnostic override\n",
1601               unit, cvptr->cylinder, cvptr->head, cvptr->sector);
1602     }
1603 
1604 else if (props->clear_status) {                         /* otherwise if this command clears prior status */
1605     cvptr->status = Normal_Completion;                  /*   then do it */
1606     cvptr->spd_unit = unit;                             /*     and save the unit number for status requests */
1607     }
1608 
1609 
1610 cvptr->state = Busy_State;                              /* the controller is now busy */
1611 cvptr->index = 0;                                       /* reset the buffer index */
1612 cvptr->count = 0;                                       /*   and the sector/word count */
1613 cvptr->verify = props->verify_address;                  /* set the address verification flag */
1614 
1615 cuptr->OPCODE = cvptr->opcode;                          /* set the controller unit opcode */
1616 cuptr->wait = NO_EVENT;                                 /*   and assume no controller scheduling */
1617 
1618 outbound = cmd_functions [cvptr->opcode] [Idle_Phase];  /* set up the initial function set and zero data */
1619 
1620 
1621 if (cvptr->opcode == Invalid_Opcode)                        /* if the opcode is invalid */
1622     set_completion (cvptr, cuptr, Illegal_Opcode);          /*   then finish with an illegal opcode error */
1623 
1624 else if (props->unit_check && unit > MAX_UNIT)              /* otherwise if the unit number is checked and is illegal */
1625     set_completion (cvptr, cuptr, Unit_Unavailable);        /*   then finish with a unit unavailable error */
1626 
1627 else if (props->unit_check && unit > DL_MAXDRIVE            /* otherwise if the unit number is checked and is invalid */
1628   || props->seek_wait && (drive_status (duptr) & S2_STOPS)) /*   or if we're waiting for an offline drive */
1629     set_completion (cvptr, cuptr, Status_2_Error);          /*     then finish with a Status-2 error */
1630 
1631 else {                                                  /* otherwise the command and unit are valid */
1632     if (duptr) {                                        /* if the drive unit is accessed  */
1633         duptr->OPCODE = cvptr->opcode;                  /*   then set the drive opcode for later reference */
1634         duptr->wait = NO_EVENT;                         /* assume no drive scheduling */
1635         duptr->STATUS &= ~S2_ATTENTION;                 /* clear any pending Attention status */
1636         }
1637 
1638     if (props->param_count != 0) {                      /* if the command takes or returns parameters */
1639         cvptr->length = props->param_count;             /*   then set the parameter count */
1640         cuptr->PHASE = Parameter_Phase;                 /* set up the parameter transfer on the controller */
1641         wait_timer (cvptr, SET);                        /*   and start the timer to wait for the first parameter */
1642         }
1643 
1644     switch (cvptr->opcode) {                            /* dispatch the command for initiation */
1645 
1646         case Cold_Load_Read:
1647             cvptr->cylinder = 0;                                /* set the cylinder address to 0 */
1648             cvptr->head = CM_HEAD (inbound_data);               /* set the head and */
1649             cvptr->sector = CM_SECTOR (inbound_data);           /*   sector addresses from the command */
1650 
1651             if (start_seek (cvptr, duptr) == FALSE)             /* start the seek; if it failed */
1652                 set_completion (cvptr, cuptr, Status_2_Error);  /*   then set up the completion status */
1653 
1654             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s from cylinder %u head %u sector %u\n",
1655                       unit, opcode_name [Cold_Load_Read], cvptr->cylinder, cvptr->head, cvptr->sector);
1656             break;                                              /* wait for seek completion */
1657 
1658 
1659         case Recalibrate:
1660             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder 0\n",
1661                       unit, opcode_name [Recalibrate]);
1662 
1663             if (duptr->PHASE == Seek_Phase) {                   /* if the unit is currently seeking */
1664                 seek_wait_time = sim_activate_time (duptr);     /*   then get the remaining event time */
1665 
1666                 sim_cancel (duptr);                             /* cancel the event to allow rescheduling */
1667                 duptr->PHASE = Idle_Phase;                      /*   and idle the drive so that the seek succeeds */
1668 
1669                 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
1670                           unit, opcode_name [Recalibrate]);
1671                 }
1672 
1673             else                                                /* otherwise the drive is idle */
1674                 seek_wait_time = 0;                             /*   so there's no seek wait time */
1675 
1676             if (start_seek (cvptr, duptr) == FALSE)                 /* start the seek; if it failed */
1677                 set_completion (cvptr, cuptr, Status_2_Error);      /*   then set up the completion status */
1678 
1679             else if (cvptr->type == MAC)                            /* otherwise if this a MAC controller */
1680                 set_completion (cvptr, cuptr, Normal_Completion);   /*   then schedule seek completion */
1681 
1682             duptr->wait = duptr->wait + seek_wait_time;             /* increase the delay by any remaining seek time */
1683             break;                                                  /*   and wait for the recalibrate to complete */
1684 
1685 
1686         case Request_Status:
1687             cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit    /* set the Status-1 value */
1688                                   | S1_STATUS (cvptr->status)); /*   into the buffer */
1689 
1690             if (cvptr->type == MAC)                     /* if this a MAC controller */
1691                 if (unit > DL_MAXDRIVE)                 /*   then if the unit number is invalid */
1692                     rptr = NULL;                        /*     then it does not correspond to a unit */
1693                 else                                    /*   otherwise the unit is valid */
1694                     rptr = cvptr->device->units + unit; /*     so get the address of the referenced unit */
1695             else                                        /* otherwise it is not a MAC controller */
1696                 rptr = duptr;                           /*   so the referenced unit is the current unit */
1697 
1698             cvptr->buffer [1] = (DL_BUFFER) drive_status (rptr);    /* set the Status-2 value into the buffer */
1699 
1700             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns %sunit %u | %s and %s%s | %s\n",
1701                       unit, opcode_name [Request_Status],
1702                       fmt_bitset (cvptr->spd_unit, status_1_format),
1703                       CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
1704                       (cvptr->buffer [1] & S2_ERROR ? "error | " : ""),
1705                       drive_props [S2_TO_DRIVE_TYPE (cvptr->buffer [1])].name,
1706                       fmt_bitset (cvptr->buffer [1], status_2_format));
1707 
1708             if (rptr)                                   /* if the referenced unit is valid */
1709                 rptr->STATUS &= ~S2_FIRST_STATUS;       /*   then clear the First Status bit */
1710 
1711             cvptr->spd_unit = S1_UNIT (unit);           /* save the unit number referenced in the command */
1712 
1713             if (unit > MAX_UNIT)                        /* if the unit number is illegal */
1714                 cvptr->status = Unit_Unavailable;       /*   then the next status will be Unit Unavailable */
1715             else                                        /* otherwise a legal unit */
1716                 cvptr->status = Normal_Completion;      /*   clears the controller status */
1717             break;
1718 
1719 
1720         case Request_Sector_Address:
1721             if (drive_status (duptr) & S2_NOT_READY)            /* if the drive is not ready */
1722                 set_completion (cvptr, cuptr, Status_2_Error);  /*   then finish with Not Ready status */
1723 
1724             else                                                /* otherwise the drive is ready */
1725                 cvptr->buffer [0] =                             /*   so calculate the current sector address */
1726                   (DL_BUFFER) CURRENT_SECTOR (cvptr, duptr);
1727 
1728             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns sector %u\n",
1729                       unit, opcode_name [Request_Sector_Address], cvptr->buffer [0]);
1730             break;
1731 
1732 
1733         case Clear:
1734             clear_controller (cvptr, Soft_Clear);               /* clear the controller */
1735             set_completion (cvptr, cuptr, Normal_Completion);   /*   and schedule the command completion */
1736 
1737             tpprintf (cvptr->device, DL_DEB_CMD, "%s\n", opcode_name [Clear]);
1738             break;
1739 
1740 
1741         case Request_Syndrome:
1742             if (cvptr->status == Correctable_Data_Error) {      /* if this is a correction override */
1743                 cvptr->buffer [3] = (DL_BUFFER) dop->spd;       /*   then load the displacement */
1744                 cvptr->buffer [4] = (DL_BUFFER) dop->cylinder;  /*     and three */
1745                 cvptr->buffer [5] = (DL_BUFFER) dop->head;      /*       syndrome words */
1746                 cvptr->buffer [6] = (DL_BUFFER) dop->sector;    /*         from the override entry */
1747 
1748                 cvptr->dop_index++;                             /* point at the  */
1749                 dop++;                                          /*   next table entry */
1750                 }
1751 
1752             else {                                          /* otherwise no correction data was supplied */
1753                 cvptr->buffer [3] = 0;                      /*   so the displacement is always zero */
1754                 cvptr->buffer [4] = 0;                      /*     as are */
1755                 cvptr->buffer [5] = 0;                      /*       the three */
1756                 cvptr->buffer [6] = 0;                      /*         syndrome words */
1757 
1758                 if (cvptr->status == Normal_Completion)         /* if we've been called without an override */
1759                     cvptr->status = Uncorrectable_Data_Error;   /*   then presume that an uncorrectable error occurred */
1760                 }
1761 
1762             cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit    /* save the Status-1 value */
1763                                   | S1_STATUS (cvptr->status)); /*   in the buffer */
1764 
1765             set_address (cvptr, 1);                         /* save the CHS values in the buffer */
1766 
1767             tpprintf (cvptr->device, DL_DEB_CMD, "%s returns %sunit %u | %s | cylinder %u head %u sector %u | "
1768                                                  "syndrome %06o %06o %06o %06o\n",
1769                       opcode_name [Request_Syndrome], fmt_bitset (cvptr->spd_unit, status_1_format),
1770                       CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
1771                       cvptr->cylinder, cvptr->head, cvptr->sector,
1772                       cvptr->buffer [3], cvptr->buffer [4], cvptr->buffer [5], cvptr->buffer [6]);
1773 
1774             next_sector (cvptr, cvptr->device->units        /* address the next sector of the last unit used */
1775                                   + S1_UNIT (cvptr->spd_unit));
1776             break;
1777 
1778 
1779         case Set_File_Mask:
1780             cvptr->file_mask = CM_FILE_MASK (inbound_data);     /* save the supplied file mask */
1781 
1782             outbound |= CM_RETRY (inbound_data);                /* return the retry count */
1783 
1784             set_completion (cvptr, cuptr, Normal_Completion);   /* schedule the command completion */
1785 
1786             tpprintf (cvptr->device, DL_DEB_CMD, "%s to %sretries %u\n",
1787                       opcode_name [Set_File_Mask], fmt_bitset (cvptr->file_mask, file_mask_format),
1788                       CM_RETRY (inbound_data));
1789             break;
1790 
1791 
1792         case Request_Disc_Address:
1793             set_address (cvptr, 0);                     /* set the controller's CHS values into the buffer */
1794 
1795             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns cylinder %u head %u sector %u\n",
1796                       unit, opcode_name [Request_Disc_Address], cvptr->cylinder, cvptr->head, cvptr->sector);
1797             break;
1798 
1799 
1800         case End:
1801             tpprintf (cvptr->device, DL_DEB_CMD, "%s\n", opcode_name [End]);
1802 
1803             end_command (cvptr, NULL, Normal_Completion);   /* end the command and idle the controller */
1804             break;
1805 
1806 
1807         case Wakeup:
1808             set_completion (cvptr, cuptr, Unit_Available);  /* schedule the command completion */
1809 
1810             tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s\n",
1811                       unit, opcode_name [Wakeup]);
1812             break;
1813 
1814 
1815         /* these commands wait for seek completion before starting */
1816 
1817         case Read_Without_Verify:
1818             cvptr->verify = FALSE;                      /* do not verify until a track is crossed */
1819             inbound_data &= ~CM_SPD_MASK;               /* clear the SPD bits to avoid changing the state */
1820 
1821         /* fall through into the Initialize case */
1822 
1823         case Initialize:
1824             cvptr->spd_unit |= CM_SPD (inbound_data);   /* merge the SPD flags with the unit */
1825 
1826         /* fall through into the read/write cases */
1827 
1828         case Read:
1829         case Read_Full_Sector:
1830         case Write:
1831         case Write_Full_Sector:
1832             if (duptr->PHASE == Seek_Phase)                 /* if the unit is currently seeking */
1833                 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
1834                           unit, opcode_name [cvptr->opcode]);
1835 
1836             else                                            /* otherwise the unit is idle */
1837                 set_rotation (cvptr, duptr);                /*   so set up the rotation phase and latency */
1838             break;
1839 
1840 
1841         /* these commands take parameters but otherwise require no preliminary work */
1842 
1843         case Seek:
1844         case Verify:
1845         case Address_Record:
1846         case Read_With_Offset:
1847         case Load_TIO_Register:
1848             break;
1849 
1850 
1851         case Invalid_Opcode:                            /* for completeness; invalid commands are not dispatched */
1852             break;
1853         }
1854     }
1855 
1856 
1857 if (cvptr->state == Busy_State) {                       /* if the command has not completed immediately */
1858     if (cuptr->wait != NO_EVENT && cvptr->type == MAC)  /*   then if the controller unit is scheduled */
1859         activate_unit (cvptr, cuptr);                   /*      then activate it */
1860 
1861     if (duptr && duptr->wait != NO_EVENT)               /*   and if the drive unit is valid and scheduled */
1862         activate_unit (cvptr, duptr);                   /*      then activate it as well */
1863     }
1864 
1865 if (outbound & WRTIO)                                           /* if status is expected immediately */
1866     outbound |= S1_STATUS (cvptr->status) | cvptr->spd_unit;    /*   then return the Status-1 value */
1867 
1868 return outbound;                                        /* return the data word and function set */
1869 }
1870 
1871 
1872 /* Continue the current command.
1873 
1874    This routine simulates continuing execution of the controller microcode for
1875    the current command.  It's called whenever the controller has had to wait for
1876    action from the CPU interface or the drive unit, and that action has now
1877    occurred.  Typically, this would be whenever the interface flag status
1878    changes, or a unit's event service has been entered.  It returns a set of
1879    action functions and a data word to the caller.  It also sets up the next
1880    phase of operation on the controller and/or drive unit and schedules the
1881    unit(s) as appropriate.
1882 
1883    On entry, the "uptr" parameter is set to NULL if the controller was called
1884    for a CPU interface action, or it points to the unit whose event service was
1885    just called; this may be either the controller unit or a drive unit.  The
1886    "inbound_flags" and "inbound_data" parameters contain the CPU interface flags
1887    and data buffer values.
1888 
1889    If the entry is for a unit service, the unit number of the drive requesting
1890    service is determined.  If the entry is for the CPU interface, the controller
1891    is checked; if it's idle, the routine returns because no command is in
1892    progress.
1893 
1894    While a unit is activated, the current phase indicates the reason for the
1895    activation, i.e., what the simulated drive is "doing" at the moment, as
1896    follows:
1897 
1898      Idle_Phase        -- waiting for the next command to be issued (note that
1899                           this phase, which indicates that the unit is not
1900                           scheduled, is distinct from the controller Idle_State,
1901                           which indicates that the controller itself is idle)
1902 
1903      Parameter_Phase   -- waiting for a parameter to be transferred to or from
1904                           the interface
1905 
1906      Seek_Phase        -- waiting for a seek to complete (explicit or automatic)
1907 
1908      Rotate_Phase      -- waiting for the target sector to arrive under the head
1909 
1910      Data_Phase        -- waiting for the interface to accept or return the next
1911                           data word to be transferred to or from the drive
1912 
1913      Intersector_Phase -- waiting for the controller to finish executing the
1914                           end-of-sector microcode
1915 
1916      End_Phase         -- waiting for the controller to finish executing the
1917                           microcode corresponding to the current command
1918 
1919    Depending on the current command opcode and phase, a number of actions may be
1920    taken:
1921 
1922      Idle_Phase -- If the controller unit is being serviced, then the 1.74
1923      second command wait timer has expired while waiting for a new command.
1924      Reset the file mask and idle the controller.
1925 
1926      Parameter_Phase -- If the controller unit is being serviced, then the 1.74
1927      second command wait timer has expired while waiting for a parameter from
1928      the CPU.  Reset the file mask and idle the controller.  Otherwise, for
1929      outbound parameters, return the next word from the sector buffer and
1930      restart the timer; if the last word has been sent, end the command.  For
1931      inbound parameters, store the next word in the appropriate controller state
1932      variable; if the last word has been received, end the command or set up the
1933      next operation phase (seek, rotate, etc.).
1934 
1935      Seek_Phase -- If a Seek or Recalibrate has completed, set Drive Attention
1936      status.  All other commands have been waiting for seek completion before
1937      starting, so set up the rotate phase to begin the command.
1938 
1939      Rotate_Phase -- Set up the read or write of the current sector.  For all
1940      commands except Verify, proceed to the data phase to begin the data
1941      transfer.  For Verify, skip the data phase and proceed directly to the
1942      end-of-sector processing, but schedule that event as though the full sector
1943      rotation time had elapsed.
1944 
1945      Data_Phase -- For read transfers, return the next word from the sector
1946      buffer, or for write transfers, store the next word into the sector buffer,
1947      and schedule the next data phase transfer if the CPU has not indicated an
1948      end-of-data condition.  If it has, or if the last word of the sector has
1949      been transmitted, schedule the intersector phase.
1950 
1951      Intersector_Phase -- Complete the read or write of the current sector.  If
1952      the CPU has indicated an end-of-data condition, end the command.
1953      Otherwise, address the next sector and schedule the rotate phase.
1954 
1955      End_Phase -- End the command.  The end phase is used to provide a
1956      controller delay when an operation has no other command phases.
1957 
1958    At the completion of the current phase, the next phase is scheduled, if
1959    required, before returning the appropriate function set and data word to the
1960    caller.
1961 
1962    The commands employ the various phases as follows:
1963                                                                Inter
1964        Command                  Param   Seek   Rotate   Data   sector   End
1965      +------------------------+-------+------+--------+------+--------+-----+
1966      | Cold Load Read         |   -   |  D   |   D    |  D   |   D    |  -  |
1967      | Recalibrate            |   -   |  D   |   -    |  -   |   -    |  -  |
1968      | Seek                   |   c   |  D   |   -    |  -   |   -    |  -  |
1969      | Request Status         |   c   |  -   |   -    |  -   |   -    |  -  |
1970      | Request Sector Address |   c   |  -   |   -    |  -   |   -    |  -  |
1971      | Read                   |   -   |  -   |   D    |  D   |   D    |  -  |
1972      | Read Full Sector       |   -   |  -   |   D    |  D   |   D    |  -  |
1973      | Verify                 |   c   |  -   |   D    |  -   |   D    |  -  |
1974      | Write                  |   -   |  -   |   D    |  D   |   D    |  -  |
1975      | Write Full Sector      |   -   |  -   |   D    |  D   |   D    |  -  |
1976      | Clear                  |   -   |  -   |   -    |  -   |   -    |  C  |
1977      | Initialize             |   -   |  -   |   D    |  D   |   D    |  -  |
1978      | Address Record         |   c   |  -   |   -    |  -   |   -    |  -  |
1979      | Request Syndrome       |   c   |  -   |   -    |  -   |   -    |  -  |
1980      | Read With Offset       |   c   |  -   |   D    |  D   |   D    |  -  |
1981      | Set File Mask          |   -   |  -   |   -    |  -   |   -    |  C  |
1982      | Invalid Opcode         |   -   |  -   |   -    |  -   |   -    |  C  |
1983      | Read Without Verify    |   -   |  -   |   D    |  D   |   D    |  -  |
1984      | Load TIO Register      |   c   |  -   |   -    |  -   |   -    |  -  |
1985      | Request Disc Address   |   c   |  -   |   -    |  -   |   -    |  -  |
1986      | End                    |   -   |  -   |   -    |  -   |   -    |  -  |
1987      | Wakeup                 |   -   |  -   |   -    |  -   |   -    |  C  |
1988      +------------------------+-------+------+--------+------+--------+-----+
1989 
1990      Key:
1991        C = controller unit is scheduled
1992        c = controller is called directly by the CPU interface
1993        D = drive unit is scheduled
1994        - = the phase is not used
1995 
1996 
1997    Implementation notes:
1998 
1999     1. The "%.0u" print specification in the trace call absorbs the zero "unit"
2000        value parameter without printing when the controller unit is specified.
2001 
2002     2. The Seek command does not check for Access Not Ready before issuing the
2003        seek, so if a prior seek is in progress, the drive will reject it with a
2004        Seek Check error.  However, the parameters (e.g., controller CHS
2005        addresses) are still set as though the command had succeeded.
2006 
2007        A Seek command will return to the Poll Loop with Seek Check status set.
2008        When the seek in progress completes, the controller will interrupt with
2009        Drive Attention status.  The controller address will differ from the
2010        drive address, so it's incumbent upon the caller to issue a Request
2011        Status command after the seek, which will return Status-2 Error status.
2012 
2013     3. The set of interface functions to assert on command completion is
2014        normally specified by the End_Phase entry in the cmd_functions table,
2015        regardless of whether or not a command has an end phase.  However, the
2016        Request Syndrome command returns either Correctable Data Error or
2017        Uncorrectable Data Error for normal command completion.  These status
2018        returns would normally include DVEND to indicate that the command should
2019        be retried, but that's wrong for Request Syndrome, so we explicitly
2020        override the function set for this command.
2021 
2022     4. Command completion must be detected by the controller state changing to
2023        "not busy" rather than simply being "not busy" at the end of the routine.
2024        Otherwise, a seek that completes while the controller is waiting for a
2025        command would re-issue the end phase functions.
2026 
2027     5. The disc is a synchronous device, so overrun or underrun can occur if the
2028        interface is not ready when the controller must transfer data.  There are
2029        four conditions that lead to an overrun or underrun:
2030 
2031          a. The controller is ready with a disc read word (IFCLK * IFIN), but
2032             the interface buffer is full (DTRDY).
2033 
2034          b. The controller needs a disc write word (IFCLK * IFOUT), but the
2035             interface buffer is empty (~DTRDY).
2036 
2037          c. The CPU attempts to read a word, but the interface buffer is empty
2038             (~DTRDY).
2039 
2040          d. The CPU attempts to write a word, but the interface buffer is full
2041             (DTRDY).
2042 
2043        The 13037 controller ORs the interface-supplied OVRUN signal with an
2044        internal overrun latch that sets on condition 2 above (write underrun).
2045        However, both the 13175A HP 1000 interface and the 30229B HP 3000
2046        interface assert OVRUN for all four conditions, so the latch is not
2047        simulated.
2048 
2049     6. Not all changes of CPU interface flag status are significant.  If the
2050        routine is called when it isn't needed, the routine simply returns with
2051        no action.
2052 */
2053 
continue_command(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET inbound_flags,CNTLR_IBUS inbound_data)2054 static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET inbound_flags, CNTLR_IBUS inbound_data)
2055 {
2056 const t_bool service_entry = (uptr != NULL);            /* set TRUE if entered via unit service */
2057 CNTLR_OPCODE opcode;
2058 CNTLR_PHASE phase;
2059 CNTLR_IFN_IBUS outbound;
2060 t_bool controller_service, controller_was_busy;
2061 int32 unit;
2062 uint32 sector_count;
2063 
2064 if (service_entry) {                                    /* if this is an event service entry */
2065     unit = (int32) (uptr - cvptr->device->units);       /*   then get the unit number */
2066 
2067     controller_service = (uptr == CNTLR_UPTR            /* set TRUE if the controller is being serviced */
2068                             && cvptr->type == MAC);
2069     }
2070 
2071 else if (CNTLR_UPTR->PHASE == Idle_Phase)               /* otherwise if this interface entry isn't needed */
2072     return NO_ACTION;                                   /*   then quit as there's nothing to do */
2073 
2074 else {                                                  /* otherwise the controller is expecting the entry */
2075     uptr = CNTLR_UPTR;                                  /* set up to use the controller unit */
2076     unit = CNTLR_UNIT;                                  /*   and unit number */
2077     controller_service = FALSE;                         /*     but note that this isn't a service entry */
2078     }
2079 
2080 
2081 opcode = (CNTLR_OPCODE) uptr->OPCODE;                   /* get the current opcode */
2082 phase  = (CNTLR_PHASE)  uptr->PHASE;                    /*   and command phase */
2083 
2084 if (controller_service == FALSE || phase == End_Phase)
2085     tpprintf (cvptr->device, DL_DEB_STATE, (unit == CNTLR_UNIT
2086                                               ? "Controller unit%.0d %s %s phase entered from %s\n"
2087                                               : "Unit %d %s %s phase entered from %s\n"),
2088               (unit == CNTLR_UNIT ? 0 : unit), opcode_name [opcode], phase_name [phase],
2089               (service_entry ? "service" : "interface"));
2090 
2091 controller_was_busy = (cvptr->state == Busy_State);     /* set TRUE if the controller was busy on entry */
2092 
2093 outbound = cmd_functions [opcode] [phase];              /* set up the initial function return set */
2094 
2095 
2096 switch (phase) {                                        /* dispatch the phase */
2097 
2098     case Idle_Phase:                                    /* the command wait timer has expired */
2099         clear_controller (cvptr, Timeout_Clear);        /*   so idle the controller and clear the file mask */
2100 
2101         outbound = NO_FUNCTIONS;                        /* clear the function set for an idle return */
2102 
2103         tpprintf (cvptr->device, DL_DEB_INCO, "Controller command wait timed out\n");
2104         break;
2105 
2106 
2107     case Parameter_Phase:
2108         if (controller_service) {                       /* if the parameter wait timer has expired */
2109             clear_controller (cvptr, Timeout_Clear);    /*   then idle the controller and clear the file mask */
2110 
2111             outbound = NO_FUNCTIONS;                    /* clear the function set for an idle return */
2112 
2113             tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command aborted with parameter wait timeout\n",
2114                       CM_UNIT (cvptr->spd_unit), opcode_name [opcode]);
2115             }
2116 
2117         else switch (opcode) {                          /* otherwise dispatch the command */
2118 
2119             case Request_Status:                        /* these commands */
2120             case Request_Disc_Address:                  /*   return parameters */
2121             case Request_Sector_Address:                /*     to the interface */
2122             case Request_Syndrome:
2123                 if (cvptr->length == 0)                         /* if the last parameter has been sent */
2124                     end_command (cvptr, uptr, cvptr->status);   /*   then terminate the command with the preset status */
2125 
2126                 else {                                          /* otherwise there are more to send */
2127                     outbound |= cvptr->buffer [cvptr->index++]; /*   so return the next value from the buffer */
2128                     cvptr->length = cvptr->length - 1;          /*     and drop the parameter count */
2129 
2130                     wait_timer (cvptr, SET);                    /* restart the parameter timer */
2131                     }
2132                 break;
2133 
2134 
2135             case Seek:                                          /* these commands receive parameters */
2136             case Address_Record:                                /*   from the interface */
2137                 cvptr->buffer [cvptr->index++] =                /* save the current one in the buffer */
2138                    (DL_BUFFER) inbound_data;
2139                 cvptr->length = cvptr->length - 1;              /*   and drop the parameter count */
2140 
2141                 if (cvptr->length > 0)                          /* if another parameter is expected */
2142                     wait_timer (cvptr, SET);                    /*   then restart the parameter timer */
2143 
2144                 else {                                              /* otherwise all parameters are in */
2145                     cvptr->cylinder = cvptr->buffer [0];            /*   so fill in the supplied cylinder */
2146                     cvptr->head = PI_HEAD (cvptr->buffer [1]);      /*     and head */
2147                     cvptr->sector = PI_SECTOR (cvptr->buffer [1]);  /*       and sector addresses */
2148 
2149                     if (opcode == Address_Record) {             /* if this is an Address Record command */
2150                         cvptr->eoc = CLEAR;                     /*   then clear the end-of-cylinder flag */
2151 
2152                         tpprintf (cvptr->device, DL_DEB_CMD, "%s to cylinder %u head %u sector %u\n",
2153                                   opcode_name [Address_Record],
2154                                   cvptr->cylinder, cvptr->head, cvptr->sector);
2155 
2156                         end_command (cvptr, uptr,               /* the command is now complete */
2157                                      Normal_Completion);
2158                         }
2159 
2160                     else {                                      /* otherwise it's a Seek command */
2161                         tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder %u head %u sector %u\n",
2162                                   CM_UNIT (cvptr->spd_unit), opcode_name [Seek],
2163                                   cvptr->cylinder, cvptr->head, cvptr->sector);
2164 
2165                         uptr = cvptr->device->units             /* get the target unit */
2166                                  + CM_UNIT (cvptr->spd_unit);
2167 
2168                         if (start_seek (cvptr, uptr) == FALSE)  /* start the seek; if it failed, */
2169                             end_command (cvptr, uptr,           /*   then report the error */
2170                                          Status_2_Error);
2171 
2172                         else if (cvptr->type == MAC)            /* otherwise if this a MAC controller */
2173                             end_command (cvptr, uptr,           /*   then complete the command and idle the controller */
2174                                          Normal_Completion);
2175                         }                                       /* otherwise an ICD command ends when the seek completes */
2176                     }
2177                 break;
2178 
2179 
2180             case Verify:
2181                 if (inbound_data == 0)                  /* if the sector count is zero */
2182                     sector_count = 65536;               /*   then use the rollover count */
2183                 else                                    /* otherwise */
2184                     sector_count = inbound_data;        /*   use the count as is */
2185 
2186                 cvptr->count = sector_count * WORDS_PER_SECTOR; /* convert to the number of words to verify */
2187 
2188                 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s %u sector%s\n",
2189                           CM_UNIT (cvptr->spd_unit), opcode_name [Verify],
2190                           sector_count, (sector_count == 1 ? "" : "s"));
2191 
2192                 wait_timer (cvptr, CLEAR);              /* stop the parameter timer */
2193 
2194                 uptr = cvptr->device->units             /* get the target unit */
2195                          + CM_UNIT (cvptr->spd_unit);
2196 
2197                 if (uptr->PHASE == Seek_Phase) {        /* if a seek is in progress, */
2198                     uptr->wait = NO_EVENT;              /*   then wait for it to complete */
2199 
2200                     tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
2201                               CM_UNIT (cvptr->spd_unit), opcode_name [Verify]);
2202                     }
2203 
2204                 else                                    /* otherwise the unit is idle */
2205                     set_rotation (cvptr, uptr);         /*   so set up the rotation phase and latency */
2206                 break;
2207 
2208 
2209             case Read_With_Offset:
2210                 tpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s using %soffset %+d\n",
2211                           CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset],
2212                           fmt_bitset (inbound_data, offset_format),
2213                           (inbound_data & PI_NEG_OFFSET ? - (int) PI_OFFSET (inbound_data)
2214                                                         :   (int) PI_OFFSET (inbound_data)));
2215 
2216                 wait_timer (cvptr, CLEAR);                  /* stop the parameter timer */
2217 
2218                 uptr = cvptr->device->units                 /* get the target unit */
2219                          + CM_UNIT (cvptr->spd_unit);
2220 
2221                 if (uptr->PHASE == Seek_Phase) {            /* if a seek is in progress, */
2222                     uptr->wait = NO_EVENT;                  /*   then wait for it to complete */
2223 
2224                     tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n",
2225                               CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset]);
2226                     }
2227 
2228                 else {                                      /* otherwise the unit is idle */
2229                     uptr->PHASE = Seek_Phase;               /*   so schedule the seek phase */
2230                     uptr->wait = cvptr->dlyptr->seek_one;   /*     with the offset positioning delay */
2231                     }
2232                 break;
2233 
2234 
2235             case Load_TIO_Register:
2236                 wait_timer (cvptr, CLEAR);                      /* stop the parameter timer */
2237 
2238                 tpprintf (cvptr->device, DL_DEB_CMD, "%s with %06o\n",
2239                           opcode_name [Load_TIO_Register], inbound_data);
2240 
2241                 end_command (cvptr, uptr, Normal_Completion);   /* complete the command */
2242 
2243                 return inbound_data                             /* return the supplied TIO value */
2244                          | cmd_functions [Load_TIO_Register] [End_Phase];
2245                 break;
2246 
2247 
2248             default:                                    /* the remaining commands */
2249                 break;                                  /*   do not have a parameter phase */
2250             }
2251 
2252         break;
2253 
2254 
2255     case Seek_Phase:
2256         switch (opcode) {                               /* dispatch the command */
2257 
2258             case Recalibrate:
2259             case Seek:
2260                 if (cvptr->type == MAC) {               /* if this a MAC controller */
2261                     uptr->STATUS |= S2_ATTENTION;       /*   set Attention in the unit status */
2262                     uptr->PHASE = Idle_Phase;           /*     and idle the drive */
2263                     }
2264 
2265                 else                                            /* otherwise this is an ICD or CS/80 drive */
2266                     end_command (cvptr, uptr, Drive_Attention); /*   so seeks end with Drive Attention status */
2267                 break;
2268 
2269 
2270             case Cold_Load_Read:
2271                 cvptr->file_mask = CM_SPARE_EN;             /* enable sparing in surface mode without auto-seek */
2272 
2273             /* fall through into the default case */
2274 
2275             default:                                        /* a command was waiting on seek completion */
2276                 set_rotation (cvptr, uptr);                 /*   so set up the rotation phase and latency */
2277                 break;
2278             }
2279 
2280         break;
2281 
2282 
2283     case Rotate_Phase:
2284         switch (opcode) {                               /* dispatch the command */
2285 
2286             case Write:
2287             case Write_Full_Sector:
2288             case Initialize:
2289                 start_write (cvptr, uptr);              /* start the sector write */
2290                 break;
2291 
2292 
2293             case Read:
2294             case Read_Full_Sector:
2295             case Read_With_Offset:
2296             case Read_Without_Verify:
2297             case Cold_Load_Read:
2298                 start_read (cvptr, uptr, inbound_flags);    /* start the sector read */
2299                 break;
2300 
2301 
2302             case Verify:
2303                 inbound_flags &= ~EOD;                          /* EOD is not relevant for Verify */
2304 
2305                 if (start_read (cvptr, uptr, inbound_flags)) {  /* if the sector read was set up successfully */
2306                     uptr->PHASE = Intersector_Phase;            /*   then skip the data phase */
2307                     uptr->wait = cvptr->dlyptr->sector_full;    /*     and reschedule for the sector read time */
2308                     }
2309                 break;
2310 
2311 
2312             default:                                    /* the remaining commands */
2313                 break;                                  /*   do not have a rotate phase */
2314             }
2315 
2316         break;
2317 
2318 
2319     case Data_Phase:
2320         if (inbound_flags & EOD)                        /* if the transfer has ended */
2321             outbound = NO_FUNCTIONS;                    /*   then don't assert IFIN/IFOUT on return */
2322 
2323         switch (opcode) {                               /* dispatch the command */
2324 
2325             case Read:
2326             case Read_With_Offset:
2327             case Read_Without_Verify:
2328             case Read_Full_Sector:
2329             case Cold_Load_Read:
2330                 if ((inbound_flags & EOD) == NO_FLAGS) {            /* if the transfer continues */
2331                     outbound |= cvptr->buffer [cvptr->index++];     /*   then get the next word from the buffer */
2332 
2333                     cvptr->count  = cvptr->count  + 1;              /* count the */
2334                     cvptr->length = cvptr->length - 1;              /*   transfer */
2335 
2336                     tpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n",
2337                               unit, opcode_name [opcode],
2338                               cvptr->count, DLIBUS (outbound));
2339                     }
2340 
2341                 uptr->wait = cvptr->dlyptr->data_xfer;              /* set the transfer delay */
2342 
2343                 if (cvptr->length == 0 || inbound_flags & EOD) {    /* if the buffer is empty or the transfer is done */
2344                       uptr->PHASE = Intersector_Phase;              /*   then set up the intersector phase */
2345 
2346                       if (cvptr->device->flags & DEV_REALTIME)      /* if we're in realistic timing mode */
2347                           uptr->wait = uptr->wait                   /*   then account for the actual delay */
2348                                          * (cvptr->length + cmd_props [opcode].postamble_size);
2349                       }
2350                 break;
2351 
2352 
2353             case Write:
2354             case Write_Full_Sector:
2355             case Initialize:
2356                 if ((inbound_flags & EOD) == NO_FLAGS) {    /* if the transfer continues */
2357                     cvptr->buffer [cvptr->index++] =        /*   then store the next word in the buffer */
2358                        (DL_BUFFER) inbound_data;
2359 
2360                     cvptr->count  = cvptr->count  + 1;      /* count the */
2361                     cvptr->length = cvptr->length - 1;      /*   transfer */
2362 
2363                     tpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n",
2364                               unit, opcode_name [opcode],
2365                               cvptr->count, inbound_data);
2366                     }
2367 
2368                 uptr->wait = cvptr->dlyptr->data_xfer;              /* set the transfer delay */
2369 
2370                 if (cvptr->length == 0 || inbound_flags & EOD) {    /* if the buffer is empty or the transfer is done */
2371                       uptr->PHASE = Intersector_Phase;              /*   then set up the intersector phase */
2372 
2373                       if (cvptr->device->flags & DEV_REALTIME)      /* if we're in realistic timing mode */
2374                           uptr->wait = uptr->wait                   /*   then account for the actual delay */
2375                                          * (cvptr->length + cmd_props [opcode].postamble_size);
2376                       }
2377                 break;
2378 
2379 
2380             default:                                    /* the remaining commands */
2381                 break;                                  /*   do not have a data phase */
2382             }
2383 
2384         break;
2385 
2386 
2387     case Intersector_Phase:
2388         switch (opcode) {                               /* dispatch the command */
2389 
2390             case Read:
2391             case Read_With_Offset:
2392             case Read_Without_Verify:
2393             case Read_Full_Sector:
2394             case Cold_Load_Read:
2395                 end_read (cvptr, uptr, inbound_flags);  /* end the sector read */
2396                 break;
2397 
2398 
2399             case Write:
2400             case Write_Full_Sector:
2401             case Initialize:
2402                 end_write (cvptr, uptr, inbound_flags); /* end the sector write */
2403                 break;
2404 
2405 
2406             case Verify:
2407                 cvptr->count = cvptr->count - WORDS_PER_SECTOR; /* decrement the word count */
2408 
2409                 if (cvptr->count > 0)                   /* if there more sectors to verify */
2410                     inbound_flags &= ~EOD;              /*   then this is not the end of data */
2411                 else                                    /* otherwise the command is complete */
2412                     inbound_flags |= EOD;               /*   and this is the end of data */
2413 
2414                 end_read (cvptr, uptr, inbound_flags);  /* end the sector read */
2415                 break;
2416 
2417 
2418             default:                                    /* the remaining commands */
2419                 break;                                  /*   do not have an intersector phase */
2420             }
2421 
2422         break;
2423 
2424 
2425     case End_Phase:
2426         end_command (cvptr, uptr, cvptr->status);       /* complete the command with the preset status */
2427         break;
2428     }
2429 
2430 
2431 if (uptr->wait != NO_EVENT)                             /* if the unit has been scheduled */
2432     activate_unit (cvptr, uptr);                        /*   then activate it */
2433 
2434 if (controller_was_busy && cvptr->state != Busy_State) {    /* if the command has just completed */
2435     if (cvptr->status == Normal_Completion                  /*   then if the command completed normally */
2436       || opcode == Request_Syndrome)                        /*   or it was a Request Syndrome command */
2437         outbound = cmd_functions [opcode] [End_Phase];      /*     then use the normal exit function set */
2438     else                                                    /*   otherwise */
2439         outbound = status_functions [cvptr->status];        /*     the function set depends on the status */
2440 
2441     if (outbound & WRTIO)                                           /* if the TIO register will be written */
2442         outbound |= S1_STATUS (cvptr->status) | cvptr->spd_unit;    /*   then include the Status-1 value */
2443     }
2444 
2445 return outbound;                                        /* return the data word and function set */
2446 }
2447 
2448 
2449 /* Poll the drives for Attention status.
2450 
2451    MAC controllers complete their Seek and Recalibrate commands when the seeks
2452    are initiated, so that other drives may be serviced during the waits.  A
2453    drive will set its Attention status when its seek completes, and the
2454    controller must poll the drives for attention requests when it is idle and
2455    interrupts are allowed by the CPU interface.
2456 
2457    Starting with the last unit that had previously requested attention, each
2458    drive is checked in sequence.  If a drive has its Attention status set, the
2459    controller saves its unit number, sets the result status to Drive Attention,
2460    and enters the command wait state.  The routine returns a function set that
2461    indicates that an interrupt should be generated.  The next time the routine
2462    is called, the poll begins with the last unit that requested attention, so
2463    that each unit is given an equal chance to respond.
2464 
2465    If no unit is requesting attention, the routine returns an empty function set
2466    to indicate that no interrupt should be generated.
2467 
2468    ICD controllers do not call this routine, because each controller waits for
2469    seek completion on its dedicated drive before completing the associated Seek
2470    or Recalibrate command.
2471 */
2472 
poll_drives(CVPTR cvptr)2473 static CNTLR_IFN_IBUS poll_drives (CVPTR cvptr)
2474 {
2475 uint32  unit;
2476 UNIT   *units = cvptr->device->units;
2477 
2478 tpprintf (cvptr->device, DL_DEB_INCO, "Controller polled drives for attention\n");
2479 
2480 for (unit = 0; unit <= DL_MAXDRIVE; unit++) {           /* check each unit in turn */
2481     cvptr->poll_unit =                                  /* start with the last unit checked */
2482       (cvptr->poll_unit + 1) % (DL_MAXDRIVE + 1);       /*   and cycle back to unit 0 */
2483 
2484     if (units [cvptr->poll_unit].STATUS & S2_ATTENTION) {   /* if the unit is requesting attention, */
2485         units [cvptr->poll_unit].STATUS &= ~S2_ATTENTION;   /*   clear the Attention status */
2486 
2487         tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u requested attention\n",
2488                   cvptr->poll_unit);
2489 
2490         cvptr->spd_unit = cvptr->poll_unit;             /* set the controller's unit number */
2491         cvptr->status = Drive_Attention;                /*   and status */
2492 
2493         cvptr->state = Wait_State;                      /* set the controller state to waiting */
2494         wait_timer (cvptr, SET);                        /* start the command wait timer */
2495 
2496         return status_functions [Drive_Attention]               /* tell the caller to interrupt */
2497                  | S1_STATUS (cvptr->status) | cvptr->spd_unit; /*   and include the Status-1 value */
2498         }
2499     }
2500 
2501 return NO_ACTION;                                       /* no drives have attention set */
2502 }
2503 
2504 
2505 /* Clear the controller.
2506 
2507    A "hard", "timeout", or "soft" clear is performed on the indicated controller
2508    as specified by the "clear_type" parameter.
2509 
2510    In hardware, four conditions clear the 13037 controller:
2511 
2512      - an initial application of power
2513      - an assertion of the CLEAR signal by the CPU interface
2514      - a timeout of the command wait timer
2515      - a programmed Clear command
2516 
2517    The first two conditions, called "hard clears," are equivalent and cause a
2518    firmware restart with the PWRON flag set.  The 13175 interface for the HP
2519    1000 asserts the CLEAR signal in response to the backplane CRS signal if the
2520    PRESET jumper is installed in the enabled position (which is the usual case).
2521    The 30229B interface for the HP 3000 asserts CLEAR in response to an IORESET
2522    signal or a programmed Master Reset if the PRESET DISABLE jumper is installed
2523    in the enabled position.
2524 
2525    The third condition, a "timeout clear", also causes a firmware restart but
2526    with the PWRON flag clear.  The last condition, a "soft clear" is executed in
2527    the command handler and therefore returns to the Command Wait Loop instead of
2528    the Poll Loop.
2529 
2530    For a hard clear, the 13037 controller will:
2531 
2532      - disconnect the CPU interface
2533      - zero the controller RAM (no drives held, last polled unit number reset)
2534      - clear the clock offset
2535      - clear the file mask
2536      - issue a Controller Preset to clear all connected drives
2537      - enter the Poll Loop (which clears the controller status)
2538 
2539    For a timeout clear, the 13037 controller will:
2540 
2541      - disconnect the CPU interface
2542      - clear the hold bits of any drives held by the interface that timed out
2543      - clear the clock offset
2544      - clear the file mask
2545      - enter the Poll Loop (which clears the controller status)
2546 
2547    For a programmed "soft" clear, the 13037 controller will:
2548 
2549      - clear the controller status
2550      - issue a Controller Preset to clear all connected drives
2551      - enter the Command Wait Loop
2552 
2553    Controller Preset is a tag bus command that is sent to all drives connected
2554    to the controller.  Each drive will:
2555 
2556      - disconnect from the controller
2557      - clear its internal drive faults
2558      - clear its head and sector registers
2559      - clear its illegal head and sector flip-flops
2560      - reset its seek check, first status, drive fault, and attention status
2561 
2562    On a 7905 or 7906 drive, clearing the head register will change Read-Only
2563    status to reflect the position of the PROTECT LOWER DISC switch.
2564 
2565    In simulation, a hard clear occurs when an SCP RESET command is entered, or a
2566    programmed CLC 0 instruction or Master Clear is executed.  A timeout clear
2567    occurs when the command or parameter wait timer expires.  A soft clear occurs
2568    when a programmed Clear command is issued.
2569 
2570    Because the controller execution state is implemented by scheduling command
2571    phases for the target or controller unit, a simulated firmware restart must
2572    abort any in-process activation.  However, a firmware restart does not affect
2573    seeks in progress, so these must be allowed to continue to completion so that
2574    their Attention requests will be honored.
2575 
2576 
2577    Implementation notes:
2578 
2579     1. The specific 13365 controller actions on hard or soft clears are not
2580        documented.  Therefore, an ICD controller clear is handled as a MAC
2581        controller clear, except that only the current drive is preset (as an ICD
2582        controller manages only a single drive).
2583 
2584     2. Neither hard nor soft clears affect the controller flags (e.g., EOC) or
2585        registers (e.g., cylinder address).
2586 
2587     3. In simulation, an internal seek, such as an auto-seek during a Read
2588        command or the initial seek during a Cold Load Read command, will be
2589        aborted for a hard clear, whereas in hardware it would complete normally.
2590        This is OK, however, because an internal seek always clears the drive's
2591        Attention status on completion, so aborting the simulated seek is
2592        equivalent to an immediate seek completion.
2593 
2594     4. If a drive unit is disabled, it is still cleared.  A unit cannot be
2595        disabled while it is active, so it must be in the idle state while
2596        disabled.  Clearing the status keeps it consistent in case it is
2597        reenabled later.
2598 
2599     5. A soft clear does not abort commands in progress on a drive unit.
2600        However, a soft clear is a result of a programmed command that can only
2601        be issued when the prior command has completed (except for Seek and
2602        Recalibrate commands, which are never aborted).
2603 
2604     6. In simulation, a Controller Preset only resets the specified status bits,
2605        as the remainder of the hardware actions are not implemented.
2606 */
2607 
clear_controller(CVPTR cvptr,CNTLR_CLEAR clear_type)2608 static void clear_controller (CVPTR cvptr, CNTLR_CLEAR clear_type)
2609 {
2610 uint32  unit_count;
2611 UNIT   *uptr;
2612 
2613 if (clear_type == Timeout_Clear) {                      /* if this is a timeout clear */
2614     cvptr->file_mask = 0;                               /*   then clear the file mask */
2615     idle_controller (cvptr);                            /*     and idle the controller */
2616     }
2617 
2618 else {                                                  /* otherwise */
2619     if (clear_type == Hard_Clear) {                     /*   if this a hard clear */
2620         cvptr->file_mask = 0;                           /*     then clear the file mask */
2621 
2622         if (cvptr->type == MAC)                         /* if this is a MAC controller */
2623             cvptr->poll_unit = 0;                       /*   then clear the last unit polled too */
2624 
2625         idle_controller (cvptr);                        /* idle the controller */
2626         }
2627 
2628     else                                                /* otherwise it's a soft clear */
2629         cvptr->status = Normal_Completion;              /*   so clear the status explicitly */
2630 
2631     if (cvptr->type == MAC) {                           /* if this a MAC controller */
2632         uptr = cvptr->device->units;                    /*   then preset all units */
2633         unit_count = cvptr->device->numunits - 1;       /*     except the controller unit */
2634         }
2635 
2636     else {                                              /* otherwise preset */
2637         uptr = cvptr->device->units + cvptr->poll_unit; /*   only the single unit */
2638         unit_count = 1;                                 /*     dedicated to the controller */
2639         }
2640 
2641     while (unit_count > 0) {                            /* preset each drive in turn */
2642         if (uptr->PHASE != Idle_Phase                   /* if the unit is active */
2643           && uptr->OPCODE != Seek                       /*   but not seeking */
2644           && uptr->OPCODE != Recalibrate) {             /*     or recalibrating */
2645             sim_cancel (uptr);                          /*       then cancel the unit event */
2646             uptr->PHASE = Idle_Phase;                   /*         and idle it */
2647             }
2648 
2649         uptr->STATUS &= ~(S2_CPS | S2_READ_ONLY);       /* do a "Controller Preset" on the unit */
2650 
2651         if (uptr->flags & UNIT_PROT_U)                  /* if the (upper) heads are protected */
2652             uptr->STATUS |= S2_READ_ONLY;               /*   then set read-only status */
2653 
2654         uptr++;                                         /* point at the next unit */
2655         unit_count = unit_count - 1;                    /*   and count the unit just cleared */
2656         }
2657     }
2658 
2659 return;
2660 }
2661 
2662 
2663 
2664 /* Disc library global utility routines */
2665 
2666 
2667 /* Return the name of an opcode.
2668 
2669    A string representing the supplied controller opcode is returned to the
2670    caller.  If the opcode is illegal or undefined for the indicated controller,
2671    the string "Invalid" is returned.
2672 */
2673 
dl_opcode_name(CNTLR_TYPE controller,CNTLR_OPCODE opcode)2674 const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode)
2675 {
2676 if (controller <= LAST_CNTLR                            /* if the controller type is legal */
2677   && opcode <= LAST_OPCODE                              /*   and the opcode is legal */
2678   && cmd_props [opcode].valid [controller])             /*     and is defined for this controller, */
2679     return opcode_name [opcode];                        /*       then return the opcode name */
2680 else                                                    /* otherwise the type or opcode is illegal */
2681     return invalid_name;                                /*   so return an error indication */
2682 }
2683 
2684 
2685 /* Return the name of a command result status.
2686 
2687    A string representing the supplied command result status is returned to the
2688    caller.  If the status is illegal or undefined, the string "Invalid" is
2689    returned.
2690 */
2691 
dl_status_name(CNTLR_STATUS status)2692 const char *dl_status_name (CNTLR_STATUS status)
2693 {
2694 if (status <= Drive_Attention && status_name [status])  /* if the status is legal */
2695     return status_name [status];                        /*   then return the status name */
2696 else                                                    /* otherwise the status is illegal */
2697     return invalid_name;                                /*   so return an error indication */
2698 }
2699 
2700 
2701 
2702 /* Disc library global SCP support routines */
2703 
2704 
2705 /* Attach a disc image file to a unit.
2706 
2707    The file specified by the supplied filename is attached to the indicated
2708    unit.  If the attach was successful, the heads are loaded on the drive.
2709 
2710 
2711    Implementation notes:
2712 
2713     1. The pointer to the appropriate event delay times is set in case we are
2714        being called during a RESTORE command (the assignment is redundant
2715        otherwise).
2716 */
2717 
dl_attach(CVPTR cvptr,UNIT * uptr,char * cptr)2718 t_stat dl_attach (CVPTR cvptr, UNIT *uptr, char *cptr)
2719 {
2720 t_stat result;
2721 
2722 result = attach_unit (uptr, cptr);                          /* attach the unit */
2723 
2724 if (result == SCPE_OK)                                      /* if the attach succeeded */
2725   result = dl_load_unload (cvptr, uptr, TRUE);              /*   then load the heads */
2726 
2727 dl_set_timing (cvptr->device->units,                        /* reestablish */
2728                (cvptr->device->flags & DEV_REALTIME),       /*   the delay times */
2729                NULL, (void *) cvptr);                       /*     pointer(s) */
2730 
2731 return result;                                              /* return the command result status */
2732 }
2733 
2734 
2735 /* Detach a disc image file from a unit.
2736 
2737    The heads are unloaded on the drive, and the attached file, if any, is
2738    detached.
2739 */
2740 
dl_detach(CVPTR cvptr,UNIT * uptr)2741 t_stat dl_detach (CVPTR cvptr, UNIT *uptr)
2742 {
2743 t_stat unload, detach;
2744 
2745 unload = dl_load_unload (cvptr, uptr, FALSE);           /* unload the heads */
2746 
2747 if (unload == SCPE_OK || unload == SCPE_INCOMP) {       /* if the unload succeeded */
2748     detach = detach_unit (uptr);                        /*   then detach the unit */
2749 
2750     if (detach == SCPE_OK)                              /* if the detach succeeded as well */
2751         return unload;                                  /*   then return the unload status */
2752     else                                                /* otherwise */
2753         return detach;                                  /*   return the detach failure status */
2754     }
2755 
2756 else                                                    /* otherwise the unload failed */
2757     return unload;                                      /*   so return the failure status */
2758 }
2759 
2760 
2761 /* Load or unload the drive heads.
2762 
2763    In hardware, a drive's heads are loaded when a disc pack is installed and the
2764    RUN/STOP switch is set to RUN.  The drive reports First Status when the heads
2765    load to indicate that the pack has potentially changed.  Setting the switch
2766    to STOP unloads the heads.  When the heads are unloaded, the drive reports
2767    Not Ready and Drive Busy status.  In both cases, the drive reports Attention
2768    status to the controller.  A MAC controller will clear a drive's Attention
2769    status and will interrupt the CPU when the drives are polled in the Idle
2770    Loop.  An ICD controller also clears the drive's Attention status but will
2771    assert a Parallel Poll Response only when the heads unload.
2772 
2773    In simulation, the unit must be attached, corresponding to having a disc pack
2774    installed in the drive, before the heads may be unloaded or loaded.  If it
2775    isn't, the routine returns SCPE_UNATT.  Otherwise, the UNIT_UNLOAD flag and
2776    the drive status are set accordingly.
2777 
2778    If the (MAC) controller is idle, the routine returns SCPE_INCOMP to indicate
2779    that the caller must then call the controller to poll for drive attention to
2780    complete the command.  Otherwise, it returns SCPE_OK, and the drives will be
2781    polled automatically when the current command or command wait completes and
2782    the controller is idled.
2783 
2784 
2785    Implementation notes:
2786 
2787     1. Loading or unloading the heads clears Fault and Seek Check status.
2788 
2789     2. If we are called during a RESTORE command, the unit's flags are not
2790        changed to avoid upsetting the state that was SAVEd.
2791 
2792     3. Unloading an active unit does not cancel the event.  This ensures that
2793        the controller will not hang during a transfer but instead will see the
2794        unloaded unit and fail the transfer with Access_Not_Ready status.
2795 */
2796 
dl_load_unload(CVPTR cvptr,UNIT * uptr,t_bool load)2797 t_stat dl_load_unload (CVPTR cvptr, UNIT *uptr, t_bool load)
2798 {
2799 if ((uptr->flags & UNIT_ATT) == 0)                      /* the unit must be attached to [un]load */
2800     return SCPE_UNATT;                                  /*   so return "Unit not attached" if it is not */
2801 
2802 else if ((sim_switches & SIM_SW_REST) == 0) {           /* if we are not being called during a RESTORE command */
2803     uptr->STATUS &= ~S2_CPS;                            /*   then do a "Controller Preset" on the unit */
2804 
2805     if (load) {                                         /* if we are loading the heads */
2806         uptr->flags &= ~UNIT_UNLOAD;                    /*   then clear the unload flag */
2807         uptr->STATUS |= S2_FIRST_STATUS;                /*     and set First Status */
2808 
2809         if (cvptr->type != ICD)                         /* if this is not an ICD controller */
2810             uptr->STATUS |= S2_ATTENTION;               /*   then set Attention status also */
2811         }
2812 
2813     else {                                              /* otherwise we are unloading the heads */
2814         uptr->flags |= UNIT_UNLOAD;                     /*   so set the unload flag */
2815         uptr->STATUS |= S2_ATTENTION;                   /*     and Attention status */
2816         }
2817 
2818     tpprintf (cvptr->device, DL_DEB_CMD, "RUN/STOP switch set to %s\n",
2819               (load ? "RUN" : "STOP"));
2820 
2821     if (cvptr->type == MAC && cvptr->state == Idle_State)   /* if this is a MAC controller, and it's idle */
2822         return SCPE_INCOMP;                                 /*   then the controller must be called to poll the drives */
2823     }                                                       /* otherwise indicate that the command is complete */
2824 
2825 return SCPE_OK;                                         /* return normal completion status to the caller */
2826 }
2827 
2828 
2829 /* Set the drive model.
2830 
2831    This validation routine is called to set the model of the disc drive
2832    associated with the specified unit.  The "value" parameter indicates the
2833    model ID, and the unit capacity is set to the size indicated.
2834 
2835 
2836    Implementation notes:
2837 
2838     1. If the drive is changed from a 7905 or 7906, which has separate head
2839        protect switches, to a 7920 or 7925, which has a single protect switch,
2840        ensure that both protect bits are set so that all heads are protected.
2841 */
2842 
dl_set_model(UNIT * uptr,int32 value,char * cptr,void * desc)2843 t_stat dl_set_model (UNIT *uptr, int32 value, char *cptr, void *desc)
2844 {
2845 if (uptr->flags & UNIT_ATT)                             /* if the unit is currently attached */
2846     return SCPE_ALATT;                                  /*   then the disc model cannot be changed */
2847 
2848 uptr->capac = drive_props [GET_MODEL (value)].words;    /* set the capacity to the new value */
2849 
2850 if (uptr->flags & UNIT_PROT                             /* if either protect bit is set */
2851   && (value == UNIT_7920 || value == UNIT_7925))        /*   and the new drive is a 7920 or 7925 */
2852     uptr->flags |= UNIT_PROT;                           /*     then ensure that both bits are set */
2853 
2854 return SCPE_OK;
2855 }
2856 
2857 
2858 /* Set or clear the write protection status.
2859 
2860    This validation routine is called to set the write protection status of the
2861    disc drive associated with the specified unit.  The "value" parameter
2862    indicates whether the drive is to be protected (1) or unprotected (0).
2863 
2864    In hardware, the 7920 and 7925 drives have a READ ONLY switch that write-
2865    protects all heads in the drive, and Read-Only status directly reflects the
2866    position of the switch.  The switch is simulated by the SET <unit> PROTECT
2867    and SET <unit> UNPROTECT commands.
2868 
2869    The 7905 and 7906 drives have separate PROTECT UPPER DISC and PROTECT LOWER
2870    DISC switches that protect heads 0-1 and 2 (7905) or 2-3 (7906),
2871    respectively, and Read-Only status reflects the position of the switch
2872    associated with the head currently addressed by the drive's Head Register.
2873    The Head Register is loaded by the controller as part of a Seek or Cold Load
2874    Read command, or during an auto-seek or spare track seek, if permitted by the
2875    file mask.  A Controller Preset command sent to a drive clears the Head
2876    Register, so Read-Only status reflects the PROTECT UPPER DISC switch setting.
2877 
2878    The SET <unit> PROTECT=(UPPER | LOWER) and SET <unit> UNPROTECT=(UPPER |
2879    LOWER) simulation commands are provided to protect or unprotect the upper or
2880    lower heads individually.  If the option values are omitted, e.g., SET <unit>
2881    PROTECT, then both upper and lower heads are (un)protected.
2882 */
2883 
dl_set_protect(UNIT * uptr,int32 value,char * cptr,void * desc)2884 t_stat dl_set_protect (UNIT *uptr, int32 value, char *cptr, void *desc)
2885 {
2886 const uint32 model = uptr->flags & UNIT_MODEL;
2887 char gbuf [CBUFSIZE];
2888 
2889 if (cptr == NULL)                                       /* if there are no arguments */
2890     if (value)                                          /*   then if setting the protection status */
2891         uptr->flags |= UNIT_PROT;                       /*     then protect all heads */
2892     else                                                /*   otherwise */
2893         uptr->flags &= ~UNIT_PROT;                      /*     unprotect all heads */
2894 
2895 else if (*cptr == '\0')                                 /* otherwise if the argument is empty */
2896     return SCPE_MISVAL;                                 /*   then reject the command */
2897 
2898 else if (model == UNIT_7920 || model == UNIT_7925)      /* otherwise if this is a 7920 or 7925 */
2899     return SCPE_ARG;                                    /*   then the heads cannot be protected separately */
2900 
2901 else {                                                  /* otherwise a 7905/06 argument is present */
2902     cptr = get_glyph (cptr, gbuf, ';');                 /* get the argument */
2903 
2904     if (strcmp ("LOWER", gbuf) == 0)                    /* if the LOWER option was specified */
2905         if (value)                                      /*   then if setting the protection status */
2906             uptr->flags |= UNIT_PROT_L;                 /*     then set the protect lower disc flag */
2907         else                                            /*   otherwise */
2908             uptr->flags &= ~UNIT_PROT_L;                 /*    clear the protect lower disc flag */
2909 
2910     else if (strcmp ("UPPER", gbuf) == 0)               /* otherwise if the UPPER option was specified */
2911         if (value)                                      /*   then if setting the protection status */
2912             uptr->flags |= UNIT_PROT_U;                 /*     then set the protect upper disc flag */
2913         else                                            /*   otherwise */
2914             uptr->flags &= ~UNIT_PROT_U;                /*    clear the protect upper disc flag */
2915 
2916     else                                                /* otherwise some other argument was given */
2917         return SCPE_ARG;                                /*   so report the error */
2918     }
2919 
2920 return SCPE_OK;
2921 }
2922 
2923 
2924 /* Show the write protection status.
2925 
2926    This display routine is called to show the write protection status of the
2927    disc drive associated with the specified unit.  The "value" and "desc"
2928    parameters are unused.
2929 
2930    The unit flags contain two bits that indicate write protection for heads 0-1
2931    and heads 2-n.  If both bits are clear, the drive is unprotected.  A 7905 or
2932    7906 drive may have one or the other or both bits set, indicating that the
2933    upper, lower, or both platters are protected.  A 7920 or 7925 will have both
2934    bits set, indicating that the entire drive is protected.
2935 */
2936 
dl_show_protect(FILE * st,UNIT * uptr,int32 value,void * desc)2937 t_stat dl_show_protect (FILE *st, UNIT *uptr, int32 value, void *desc)
2938 {
2939 const uint32 model = uptr->flags & UNIT_MODEL;
2940 
2941 if ((uptr->flags & UNIT_PROT) == 0)                     /* if the protection flags are clear */
2942     fputs ("unprotected", st);                          /*   then report the disc as unprotected */
2943 
2944 else if (model == UNIT_7905 || model == UNIT_7906)      /* otherwise if this is a 7905/06 */
2945     if ((uptr->flags & UNIT_PROT) == UNIT_PROT_L)       /*   then if only the lower disc protect flag is set */
2946         fputs ("lower protected", st);                  /*     then report it */
2947     else if ((uptr->flags & UNIT_PROT) == UNIT_PROT_U)  /*   otherwise if only the upper disc protect flag is set */
2948         fputs ("upper protected", st);                  /*     then report it */
2949     else                                                /*   otherwise both flags are set */
2950         fputs ("lower/upper protected", st);            /*     so report them */
2951 
2952 else                                                    /* otherwise it's a 7920/25 */
2953     fputs ("protected", st);                            /*   so either flag set indicates a protected disc */
2954 
2955 return SCPE_OK;
2956 }
2957 
2958 
2959 /* Set or clear the diagnostic override table.
2960 
2961    This validation routine is called to set or clear the diagnostic override
2962    table associated with the specified unit.  The "value" parameter is either
2963    the positive maximum table entry count if an entry is to be added, or zero if
2964    the table is to be cleared, and "desc" is a pointer to the controller.
2965 
2966    If the CPU interface declares a diagnostic override table, it will specify
2967    the table when initializing the controller variables structure with the
2968    CNTLR_INIT macro.  This sets the "dop_base" pointer in the structure to point
2969    at the table.  If the interface does not declare a table, the pointer will be
2970    NULL.
2971 
2972    If the table is present, new entries may be added with this command:
2973 
2974      SET <dev> DIAG=<cylinder>;<head>;<sector>;<opcode>;<spd>;<status>
2975 
2976    The cylinder, head, and sector values are entered as decimal numbers, the
2977    opcode and status values are entered as octal numbers, and the SPD value is
2978    specified as any combination of the letters "S", "P", or "D".
2979 
2980    If a command specifies the opcode value as Request Syndrome (15) and the
2981    status value as Correctable Data Error (17), then four additional values must
2982    be specified as part of the command line above:
2983 
2984       ;<displacement>;<syndrome 1>;<syndrome 2>;<syndrome 3>
2985 
2986    The displacement value is entered as a decimal number, and the three syndrome
2987    values are entered as octal numbers.
2988 
2989    Entering SET <dev> DIAG by itself resets the current entry pointer to the
2990    first table entry.  Entering SET <dev> NODIAG clears the table.
2991 
2992    If the override table was not declared by the CPU interface, the routine
2993    returns "Command not allowed."  If SET NODIAG was entered, the "value"
2994    parameter will be -1, and the table will be cleared by storing the special
2995    value DL_OVEND into the first table entry.  Otherwise, if SET DIAG is
2996    entered, the table pointer is reset.  However, if the table is already empty,
2997    the routine returns "Missing value" to indicate that the table must be
2998    populated first.
2999 
3000    If a new entry is to be added, the "value" parameter will indicate the size
3001    of the table in entries.  If no free entry exists, the routine returns
3002    "Memory exhausted".  Otherwise, the supplied parameters are parsed and
3003    entered into the table.  An array of maximum allowed values and radixes are
3004    used during parsing to validate each parameter.  The non-numeric SPD
3005    parameter is parsed separately.  If, after parsing the first six parameters,
3006    the opcode and status are Request Syndrome and Correctable Data Error,
3007    respectively, then four more parameters are sought.  These are stored into
3008    the following table entry.
3009 
3010 
3011    Implementation notes:
3012 
3013     1. Each maximum array element value limits the absolute value of its
3014        corresponding numeric parameter.  Negative values may be specified for
3015        unsigned values; no error is returned, and these simply will never match
3016        their intended controller values.
3017 
3018     2. Each radix array element value is used to parse its corresponding
3019        parameter.  A radix of 0 is used to indicate the S/P/D parameter, which
3020        is parsed alphabetically rather than numerically.
3021 
3022     3. One table entry is always reserved for the end-of-table value, so the
3023        number of configurable entries is one less than the defined table size.
3024 */
3025 
dl_set_diag(UNIT * uptr,int32 value,char * cptr,void * desc)3026 t_stat dl_set_diag (UNIT *uptr, int32 value, char *cptr, void *desc)
3027 {
3028 typedef struct {
3029     t_value  max;                               /* maximum allowed value */
3030     uint32   radix;                             /* numeric parsing radix */
3031     } PARSER_PROP;
3032 
3033 static const PARSER_PROP param [] = {
3034 /*    maximum value  radix */
3035 /*    -------------  ----- */
3036     {         822,     10  },                   /* cylinder */
3037     {           8,     10  },                   /* head */
3038     {          63,     10  },                   /* sector */
3039     { LAST_OPCODE,      8  },                   /* opcode */
3040     {           0,      0  },                   /* SPD */
3041     { LAST_STATUS,      8  },                   /* status */
3042     {         135,     10  },                   /* displacement */
3043     {    D16_UMAX,      8  },                   /* syndrome 1 */
3044     {    D16_UMAX,      8  },                   /* syndrome 2 */
3045     {    D16_UMAX,      8  }                    /* syndrome 3 */
3046     };
3047 
3048 const CVPTR cvptr = (CVPTR) desc;
3049 DIAG_ENTRY *entry;
3050 uint32 pidx, params [10];
3051 t_stat status;
3052 char gbuf [CBUFSIZE];
3053 
3054 if (cvptr->dop_base == NULL)                            /* if the override array is not present */
3055     return SCPE_NOFNC;                                  /*   then the command is not allowed */
3056 
3057 else if (value == 0)                                    /* otherwise if this is a NODIAG call */
3058     if (cptr != NULL)                                   /*   then if something follows the keyword */
3059         return SCPE_2MARG;                              /*     then report an error */
3060 
3061     else {                                              /* otherwise the command is valid */
3062         cvptr->dop_index = -1;                          /*   so clear the current entry pointer */
3063         cvptr->dop_base->cylinder = DL_OVEND;           /*     and mark the first entry as the end */
3064         }
3065 
3066 else if (cptr == NULL)                                  /* otherwise if DIAG is by itself */
3067     if (cvptr->dop_base->cylinder == DL_OVEND)          /*   then if there are no entries in the table */
3068         return SCPE_MISVAL;                             /*     then one must be entered first */
3069     else                                                /*   otherwise */
3070         cvptr->dop_index = 0;                           /*     reset the current pointer to the first entry */
3071 
3072 else if (*cptr == '\0')                                 /* otherwise if there are no parameters */
3073     return SCPE_MISVAL;                                 /*   then report a missing value */
3074 
3075 else {                                                  /* otherwise at least one parameter is present */
3076     for (entry = cvptr->dop_base;                       /* find the */
3077          entry->cylinder != DL_OVEND && value > 0;      /*   last entry */
3078          entry++, value--);                             /*     in the current table */
3079 
3080     if (value <= 1)                                     /* if there's not enough room to add a new entry */
3081         return SCPE_MEM;                                /*   then report the error to the user */
3082 
3083     else {                                              /* otherwise there's at least one free entry */
3084         for (pidx = 0; pidx < 10; pidx++) {             /*   so assume a full set of arguments are present */
3085             if (*cptr == '\0')                          /* if the next argument is not there */
3086                 return SCPE_2FARG;                      /*   then report it missing */
3087 
3088             if (param [pidx].radix == 0) {              /* if this is the SPD argument */
3089                 params [pidx] = 0;                      /*   then parse it specially */
3090 
3091                 while (*cptr != ';' && *cptr != '\0') { /* look for multiple arguments */
3092                     if (*cptr == 'S')                   /* if it's an S */
3093                         params [pidx] |= CM_SPARE;      /*   then set the spare bit */
3094                     else if (*cptr == 'P')              /* or if it's a P */
3095                         params [pidx] |= CM_PROTECTED;  /*   then set the protected bit */
3096                     else if (*cptr == 'D')              /* or if it's a D */
3097                         params [pidx] |= CM_DEFECTIVE;  /*   then set the defective bit */
3098                     else                                /* any other character */
3099                         return SCPE_ARG;                /*   results in an invalid argument error */
3100 
3101                     cptr++;                             /* point at the next character and continue */
3102                     }                                   /*   until a separator or terminator is seen */
3103 
3104                 if (*cptr == ';')                       /* if a separator was seen */
3105                     cptr++;                             /*   then move past it */
3106 
3107                 status = SCPE_OK;                       /* reassure the compiler that status is not uninitialized */
3108                 }
3109 
3110             else {                                      /* otherwise parse a numeric argument */
3111                 cptr = get_glyph (cptr, gbuf, ';');     /* get the argument */
3112 
3113                 if (gbuf [0] == '-') {                  /* if the argument is negative */
3114                     gbuf [0] = ' ';                     /*   then clear the sign */
3115                     params [pidx] =                     /*     and negate the resulting value */
3116                       (uint32) NEG16 (get_uint (gbuf, param [pidx].radix,
3117                                                 param [pidx].max, &status));
3118                     }
3119 
3120                 else                                    /* otherwise the argument is unsigned */
3121                     params [pidx] =                     /*   so use the value as is */
3122                       (uint32) get_uint (gbuf, param [pidx].radix,
3123                                          param [pidx].max, &status);
3124                 }
3125 
3126             if (status != SCPE_OK)                      /* if an error occurred */
3127                 return status;                          /*   then return the parsing status */
3128 
3129             if (pidx == 5                               /* if we have parsed the status */
3130               && (params [3] != Request_Syndrome        /*   and this is not a Request Syndrome entry */
3131               || params [5] != Correctable_Data_Error)) /*     with Correctable Data Error status */
3132                 break;                                  /*       then no more parameters are expected */
3133             }
3134 
3135         if (*cptr != '\0')                              /* if more characters are present */
3136             return SCPE_2MARG;                          /*   then report the excess */
3137 
3138         else if (pidx == 10 && value <= 2)              /* otherwise if we have syndrome values but no space */
3139             return SCPE_MEM;                            /*   the report that we can't store them */
3140 
3141         entry->cylinder = params [0];                   /* store the */
3142         entry->head     = params [1];                   /*   first set */
3143         entry->sector   = params [2];                   /*     of parameter values */
3144         entry->opcode   = (CNTLR_OPCODE) params [3];    /*       in the */
3145         entry->spd      = params [4];                   /*         first available */
3146         entry->status   = (CNTLR_STATUS) params [5];    /*            empty entry */
3147 
3148         if (pidx == 10) {                               /* if syndrome values were present */
3149             entry++;                                    /*   then store them in the next available entry */
3150 
3151             entry->spd      = params [6];               /* save the displacement */
3152             entry->cylinder = params [7];               /*   and the */
3153             entry->head     = params [8];               /*     three syndrome */
3154             entry->sector   = params [9];               /*       values */
3155             entry->opcode   = Request_Syndrome;         /* identify the entry */
3156             entry->status   = Correctable_Data_Error;   /*   by opcode and status */
3157             }
3158 
3159         entry++;                                        /* point at the next available entry */
3160         entry->cylinder = DL_OVEND;                     /*   and mark it as the end of the list */
3161 
3162         cvptr->dop_index = 0;                           /* reset the current pointer to the start of the list */
3163         }
3164     }
3165 
3166 return SCPE_OK;
3167 }
3168 
3169 
3170 /* Show the diagnostic override table.
3171 
3172    This display routine is called to show the contents of the diagnostic
3173    override table.  The "value" parameter is either the positive maximum table
3174    entry count if the routine was invoked by a SHOW <dev> DIAG command, or -1 if
3175    the routine was invoked by a SHOW <dev> command.  The "desc" parameter is a
3176    pointer to the controller.
3177 
3178    If the override table was not declared by the CPU interface, the routine
3179    returns "Command not allowed."  Otherwise, if the table is empty, the routine
3180    prints "override disabled".  If the table is populated, then the routine
3181    prints "override enabled" if it was invoked as part of a general SHOW for the
3182    device, or it prints the individual table entries if it was invoked as SHOW
3183    <dev> DIAG.
3184 
3185    Entries are printed in tabular form with the columns corresponding to the SET
3186    DIAG parameters, except that the opcode and status fields are decoded.  A
3187    Request Syndrome command entry with Correctable Data Error status is followed
3188    by an indented second line containing the displacement and syndrome values.
3189    Numeric values are printed in the same radix as is used to enter them.
3190 
3191 
3192    Implementation notes:
3193 
3194     1. The Request Syndrome displacement parameter is a 16-bit signed value
3195        contained in a 32-bit unsigned array element.  To print it properly, we
3196        convert the latter to a 16-bit signed value and then sign-extend to "int"
3197        size for fprintf.
3198 
3199     2. The explicit use of "const CNTLR_VARS *" is necessary to declare a
3200        pointer to a constant structure.  Using "const CVPTR" declares a constant
3201        pointer instead.
3202 */
3203 
dl_show_diag(FILE * st,UNIT * uptr,int32 value,void * desc)3204 t_stat dl_show_diag (FILE *st, UNIT *uptr, int32 value, void *desc)
3205 {
3206 const CNTLR_VARS *cvptr = (const CNTLR_VARS *) desc;    /* the controller pointer is supplied */
3207 DIAG_ENTRY *entry;
3208 
3209 if (cvptr->dop_base == NULL)                            /* if the table isn't defined */
3210     return SCPE_NOFNC;                                  /*   then the command is illegal */
3211 
3212 else if (cvptr->dop_index < 0) {                        /* otherwise if overrides are currently disabled */
3213     fputs ("override disabled", st);                    /*   then report it */
3214 
3215     if (value > 0)                                      /* if we were invoked by a SHOW DIAG command */
3216         fputc ('\n', st);                               /*   then we must add the line terminator */
3217     }
3218 
3219 else if (value < 0)                                     /* otherwise if we were invoked by a SHOW <dev> command */
3220     fputs ("override enabled", st);                     /*   then print the table status instead of the details */
3221 
3222 else for (entry = cvptr->dop_base;                      /* otherwise print each table entry */
3223           entry->cylinder != DL_OVEND && value > 0;     /*   until the end-of-table marker or count exhaustion */
3224           entry++, value--) {
3225     fprintf (st, "%3d  %1d  %2d  %*s  %c%c%c  %*s\n",   /* print the entry */
3226              entry->cylinder, entry->head, entry->sector,
3227              - OPCODE_LENGTH, dl_opcode_name (cvptr->type, entry->opcode),
3228              (entry->spd & CM_SPARE     ? 'S' : ' '),
3229              (entry->spd & CM_PROTECTED ? 'P' : ' '),
3230              (entry->spd & CM_DEFECTIVE ? 'D' : ' '),
3231              - STATUS_LENGTH, dl_status_name (entry->status));
3232 
3233     if (entry->opcode == Request_Syndrome               /* if the current entry is a syndrome request */
3234       && entry->status == Correctable_Data_Error) {     /*   for a correctable data error */
3235         entry++;                                        /*     then the next entry contains the values */
3236         value = value - 1;                              /* drop the entry count to account for it */
3237 
3238         fprintf (st, "            %3d  %06o  %06o  %06o\n", /* print the displacement and syndrome values */
3239                  (int) INT16 (entry->spd),
3240                  entry->cylinder, entry->head, entry->sector);
3241         }
3242     }
3243 
3244 return SCPE_OK;
3245 }
3246 
3247 
3248 /* Set the controller timing mode.
3249 
3250    This validation routine is called to set the timing mode for the disc
3251    subsystem.  As this is an extended MTAB call, the "uptr" parameter points to
3252    the unit array of the device.  The "value" parameter is set non-zero to use
3253    realistic timing and 0 to use fast timing.  For a MAC controller, the "desc"
3254    parameter is a pointer to the controller.  For ICD controllers, the "desc"
3255    parameter is a pointer to the first element of the controller array.  There
3256    must be one controller for each unit defined by the device associated with
3257    the controllers.  The "cptr" parameter is not used.
3258 
3259    If fast timing is selected, the controller's timing pointer is set to the
3260    fast timing pointer supplied by the interface when the controller was
3261    initialized.  If real timing is selected, the table of real times is searched
3262    for an entry whose controller type matches the supplied controller.  MAC and
3263    ICD controllers support several drive models with identical timing
3264    characteristics.  However, CS/80 controllers allow mixing drives with
3265    different timing on a single CPU interface.  For these, the drive type must
3266    match as well.  If a match is found, the controller's timing pointer is set
3267    to the associated real-time entry.  Otherwise, the routine returns SCPE_IERR.
3268 
3269    Non-MAC controllers are dedicated per-drive, so "desc" points not at a single
3270    controller instance but at an array of controller instances.  The timing mode
3271    is common to every controller in the array.
3272 */
3273 
dl_set_timing(UNIT * uptr,int32 value,char * cptr,void * desc)3274 t_stat dl_set_timing (UNIT *uptr, int32 value, char *cptr, void *desc)
3275 {
3276 CVPTR  cvptr = (CVPTR) desc;                            /* the controller pointer is supplied */
3277 const  DELAY_PROPS *dpptr;
3278 DRIVE_TYPE model;
3279 uint32 delay, cntlr_count;
3280 
3281 if (cvptr->type == MAC)                                 /* if this is a MAC controller */
3282     cntlr_count = 1;                                    /*   then there is one controller for all units */
3283 else                                                    /* otherwise */
3284     cntlr_count = cvptr->device->numunits;              /*   there is one controller per unit */
3285 
3286 while (cntlr_count--) {                                 /* set each controller's timing mode */
3287     if (value) {                                        /* if realistic timing is requested */
3288         model = GET_MODEL (uptr->flags);                /*   then get the drive model from the current unit */
3289         dpptr = real_times;                             /*     and reset the real-time delay table pointer */
3290 
3291         for (delay = 0; delay < DELAY_COUNT; delay++)   /* search for the correct set of times */
3292             if (dpptr->type == cvptr->type              /* if the controller types match */
3293               && (dpptr->drive == HP_All                /*   and all drive times are the same */
3294               || dpptr->drive == model)) {              /*     or the drive types match as well */
3295                 cvptr->dlyptr = dpptr;                  /*       then use this set of times */
3296                 break;
3297                 }
3298             else                                        /* otherwise */
3299                 dpptr++;                                /*   point at the next array element */
3300 
3301         if (delay == DELAY_COUNT)                       /* if the model was not found in the table */
3302             return SCPE_IERR;                           /*   then report an internal (impossible) error */
3303         else                                            /* otherwise */
3304             cvptr->device->flags |= DEV_REALTIME;       /*   set the real time flag */
3305         }
3306 
3307     else {                                              /* otherwise fast timing is requested */
3308         cvptr->device->flags &= ~DEV_REALTIME;          /*   so clear the real time flag */
3309         cvptr->dlyptr = cvptr->fastptr;                 /*     and set the delays to the FASTTIME settings */
3310         }
3311 
3312     cvptr++;                                            /* point at the next controller */
3313     uptr++;                                             /*   and corresponding unit for non-MAC controllers */
3314     }
3315 
3316 return SCPE_OK;
3317 }
3318 
3319 
3320 /* Show the controller timing mode
3321 
3322    This display routine is called to show the timing mode for the disc
3323    subsystem.  The "value" parameter is unused; the "desc" parameter is a
3324    pointer to the controller.
3325 
3326 
3327    Implementation notes:
3328 
3329     1. The explicit use of "const CNTLR_VARS *" is necessary to declare a
3330        pointer to a constant structure.  Using "const CVPTR" declares a constant
3331        pointer instead.
3332 */
3333 
dl_show_timing(FILE * st,UNIT * uptr,int32 value,void * desc)3334 t_stat dl_show_timing (FILE *st, UNIT *uptr, int32 value, void *desc)
3335 {
3336 const CNTLR_VARS *cvptr = (const CNTLR_VARS *) desc;    /* the controller pointer is supplied */
3337 
3338 if (cvptr->device->flags & DEV_REALTIME)                /* if the real time flag is set */
3339     fputs ("realistic timing", st);                     /*   then we're using realistic timing */
3340 else                                                    /* otherwise */
3341     fputs ("fast timing", st);                          /*   we're using optimized timing */
3342 
3343 return SCPE_OK;
3344 }
3345 
3346 
3347 
3348 /* Disc library local controller routines */
3349 
3350 
3351 /* Start or stop the command/parameter wait timer.
3352 
3353    A MAC controller uses a 1.74 second timer to ensure that it does not wait
3354    forever for a non-responding disc drive or CPU interface.  In simulation, MAC
3355    interfaces supply an additional controller unit that is activated when the
3356    command or parameter wait timer is started and cancelled when the timer is
3357    stopped.
3358 
3359    ICD interfaces do not use the wait timer or supply an additional unit.
3360 
3361 
3362    Implementation notes:
3363 
3364     1. Absolute activation is used because the timer is restarted between
3365        parameter word transfers.
3366 */
3367 
wait_timer(CVPTR cvptr,FLIP_FLOP action)3368 static void wait_timer (CVPTR cvptr, FLIP_FLOP action)
3369 {
3370 if (cvptr->type == MAC)                                 /* if this a MAC controller */
3371     if (action == SET)                                  /*  then if the timer is to be set */
3372         sim_activate_abs (CNTLR_UPTR, CNTLR_TIMEOUT);   /*    then activate the controller unit */
3373 
3374     else {                                              /*  otherwise the timer is to be stopped */
3375         sim_cancel (CNTLR_UPTR);                        /*    so cancel the unit */
3376         CNTLR_UPTR->PHASE = Idle_Phase;                 /*      and idle the controller unit */
3377         }
3378 return;
3379 }
3380 
3381 
3382 /* Idle the controller.
3383 
3384    The command wait timer is turned off, the status is reset, and the controller
3385    is returned to the idle state (Poll Loop).
3386 */
3387 
idle_controller(CVPTR cvptr)3388 static void idle_controller (CVPTR cvptr)
3389 {
3390 wait_timer (cvptr, CLEAR);                              /* stop the command wait timer */
3391 
3392 cvptr->status = Normal_Completion;                      /* the Poll Loop clears the status */
3393 cvptr->state  = Idle_State;                             /* idle the controller */
3394 return;
3395 }
3396 
3397 
3398 /* End the current command.
3399 
3400    The currently executing command is completed with the supplied status.  If
3401    the command completed normally, and it returns to the Poll Loop, the
3402    controller is idled, and the wait timer is cancelled.  Otherwise, the
3403    controller enters the Wait Loop, and the wait timer is started.  If the
3404    command had accessed a drive unit, the unit is idled.  Also, for a MAC
3405    controller, the controller unit is idled as well.
3406 */
3407 
end_command(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)3408 static void end_command (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
3409 {
3410 cvptr->status = status;                                 /* set the command result status */
3411 
3412 if (status == Normal_Completion                         /* if the command completed normally */
3413   && cmd_props [cvptr->opcode].idle_at_end) {           /*   and this command idles the controller */
3414     cvptr->state = Idle_State;                          /*     then set idle status */
3415     wait_timer (cvptr, CLEAR);                          /*       and stop the command wait timer */
3416     }
3417 
3418 else {                                                  /* otherwise */
3419     cvptr->state = Wait_State;                          /*   the controller waits for a new command */
3420     wait_timer (cvptr, SET);                            /*     so start the command wait timer */
3421 
3422     if (uptr)                                           /* if the command accessed a drive */
3423         uptr->PHASE = Idle_Phase;                       /*   then idle it */
3424 
3425     if (cvptr->type == MAC)                             /* if this is a MAC controller */
3426         CNTLR_UPTR->PHASE = Idle_Phase;                 /*   then idle the controller unit as well */
3427     }
3428 
3429 if (cmd_props [cvptr->opcode].transfer_size > 0)
3430     tpprintf (cvptr->device, DL_DEB_CMD, (cvptr->opcode == Initialize
3431                                             ? "Unit %u Initialize %s for %u words (%u sector%s)\n"
3432                                             : "Unit %u %s for %u words (%u sector%s)\n"),
3433               CM_UNIT (cvptr->spd_unit),
3434               (cvptr->opcode == Initialize
3435                  ? fmt_bitset (cvptr->spd_unit, initialize_format)
3436                  : opcode_name [cvptr->opcode]),
3437               cvptr->count,
3438               cvptr->count / cmd_props [cvptr->opcode].transfer_size + (cvptr->length > 0),
3439               (cvptr->count <= cmd_props [cvptr->opcode].transfer_size ? "" : "s"));
3440 
3441 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command completed with %s status\n",
3442           CM_UNIT (cvptr->spd_unit), opcode_name [cvptr->opcode],
3443           dl_status_name (cvptr->status));
3444 
3445 return;
3446 }
3447 
3448 
3449 /* Start a read operation on the current sector.
3450 
3451    This routine is called at the end of the rotate phase to begin a read
3452    operation.  The current sector given by the controller address is read from
3453    the disc image file into the sector buffer in preparation for data transfer
3454    to the CPU.  If the end of the track had been reached, and the file mask
3455    permits, an auto-seek is scheduled instead to allow the read to continue.
3456    The routine returns TRUE if the data is ready to be transferred and FALSE if
3457    it is not (due to command completion, an error, or an auto-seek that must
3458    complete first).
3459 
3460    On entry, the end-of-data flag is checked.  If it is set, the current read
3461    command is completed.  Otherwise, the buffer data offset and verify options
3462    are set up.  For a Read Full Sector, the sync word is set from the controller
3463    type, and dummy cylinder and head-sector words are generated from the current
3464    location (as would be the case in the absence of track sparing).
3465 
3466    The image file is positioned to the correct sector in preparation for
3467    reading.  If the positioning requires a permitted seek, it is scheduled, and
3468    the routine returns with the Seek_Phase set to wait for seek completion
3469    before resuming the read (when the seek completes, the service routine will
3470    be entered, and we will be called again; this time, the end-of-cylinder flag
3471    will be clear and positioning will succeed).  If positioning resulted in an
3472    error, the current read is terminated with the error status set.
3473 
3474    If positioning succeeded within the same track, the sector image is read into
3475    the buffer at an offset determined by the operation (Read Full Sector leaves
3476    room at the start of the buffer for the sector header).  If the image read
3477    failed with a host file system error, it is reported to the simulation
3478    console and the read ends with an Uncorrectable Data Error.  If it succeeded
3479    but did not return a full sector, the remainder of the buffer is padded with
3480    zeros.
3481 
3482    If the image was read correctly, the operation phase is set for the data
3483    transfer, the index of the first word to transfer is set, and the routine
3484    returns TRUE to begin the data transfer.
3485 
3486 
3487    Implementation notes:
3488 
3489     1. This routine changes the unit phase state as follows:
3490 
3491          Rotate_Phase => Idle_Phase if EOD or error (returns FALSE)
3492          Rotate_Phase => Seek_Phase if auto-seek (returns FALSE)
3493          Rotate_Phase => Data_Phase otherwise (returns TRUE)
3494 
3495     2. The position_sector routine sets up the data phase if it succeeds or the
3496        seek phase if a seek is required.
3497 */
3498 
start_read(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3499 static t_bool start_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3500 {
3501 uint32 count, offset;
3502 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3503 
3504 if (flags & EOD) {                                      /* if the end of data is indicated */
3505     end_command (cvptr, uptr, Normal_Completion);       /*   then complete the command */
3506     return FALSE;                                       /*     and end the current operation */
3507     }
3508 
3509 if (opcode == Read_Full_Sector) {                       /* if we are starting a Read Full Sector command */
3510     if (cvptr->type == MAC)                             /*   then if this is a MAC controller */
3511         cvptr->buffer [0] = 0100376;                    /*     indicate that ECC support is valid */
3512     else                                                /*   otherwise */
3513         cvptr->buffer [0] = 0100377;                    /*     indicate that ECC support is not available */
3514 
3515     set_address (cvptr, 1);                             /* set the current address into buffer words 1-2 */
3516     offset = 3;                                         /*   and start the data after the header */
3517     }
3518 
3519 else                                                    /* otherwise it's a normal read command */
3520     offset = 0;                                         /*   so data starts at the beginning of the buffer */
3521 
3522 if (position_sector (cvptr, uptr) == FALSE)             /* position the sector; if it was not */
3523     return FALSE;                                       /*   then a seek is in progress or an error occurred */
3524 
3525 tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s from cylinder %u head %u sector %u\n",
3526           (int32) (uptr - cvptr->device->units), opcode_name [opcode],
3527           uptr->CYL, cvptr->head, cvptr->sector);
3528 
3529 count = sim_fread (cvptr->buffer + offset,              /* read the sector from the image */
3530                    sizeof (DL_BUFFER),                  /*   into the sector buffer */
3531                    WORDS_PER_SECTOR, uptr->fileref);
3532 
3533 if (ferror (uptr->fileref)) {                           /* if a host file system error occurred */
3534     io_error (cvptr, uptr, Uncorrectable_Data_Error);   /*   then report it to the simulation console */
3535     return FALSE;                                       /*     and terminate with Uncorrectable Data Error status */
3536     }
3537 
3538 cvptr->length = cmd_props [opcode].transfer_size;       /* set the appropriate transfer length */
3539 cvptr->index = 0;                                       /*   and reset the data index */
3540 
3541 for (count = count + offset; count < cvptr->length; count++)    /* pad the sector as needed */
3542     cvptr->buffer [count] = 0;                                  /*   e.g., if reading from a new file */
3543 
3544 return TRUE;                                            /* the read was successfully started */
3545 }
3546 
3547 
3548 /* Finish a read operation on the current sector.
3549 
3550    This routine is called at the end of the intersector phase to finish a read
3551    operation.  Command termination conditions are checked, and the next sector
3552    is addressed in preparation for the read to continue.
3553 
3554    On entry, the diagnostic override status is checked.  If it is set, then the
3555    read is terminated with the indicated status.  Otherwise, the data overrun
3556    flag is checked.  If it is set, the read is terminated with an error.
3557    Otherwise, the next sector is addressed.
3558 
3559    If the end-of-data flag is set, the current read is completed.  Otherwise,the
3560    rotate phase is set up in preparation for the next sector read.
3561 
3562 
3563    Implementation notes:
3564 
3565     1. This routine changes the unit phase state as follows:
3566 
3567          Intersector_Phase => Idle_Phase if EOD or error
3568          Intersector_Phase => Rotate_Phase otherwise
3569 
3570     2. The HP 1000 CPU indicates the end of a read data transfer to an ICD
3571        controller by untalking the drive.  The untalk is done by the driver as
3572        soon as the DCPC completion interrupt is processed.  However, the time
3573        from the final DCPC transfer through driver entry to the point where the
3574        untalk is asserted on the bus varies from 80 instructions (RTE-6/VM with
3575        OS microcode and the buffer in the system map) to 152 instructions
3576        (RTE-IVB with the buffer in the user map).  The untalk must occur before
3577        the start of the next sector, or the drive will begin the data transfer.
3578 
3579        Normally, this is not a problem, as the driver clears the FIFO of any
3580        received data after DCPC completion.  However, if the read terminates
3581        after the last sector of a track, and accessing the next sector would
3582        require an intervening seek, and the file mask disables auto-seeking or
3583        an enabled seek would move the positioner beyond the drive limits, then
3584        the controller will indicate an End of Cylinder error if the untalk does
3585        not arrive before the seek is initiated.
3586 
3587        The RTE driver (DVA32) and various utilities that manage the disc
3588        directly (e.g., SWTCH) do not appear to account for these bogus errors,
3589        so the ICD controller hardware must avoid them in some unknown manner.
3590        We work around the issue by extending the intersector delay to allow time
3591        for a potential untalk whenever the next access would otherwise fail.
3592 
3593        Note that this issue does not occur with writes because DCPC completion
3594        asserts EOI concurrently with the final data byte to terminate the
3595        command explicitly.
3596 
3597        Note also that the delay is a fixed number of instructions, regardless of
3598        timing mode, to ensure that the CPU makes it through the driver code to
3599        output the untalk command.
3600 */
3601 
end_read(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3602 static void end_read (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3603 {
3604 uint32 bound;
3605 
3606 if (cvptr->status != Normal_Completion)                 /* if a diagnostic override is present */
3607     end_command (cvptr, uptr, cvptr->status);           /*   then report the indicated status */
3608 
3609 else if (flags & OVRUN)                                 /* otherwise if a read overrun occurred */
3610     end_command (cvptr, uptr, Data_Overrun);            /*   then terminate the command with an error */
3611 
3612 else {                                                  /* otherwise the read succeeded */
3613     next_sector (cvptr, uptr);                          /*   so address the next sector */
3614 
3615     if (flags & EOD)                                    /* if the end of data is indicated */
3616         end_command (cvptr, uptr, Normal_Completion);   /*   then complete the command */
3617 
3618     else {                                              /* otherwise reading continues */
3619         uptr->PHASE = Rotate_Phase;                     /*   so set up the unit for the rotate phase */
3620         uptr->wait = cvptr->dlyptr->intersector_gap;    /*     with a delay for the intersector time */
3621 
3622         if (cvptr->eoc == SET && cvptr->type == ICD) {      /* if a seek will be required on an ICD controller */
3623             if ((cvptr->file_mask & CM_AUTO_SEEK_EN) == 0)  /*   then if auto-seek is disabled */
3624                 bound = cvptr->cylinder;                    /*     then the bound is the current cylinder */
3625             else if (cvptr->file_mask & CM_DECR_SEEK)       /*   otherwise if a decremental seek is enabled */
3626                 bound = 0;                                  /*     then the bound is cylinder 0 */
3627             else                                            /*   otherwise the enabled bound is the last cylinder */
3628                 bound = drive_props [GET_MODEL (uptr->flags)].cylinders - 1;
3629 
3630             if (cvptr->cylinder == bound)               /* if the positioner is already at the bound */
3631                 uptr->wait = UNTALK_DELAY;              /*   then the seek will fail; delay to allow CPU to untalk */
3632             }
3633         }
3634     }
3635 
3636 return;
3637 }
3638 
3639 
3640 /* Start a write operation on the current sector.
3641 
3642    This routine is called at the end of the rotate phase to begin a write
3643    operation.  The current sector indicated by the controller address is
3644    positioned for writing from the sector buffer to the disc image file after
3645    data transfer from the CPU.  If the end of the track had been reached, and
3646    the file mask permits, an auto-seek is scheduled instead to allow the write
3647    to continue.   The routine returns TRUE if the data is ready to be
3648    transferred and FALSE if it is not (due to an error or an auto-seek that must
3649    complete first).
3650 
3651    On entry, if writing is not permitted, or formatting is required but not
3652    enabled, the command is terminated with an error.  Otherwise, the disc image
3653    file is positioned to the correct sector in preparation for writing.
3654 
3655    If the positioning requires a permitted seek, it is scheduled, and the
3656    routine returns with the Seek_Phase set to wait for seek completion before
3657    resuming the write (when the seek completes, the service routine will be
3658    entered, and we will be called again; this time, the end-of-cylinder flag
3659    will be clear and positioning will succeed).  If positioning resulted in an
3660    error, the current write is terminated with the error status set.
3661 
3662    If positioning succeeded within the same track, the operation phase is set
3663    for the data transfer, the index of the first word to transfer is set, and
3664    the routine returns TRUE to begin the data transfer.
3665 
3666 
3667    Implementation notes:
3668 
3669     1. This routine changes the unit phase state as follows:
3670 
3671          Rotate_Phase => Idle_Phase if write protected or error (returns FALSE)
3672          Rotate_Phase => Seek_Phase if auto-seek (returns FALSE)
3673          Rotate_Phase => Data_Phase otherwise (returns TRUE)
3674 
3675     2. The position_sector routine sets up the data phase if it succeeds or the
3676        seek phase if a seek is required.
3677 */
3678 
start_write(CVPTR cvptr,UNIT * uptr)3679 static t_bool start_write (CVPTR cvptr, UNIT *uptr)
3680 {
3681 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3682 
3683 if (opcode == Write                                     /* if this is a Write command */
3684   && cvptr->spd_unit & CM_PROTECTED                     /*   and the track is protected */
3685   && (uptr->flags & UNIT_FMT) == 0)                     /*     but the FORMAT switch is not set */
3686     end_command (cvptr, uptr, Protected_Track);         /*       then fail with a protection error */
3687 
3688 else if (uptr->STATUS & S2_READ_ONLY                    /* otherwise if the unit is write protected */
3689   || opcode != Write && (uptr->flags & UNIT_FMT) == 0)  /*   or the FORMAT switch must be set but is not */
3690     end_command (cvptr, uptr, Status_2_Error);          /*     then fail with a status error */
3691 
3692 else if (position_sector (cvptr, uptr) == TRUE) {       /* otherwise if positioning the sector succeeded */
3693     cvptr->length = cmd_props [opcode].transfer_size;   /*   then set the appropriate transfer length */
3694     cvptr->index = 0;                                   /*     and reset the data index */
3695 
3696     tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s to cylinder %u head %u sector %u\n",
3697               (int32) (uptr - cvptr->device->units), opcode_name [opcode],
3698               uptr->CYL, cvptr->head, cvptr->sector);
3699 
3700     return TRUE;                                        /* the write was successfully started */
3701     }
3702 
3703 return FALSE;                                           /* otherwise an error occurred or a seek is required */
3704 }
3705 
3706 
3707 /* Finish a write operation on the current sector.
3708 
3709    This routine is called at the end of the intersector phase to finish a write
3710    operation.  The current sector is written from the sector buffer to the disc
3711    image file at the current file position.  The next sector address is then
3712    updated to allow writing to continue.
3713 
3714    On entry, the drive is checked to ensure that it is ready for the write.
3715    Then the sector buffer is padded appropriately if a full sector of data was
3716    not transferred.  The buffer is written to the disc image file at the
3717    position corresponding to the controller address as set when the sector was
3718    started.  The write begins at a buffer offset determined by the command (a
3719    Write Full Sector has three header words at the start of the buffer that are
3720    not written to the disc image).
3721 
3722    If the image write failed with a host file system error, it is reported to
3723    the simulation console and the write ends with an Uncorrectable Data Error.
3724    If it succeeded, the diagnostic override status is checked.  If it is set,
3725    then the write is terminated with the indicated status.  Otherwise, the data
3726    overrun flag is checked.  If it is set, the write is terminated with an
3727    error.  Otherwise, the next sector is addressed.  If the end-of-data flag is
3728    set, the current write is completed.  Otherwise,the rotate phase is set up in
3729    preparation for the next sector write.
3730 
3731 
3732    Implementation notes:
3733 
3734     1. This routine changes the unit phase state as follows:
3735 
3736          Intersector_Phase => Idle_Phase if EOD or error
3737          Intersector_Phase => Rotate_Phase otherwise
3738 
3739     2. A partial sector is filled either with octal 177777 words (ICD) or copies
3740        of the last word (MAC), per page 7-10 of the ICD/MAC Disc Diagnostic
3741        manual.
3742 */
3743 
end_write(CVPTR cvptr,UNIT * uptr,CNTLR_FLAG_SET flags)3744 static void end_write (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags)
3745 {
3746 uint32 count;
3747 DL_BUFFER pad;
3748 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE;
3749 const uint32 offset = (opcode == Write_Full_Sector ? 3 : 0);
3750 
3751 if (uptr->flags & UNIT_UNLOAD) {                        /* if the drive is not ready */
3752     end_command (cvptr, uptr, Access_Not_Ready);        /*   then terminate the command */
3753     return;                                             /*     with an access error */
3754     }
3755 
3756 if (cvptr->index < WORDS_PER_SECTOR + offset) {         /* if a partial sector was transferred */
3757     if (cvptr->type == ICD)                             /*   then an ICD controller */
3758         pad = D16_UMAX;                                 /*     pads the sector with -1 words */
3759     else                                                /*   whereas a MAC controller */
3760         pad = cvptr->buffer [cvptr->index - 1];         /*     pads with the last word written */
3761 
3762     for (count = cvptr->index; count < WORDS_PER_SECTOR + offset; count++)
3763         cvptr->buffer [count] = pad;                    /* pad the sector buffer as needed */
3764     }
3765 
3766 sim_fwrite (cvptr->buffer + offset, sizeof (DL_BUFFER), /* write the sector to the file */
3767             WORDS_PER_SECTOR, uptr->fileref);
3768 
3769 if (ferror (uptr->fileref))                             /* if a host file system error occurred, then report it */
3770     io_error (cvptr, uptr, Uncorrectable_Data_Error);   /*    and terminate with Uncorrectable Data Error status */
3771 
3772 else if (cvptr->status != Normal_Completion)            /* otherwise if a diagnostic override is present */
3773     end_command (cvptr, uptr, cvptr->status);           /*   then report the indicated status */
3774 
3775 else if (flags & OVRUN)                                 /* otherwise if a write overrun occurred */
3776     end_command (cvptr, uptr, Data_Overrun);            /*   then terminate the command with an error */
3777 
3778 else {                                                  /* otherwise the write succeeded */
3779     next_sector (cvptr, uptr);                          /*   so address the next sector */
3780 
3781     if (flags & EOD)                                    /* if the end of data is indicated */
3782         end_command (cvptr, uptr, Normal_Completion);   /*   then complete the command */
3783 
3784     else {                                              /* otherwise writing continues */
3785         uptr->PHASE = Rotate_Phase;                     /*   so set up the unit for the rotate phase */
3786         uptr->wait = cvptr->dlyptr->intersector_gap;    /*     with a delay for the intersector time */
3787         }
3788     }
3789 
3790 return;
3791 }
3792 
3793 
3794 /* Position the disc image file at the current sector.
3795 
3796    The image file is positioned at the byte address corresponding to the drive's
3797    current cylinder and the controller's current head and sector addresses.
3798    Positioning may involve an auto-seek if a prior read or write addressed the
3799    final sector of a cylinder.  If a seek is initiated or an error is detected,
3800    the routine returns FALSE to indicate that the positioning was not performed.
3801    If the file was positioned, the routine returns TRUE.
3802 
3803    On entry, the diagnostic override status is checked.  If it is set to
3804    anything other than a data error, then positioning is terminated with the
3805    indicated status to simulate an address verification failure.  Otherwise, if
3806    the controller's end-of-cylinder flag is set, a prior read or write addressed
3807    the final sector in the current cylinder.  If the file mask does not permit
3808    auto-seeking, the command is terminated with an End of Cylinder error.
3809    Otherwise, the cylinder is incremented or decremented as directed by the file
3810    mask, and a seek to the new cylinder is started.
3811 
3812    If the increment or decrement resulted in an out-of-bounds value, the seek
3813    will return Seek Check status, and the command is terminated with an error.
3814    Otherwise, the seek is legal, and the routine returns with the seek phase set
3815    to wait for seek completion before resuming the current read or write.  When
3816    the seek completes, the service routine will be entered, and we will be
3817    called again; this time, the end-of-cylinder flag will be clear and the read
3818    or write will continue on the new cylinder.
3819 
3820    If the EOC flag was not set, the drive's position is checked against the
3821    controller's position if address verification is requested.  If they are
3822    different, as may occur with an Address Record command that specified a
3823    different location than the last Seek command, a seek is started to the
3824    correct cylinder, and the routine returns with the unit set to the seek phase
3825    to wait for seek completion as above.
3826 
3827    If the drive and controller positions agree or address verification is not
3828    requested, the CHS addresses are validated against the drive limits.  If they
3829    are invalid, Seek Check status is set, and the command is terminated with an
3830    error.
3831 
3832    If the addresses are valid, the drive is checked to ensure that it is ready
3833    for positioning.  If it is, the file is positioned to a byte offset in the
3834    image file that is calculated from the CHS address.  If positioning succeeds,
3835    the data phase is set up to begin the data transfer, and the routine returns
3836    TRUE to indicate that the file position is set.  If positioning fails with a
3837    host file system error, it is reported to the simulation console, and the
3838    routine returns FALSE to indicate that an AGC (drive positioner) fault
3839    occurred.
3840 
3841 
3842    Implementation notes:
3843 
3844     1. The ICD controller returns an End of Cylinder error if an auto-seek
3845        results in a position beyond the drive limits.  The MAC controller
3846        returns a Status-2 error.  Both controllers set the Seek Check bit in the
3847        drive status word.
3848 */
3849 
position_sector(CVPTR cvptr,UNIT * uptr)3850 static t_bool position_sector (CVPTR cvptr, UNIT *uptr)
3851 {
3852 const DRIVE_TYPE model = GET_MODEL (uptr->flags);           /* get the drive model */
3853 
3854 if (cvptr->status != Normal_Completion                      /* if a diagnostic override is present */
3855   && cvptr->status != Uncorrectable_Data_Error              /*   and it's not */
3856   && cvptr->status != Correctable_Data_Error)               /*     a data error */
3857     end_command (cvptr, uptr, cvptr->status);               /*       then report it */
3858 
3859 else if (cvptr->eoc == SET)                                     /* otherwise if we are at the end of a cylinder */
3860     if (cvptr->file_mask & CM_AUTO_SEEK_EN) {                   /*   then if an auto-seek is allowed */
3861         if (cvptr->file_mask & CM_DECR_SEEK)                    /*     then if a decremental seek is requested */
3862             cvptr->cylinder = cvptr->cylinder - 1 & D16_MASK;   /*       then decrease the address with wraparound */
3863         else                                                    /*     otherwise an incremental seek is requested */
3864             cvptr->cylinder = cvptr->cylinder + 1 & D16_MASK;   /*       so increase the address with wraparound */
3865 
3866         start_seek (cvptr, uptr);                               /* start the auto-seek */
3867 
3868         tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s autoseek to cylinder %u head %u sector %u\n",
3869                   (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE],
3870                   (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""),
3871                   cvptr->cylinder, cvptr->head, cvptr->sector);
3872 
3873         if (uptr->STATUS & S2_SEEK_CHECK)                   /* if a seek check occurred */
3874             if (cvptr->type == ICD)                         /*   then if this is an ICD controller */
3875                 end_command (cvptr, uptr, End_of_Cylinder); /*     then report it as an End of Cylinder error */
3876             else                                            /*   otherwise */
3877                 end_command (cvptr, uptr, Status_2_Error);  /*     report it as a Status-2 error */
3878         }
3879 
3880     else                                                    /* otherwise the file mask does not permit an auto-seek */
3881         end_command (cvptr, uptr, End_of_Cylinder);         /*   so terminate with an EOC error */
3882 
3883 else if (cvptr->verify                                      /* if address verification is enabled */
3884   && (uint32) uptr->CYL != cvptr->cylinder) {               /*   and the positioner is on the wrong cylinder */
3885     start_seek (cvptr, uptr);                               /*     then start a seek to the correct cylinder */
3886 
3887     tpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s reseek to cylinder %u head %u sector %u\n",
3888               (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE],
3889               (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""),
3890               cvptr->cylinder, cvptr->head, cvptr->sector);
3891 
3892     if (uptr->STATUS & S2_SEEK_CHECK)                       /* if a seek check occurred */
3893         end_command (cvptr, uptr, Status_2_Error);          /*   then report a Status-2 error */
3894     }
3895 
3896 else if (((uint32) uptr->CYL >= drive_props [model].cylinders)  /* otherwise the heads are positioned correctly */
3897   || (cvptr->head >= drive_props [model].heads)                 /*   but if the cylinder */
3898   || (cvptr->sector >= drive_props [model].sectors)) {          /*     or head or sector is out of bounds */
3899     uptr->STATUS |= S2_SEEK_CHECK;                              /*       then set Seek Check status */
3900     end_command (cvptr, uptr, Status_2_Error);                  /*         and terminate with an error */
3901     }
3902 
3903 else if (uptr->flags & UNIT_UNLOAD)                     /* otherwise if the drive is not ready for positioning */
3904     end_command (cvptr, uptr, Access_Not_Ready);        /*   then terminate with an access error */
3905 
3906 else {                                                  /* otherwise we are ready to move the heads */
3907     set_file_pos (cvptr, uptr, model);                  /*   so calculate the new position */
3908 
3909     if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) {   /* set the image file position; if it failed */
3910         io_error (cvptr, uptr, Status_2_Error);             /*   then report it to the simulation console */
3911 
3912         dl_load_unload (cvptr, uptr, FALSE);                /* unload the heads */
3913         uptr->STATUS |= S2_FAULT;                           /*   and set Fault status */
3914         }
3915 
3916     else {                                              /* otherwise the seek succeeded */
3917         uptr->PHASE = Data_Phase;                       /*   so set up the data transfer phase */
3918 
3919         if (cvptr->device->flags & DEV_REALTIME)        /* if the real time mode is enabled */
3920             uptr->wait = cvptr->dlyptr->data_xfer       /*   then base the delay on the sector preamble size */
3921                            * cmd_props [uptr->OPCODE].preamble_size;
3922         else                                            /* otherwise */
3923             uptr->wait = cvptr->dlyptr->data_xfer;      /*   start the transfer with a nominal delay */
3924 
3925         return TRUE;                                    /* report that positioning was accomplished */
3926         }
3927     }
3928 
3929 return FALSE;                                           /* positioning failed or was deferred */
3930 }
3931 
3932 
3933 /* Address the next sector.
3934 
3935    This routine is called after a sector has been successfully read or written
3936    in preparation for continuing the transfer.  It is also called after the
3937    Request Syndrome command returns the correction status for a sector in error.
3938 
3939    The controller's CHS address is incremented to point at the next sector.  If
3940    the next sector number is valid, the routine returns.  Otherwise, the sector
3941    number is reset to sector 0 and the address verification state is reset to
3942    enable it for a Read_Without_Verify command.  If the file mask is set for
3943    cylinder mode, the head is incremented, and if the new head number is valid,
3944    the routine returns.  If the head number is invalid, it is reset to head 0,
3945    and the end-of-cylinder flag is set.  The EOC flag is also set if the file
3946    mask is set for surface mode.
3947 
3948    The new cylinder address is not set here, because cylinder validation must
3949    only occur when the next sector is actually accessed.  Otherwise, reading or
3950    writing the last sector on a track or cylinder with auto-seek disabled would
3951    cause an End of Cylinder error, even if the transfer ended with that sector.
3952    Instead, we set the EOC flag to indicate that a cylinder update is pending.
3953 
3954    As a result of this deferred update method, the state of the EOC flag must be
3955    considered when returning the disc address to the CPU.
3956 */
3957 
next_sector(CVPTR cvptr,UNIT * uptr)3958 static void next_sector (CVPTR cvptr, UNIT *uptr)
3959 {
3960 const DRIVE_TYPE model = GET_MODEL (uptr->flags);       /* get the disc model */
3961 
3962 cvptr->sector = cvptr->sector + 1;                      /* increment the sector number */
3963 
3964 if (cvptr->sector < drive_props [model].sectors)        /* if we at not the end of the track */
3965     return;                                             /*   then the next sector value is OK */
3966 
3967 cvptr->sector = 0;                                          /* otherwise wrap the sector number */
3968 cvptr->verify = cmd_props [uptr->OPCODE].verify_address;    /*   and set the address verification flag */
3969 
3970 if (cvptr->file_mask & CM_CYL_MODE) {                   /* if the controller is in cylinder mode */
3971     cvptr->head = cvptr->head + 1;                      /*   then increment the head */
3972 
3973     if (cvptr->head < drive_props [model].heads)        /* if we are not at the end of the cylinder */
3974         return;                                         /*   then the next head value is OK */
3975 
3976     cvptr->head = 0;                                    /* otherwise wrap the head number */
3977     }
3978 
3979 cvptr->eoc = SET;                                       /* set the end-of-cylinder flag */
3980 return;                                                 /*   to indicate that an update is required */
3981 }
3982 
3983 
3984 /* Start a seek.
3985 
3986    A seek is initiated on the indicated unit if the drive is ready and the
3987    cylinder, head, and sector values in the controller are valid for the current
3988    drive model.  The routine returns TRUE if the unit is seeking and FALSE if
3989    the seek failed to start.
3990 
3991    If the drive is not ready, the seek fails immediately with a Status-2 error.
3992    If the drive is already seeking, Seek Check status will occur, and the
3993    routine will return TRUE to allow the current seek to complete normally.
3994 
3995    Otherwise, a seek is initiated to cylinder 0 if the current command is
3996    Recalibrate or to the cylinder value stored in the controller if it is not.
3997    EOC is reset for a seek but not for recalibrate, so that a reseek will return
3998    to the same location as was current when the recalibration was done.
3999 
4000    If the controller cylinder is beyond the drive's limit, Seek Check status is
4001    set in the unit, and the heads are not moved.  Otherwise, the relative
4002    cylinder position change is calculated, and the heads are moved to the new
4003    position.
4004 
4005    If the controller head or sector is beyond the drive's limit, Seek Check
4006    status is set in the unit.  Otherwise, Seek Check status is cleared.
4007 
4008    In hardware, the controller issues tag bus SEEK and ADR (address record)
4009    commands to the drive to load the drive's cylinder, head, and sector
4010    registers.  On the 7905 and 7906 drives, loading the head register
4011    establishes the drive's Read-Only status in conjunction with the PROTECT
4012    UPPER/LOWER DISC switch settings.
4013 
4014    A seek check for either the cylinder, head, or sector terminates the current
4015    command for an ICD controller.  For a MAC controller, the seek check is noted
4016    in the drive status, but processing will continue until the drive sets
4017    Attention status.
4018 
4019    Finally, the unit is set to the seek phase, and the scheduling delay is
4020    calculated by the distance the heads traversed (in real time mode), or
4021    it is set to a fixed delay (in fast time mode).
4022 
4023 
4024    Implementation notes:
4025 
4026     1. For ICD drives, a seek check will terminate the command immediately with
4027        a Status-2 error.  A seek-in-progress seek check cannot occur on an ICD
4028        drive, however, because the second seek command will not be started until
4029        the first seek completes.
4030 
4031     2. In hardware, a seek to the current location will set Drive Busy status
4032        for 1.3 milliseconds (the head settling time).  In simulation, disc
4033        service is scheduled as though a one-cylinder seek was requested.
4034 
4035     3. The head register contents does not affect Read-Only status on the 7920
4036        or 7925, which is established solely by the switch setting.  However, we
4037        set the drive status here anyway as a convenience.
4038 */
4039 
start_seek(CVPTR cvptr,UNIT * uptr)4040 static t_bool start_seek (CVPTR cvptr, UNIT *uptr)
4041 {
4042 int32 delta;
4043 uint32 target_cylinder;
4044 const DRIVE_TYPE model = GET_MODEL (uptr->flags);       /* get the drive model */
4045 
4046 if (uptr->flags & UNIT_UNLOAD)                          /* if the heads are unloaded */
4047     return FALSE;                                       /*   then the seek fails as the drive was not ready */
4048 
4049 else if (uptr->PHASE == Seek_Phase) {                   /* otherwise if a seek is in progress */
4050     uptr->STATUS |= S2_SEEK_CHECK;                      /*   then set Seek Check status */
4051     return TRUE;                                        /*     and return to let the seek complete */
4052     }
4053 
4054 else if (uptr->OPCODE == Recalibrate)                   /* otherwise if the unit is recalibrating */
4055     target_cylinder = 0;                                /*   then seek to cylinder 0 and don't reset the EOC flag */
4056 
4057 else {                                                  /* otherwise it's a Seek command or an auto-seek request */
4058     target_cylinder = cvptr->cylinder;                  /*   so seek to the controller cylinder */
4059     cvptr->eoc = CLEAR;                                 /*     and clear the end-of-cylinder flag */
4060     }
4061 
4062 if (target_cylinder >= drive_props [model].cylinders) { /* if the cylinder is out of bounds */
4063     delta = 0;                                          /*   then don't change the positioner */
4064     uptr->STATUS |= S2_SEEK_CHECK;                      /*     and set Seek Check status */
4065     }
4066 
4067 else {                                                  /* otherwise the cylinder value is OK */
4068     delta = abs (uptr->CYL - (int32) target_cylinder);  /* calculate the relative movement */
4069     uptr->CYL = target_cylinder;                        /*   and move the positioner */
4070 
4071     if (cvptr->head >= drive_props [model].heads        /* if the head */
4072       || cvptr->sector >= drive_props [model].sectors)  /*   or the sector is out of bounds */
4073         uptr->STATUS |= S2_SEEK_CHECK;                  /*     then set Seek Check status */
4074 
4075     else {                                              /* otherwise the head and sector are OK */
4076         uptr->STATUS &= ~S2_SEEK_CHECK;                 /*   so clear Seek Check status */
4077 
4078         if (uptr->flags &                               /* if the selected head is protected */
4079           (cvptr->head > 1 ? UNIT_PROT_L : UNIT_PROT_U))
4080             uptr->STATUS |= S2_READ_ONLY;               /*   then set read-only status */
4081         else                                            /* otherwise */
4082             uptr->STATUS &= ~S2_READ_ONLY;              /*   clear it */
4083         }
4084     }
4085 
4086 if (uptr->STATUS & S2_SEEK_CHECK && cvptr->type == ICD) /* if a seek check occurred on an ICD controller */
4087     return FALSE;                                       /*   then the command fails immediately */
4088 
4089 else {                                                  /* otherwise the seek was OK or this is a MAC controller */
4090     uptr->PHASE = Seek_Phase;                           /*   so set the unit to the seek phase */
4091 
4092     uptr->wait = cvptr->dlyptr->seek_one                /* set the seek delay, based on the relative movement */
4093                    + delta * (cvptr->dlyptr->seek_full - cvptr->dlyptr->seek_one)
4094                    / drive_props [model].cylinders;
4095     }
4096 
4097 return TRUE;                                            /* the seek is underway */
4098 }
4099 
4100 
4101 /* Report a stream I/O error.
4102 
4103    Errors indicated by the host file system are printed on the simulation
4104    console, and the current command is terminated with the supplied status
4105    indication.  The target OS will respond to the status return appropriately.
4106 */
4107 
io_error(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)4108 static void io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
4109 {
4110 cprintf ("%s simulator disc library I/O error: %s\n",   /* report the error to the console */
4111          sim_name, strerror (errno));
4112 
4113 tpprintf (cvptr->device, cvptr->device->dctrl, "Host system stream I/O call failed: %s\n",
4114           strerror (errno));
4115 
4116 clearerr (uptr->fileref);                               /* clear the error */
4117 
4118 end_command (cvptr, uptr, status);                      /* terminate the command with the supplied status */
4119 return;
4120 }
4121 
4122 
4123 /* Set up the controller completion.
4124 
4125    This routine performs a scheduled "end_command" to complete a command after a
4126    short delay.  It is called for commands that execute to completion with no
4127    drive or CPU interface interaction.  An otherwise unused "end phase" is
4128    scheduled just so that the command does not appear to complete
4129    instantaneously.
4130 */
4131 
set_completion(CVPTR cvptr,UNIT * uptr,CNTLR_STATUS status)4132 static void set_completion (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
4133 {
4134 cvptr->status = status;                                 /* save the supplied status */
4135 uptr->PHASE   = End_Phase;                              /* schedule the end phase */
4136 uptr->wait    = cvptr->dlyptr->overhead / 2;            /*   with a short delay */
4137 return;
4138 }
4139 
4140 
4141 
4142 /* Disc library local utility routines */
4143 
4144 
4145 /* Set the current controller address into the buffer.
4146 
4147    The controller's current cylinder, head, and sector are packed into two words
4148    and stored in the sector buffer, starting at the index specified.  If the
4149    end-of-cylinder flag is set, the cylinder is incremented to reflect the
4150    auto-seek that will be attempted when the next sequential access is made.
4151 
4152 
4153    Implementation notes:
4154 
4155     1. The 13037 firmware always increments the cylinder number if the EOC flag
4156        is set, rather than checking cylinder increment/decrement bit in the file
4157        mask.
4158 */
4159 
set_address(CVPTR cvptr,uint32 index)4160 static void set_address (CVPTR cvptr, uint32 index)
4161 {
4162 cvptr->buffer [index] =                                 /* update the cylinder if EOC is set */
4163   (DL_BUFFER) cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0);
4164 
4165 cvptr->buffer [index + 1] =                             /* merge the head and sector */
4166   (DL_BUFFER) (PO_HEAD (cvptr->head) | PO_SECTOR (cvptr->sector));
4167 
4168 return;
4169 }
4170 
4171 
4172 /* Return the drive status (Status-2).
4173 
4174    This routine returns the formatted unit status for the indicated drive unit.
4175 
4176    In hardware, the controller outputs the Address Unit command on the drive tag
4177    bus and the unit number on the drive control bus.  The addressed drive then
4178    responds by setting its internal "selected" flag.  The controller then
4179    outputs the Request Status command on the tag bug, and the selected drive
4180    returns its status on the control bus.  If a drive is selected but the heads
4181    are unloaded, the drive returns Not Ready and Busy status.  If no drive is
4182    selected, the control bus floats inactive.  This is interpreted by the
4183    controller as Not Ready status (because the drive returns an inactive Ready
4184    status).
4185 
4186    In simulation, an enabled but detached unit corresponds to "selected but
4187    heads unloaded," and a disabled unit corresponds to a non-existent unit.
4188 
4189 
4190    Implementation notes:
4191 
4192     1. The Attention, Read-Only, First Status, Fault, and Seek Check bits are
4193        stored in the unit status field.  The other status bits are determined
4194        dynamically.
4195 
4196     2. The Drive Busy bit is set if the unit is in the seek phase.  In hardware,
4197        this bit indicates that the heads are not positioned over a track, i.e.,
4198        that a seek is in progress.  A Request Status command is accepted only
4199        when the controller is waiting for seek completion or for a new command.
4200        Therefore, the unit will be either in the seek phase or the idle phase,
4201        respectively, when status is returned.
4202 */
4203 
drive_status(UNIT * uptr)4204 static HP_WORD drive_status (UNIT *uptr)
4205 {
4206 HP_WORD status;
4207 
4208 if (uptr == NULL)                                       /* if the unit is invalid */
4209     return S2_ERROR | S2_NOT_READY;                     /*   then it does not respond */
4210 
4211 status =                                                /* start with the drive type and unit status */
4212   S2_DRIVE_TYPE (GET_MODEL (uptr->flags)) | uptr->STATUS;
4213 
4214 if (uptr->flags & UNIT_FMT)                             /* if the format switch is enabled */
4215     status |= S2_FORMAT_EN;                             /*   then set the Format status bit */
4216 
4217 if (uptr->flags & UNIT_DIS)                             /* if the unit does not exist */
4218     status |= S2_NOT_READY;                             /*   then set the Not Ready bit */
4219 
4220 else if (uptr->flags & UNIT_UNLOAD)                     /* if the heads are unloaded */
4221     status |= S2_NOT_READY | S2_BUSY;                   /*   then set the Not Ready and Drive Busy bits */
4222 
4223 if (uptr->PHASE == Seek_Phase)                          /* if a seek is in progress */
4224     status |= S2_BUSY;                                  /*   then set the Drive Busy bit */
4225 
4226 if (status & S2_ERRORS)                                 /* if there any Status-2 errors */
4227     status |= S2_ERROR;                                 /*   then set the Error summary bit */
4228 
4229 return status;                                          /* return the unit status */
4230 }
4231 
4232 
4233 /* Activate the unit.
4234 
4235    The specified unit is activated using the unit's "wait" time.  If tracing
4236    is enabled, the activation is logged to the debug file.
4237 
4238 
4239    Implementation notes:
4240 
4241     1. The "%.0u" print specification in the trace call absorbs the zero "unit"
4242        value parameter without printing when the controller unit is specified.
4243 */
4244 
activate_unit(CVPTR cvptr,UNIT * uptr)4245 static t_stat activate_unit (CVPTR cvptr, UNIT *uptr)
4246 {
4247 t_stat result;
4248 const int32 unit = (int32) (uptr - cvptr->device->units);   /* the unit number */
4249 
4250 tpprintf (cvptr->device, DL_DEB_SERV, (unit == CNTLR_UNIT
4251                                          ? "Controller unit%.0d %s %s phase delay %d service scheduled\n"
4252                                          : "Unit %d %s %s phase delay %d service scheduled\n"),
4253           (unit == CNTLR_UNIT ? 0 : unit), opcode_name [uptr->OPCODE],
4254           phase_name [uptr->PHASE], uptr->wait);
4255 
4256 result = sim_activate (uptr, uptr->wait);               /* activate the unit */
4257 uptr->wait = NO_EVENT;                                  /*   and reset the activation time */
4258 
4259 return result;                                          /* return the activation status */
4260 }
4261 
4262 
4263 /* Set up the rotation phase.
4264 
4265    The supplied unit is set to the rotate phase at the start of a read or write
4266    command.  In real time mode, the rotational latency is determined by the
4267    distance between the "current" sector location and the target sector
4268    location.  The former is estimated from the current "simulation time," which
4269    is the number of event ticks since the simulation run was started, and the
4270    simulated disc rotation time, as follows:
4271 
4272      (simulation_time / per_sector_time) MOD sectors_per_track
4273 
4274    The distance is then:
4275 
4276      (sectors_per_track + target_sector - current_sector) MOD sectors_per_track
4277 
4278    ...and the latency is then:
4279 
4280      distance * per_sector_time
4281 
4282    In fast time mode, the latency is fixed at the specified per-sector time.
4283 */
4284 
set_rotation(CVPTR cvptr,UNIT * uptr)4285 static void set_rotation (CVPTR cvptr, UNIT *uptr)
4286 {
4287 uint32 sectors_per_track;
4288 double distance;
4289 
4290 uptr->PHASE = Rotate_Phase;                             /* set the phase */
4291 
4292 if (cvptr->device->flags & DEV_REALTIME) {              /* if the mode is real time */
4293     sectors_per_track =                                 /*   then calculate the latency as above */
4294       drive_props [GET_MODEL (uptr->flags)].sectors;
4295 
4296     distance =
4297       fmod (sectors_per_track + cvptr->sector - CURRENT_SECTOR (cvptr, uptr),
4298             sectors_per_track);
4299 
4300     uptr->wait = (int32) (cvptr->dlyptr->sector_full * distance);
4301     }
4302 
4303 else                                                    /* otherwise the mode is fast time */
4304     uptr->wait = cvptr->dlyptr->sector_full;            /*   so use the specified time directly */
4305 }
4306 
4307 
4308 /* Set the image file position.
4309 
4310    A cylinder/head/sector address is converted into a byte offset to pass to the
4311    host file I/O routines.  The cylinder is supplied by the drive unit, and the
4312    head and sector addresses are supplied by the controller.  The disc image
4313    file is laid out in one or two pieces, depending on whether a fixed platter
4314    is present in the drive.  If it is, then the area corresponding to the
4315    removable platter precedes the area corresponding to the fixed platter.  If
4316    not, then the file contains a single area encompassing all of the (removable)
4317    heads.
4318 
4319    In either case, the target track within the area is:
4320 
4321      cylinder * heads_per_cylinder + head
4322 
4323    ...and the target byte position in the file is:
4324 
4325      (target_track * sectors_per_track + sector) * bytes_per_sector
4326 */
4327 
set_file_pos(CVPTR cvptr,UNIT * uptr,uint32 model)4328 static void set_file_pos (CVPTR cvptr, UNIT *uptr, uint32 model)
4329 {
4330 uint32 track;
4331 
4332 if (cvptr->head < drive_props [model].remov_heads)              /* if the head is on a removable platter */
4333     track = uptr->CYL * drive_props [model].remov_heads         /*   then the tracks in the file are contiguous */
4334               + cvptr->head;
4335 
4336 else                                                            /* otherwise the head is on a fixed platter */
4337     track = drive_props [model].cylinders                       /*   so the target track is located */
4338               * drive_props [model].remov_heads                 /*     in the second area */
4339               + uptr->CYL * drive_props [model].fixed_heads     /*       that is offset from the first */
4340               + cvptr->head - drive_props [model].remov_heads;  /*         by the size of the removable platter */
4341 
4342 uptr->pos = (track * drive_props [model].sectors + cvptr->sector)   /* set the byte offset in the file */
4343               * WORDS_PER_SECTOR * sizeof (DL_BUFFER);              /*   of the CHS target sector */
4344 
4345 return;
4346 }
4347