1 /* hp2100_dp.c: HP 12557A/13210A Disc Interface simulator
2 
3    Copyright (c) 1993-2016, Robert M. Supnik
4    Copyright (c) 2017-2020  J. David Bryan
5 
6    Permission is hereby granted, free of charge, to any person obtaining a copy
7    of this software and associated documentation files (the "Software"), to deal
8    in the Software without restriction, including without limitation the rights
9    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10    copies of the Software, and to permit persons to whom the Software is
11    furnished to do so, subject to the following conditions:
12 
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15 
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 
23    Except as contained in this notice, the names of the authors shall not be
24    used in advertising or otherwise to promote the sale, use or other dealings
25    in this Software without prior written authorization from the authors.
26 
27    DP           12557A 2870 disc subsystem
28                 13210A 7900 disc subsystem
29 
30    25-Jan-20    JDB     First status also clears on Request Status
31    10-Jul-18    JDB     Revised I/O model
32    27-Feb-18    JDB     Corrected the conditions that clear drive status
33                         Added the BMDL
34    13-Feb-18    JDB     First Status is now cleared on Read, etc.
35    26-Jan-18    JDB     ATTACH -N now creates a full-size disc image
36    03-Aug-17    JDB     Changed perror call for I/O errors to cprintf
37    11-Jul-17    JDB     Renamed "ibl_copy" to "cpu_ibl"
38    22-Apr-17    JDB     Added fall-through comment for FNC_STA case in dpcio
39    09-Mar-17    JDB     Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
40    27-Feb-17    JDB     ibl_copy no longer returns a status code
41    09-Nov-16    JDB     Corrected disk subsystem model number from 2871 to 2870
42    13-May-16    JDB     Modified for revised SCP API function parameter types
43    30-Dec-14    JDB     Added S-register parameters to ibl_copy
44    24-Dec-14    JDB     Added casts for explicit downward conversions
45    18-Dec-12    MP      Now calls sim_activate_time to get remaining seek time
46    09-May-12    JDB     Separated assignments from conditional expressions
47    10-Feb-12    JDB     Deprecated DEVNO in favor of SC
48                         Added CNTLR_TYPE cast to dp_settype
49    28-Mar-11    JDB     Tidied up signal handling
50    26-Oct-10    JDB     Changed I/O signal handler for revised signal model
51    10-Aug-08    JDB     Added REG_FIT to register variables < 32-bit size
52    26-Jun-08    JDB     Rewrote device I/O to model backplane signals
53    28-Dec-06    JDB     Added ioCRS state to I/O decoders
54    01-Mar-05    JDB     Added SET UNLOAD/LOAD
55    07-Oct-04    JDB     Fixed enable/disable from either device
56                         Fixed ANY ERROR status for 12557A interface
57                         Fixed unattached drive status for 12557A interface
58                         Status cmd without prior STC DC now completes (12557A)
59                         OTA/OTB CC on 13210A interface also does CLC CC
60                         Fixed RAR model
61                         Fixed seek check on 13210 if sector out of range
62    20-Aug-04    JDB     Fixes from Dave Bryan
63                         - Check status on unattached drive set busy and not ready
64                         - Check status tests wrong unit for write protect status
65                         - Drive on line sets ATN, will set FLG if polling
66    15-Aug-04    RMS     Controller resumes polling for ATN interrupts after
67                         read status (found by Dave Bryan)
68    22-Jul-04    RMS     Controller sets ATN for all commands except
69                         read status (found by Dave Bryan)
70    21-Apr-04    RMS     Fixed typo in boot loader (found by Dave Bryan)
71    26-Apr-04    RMS     Fixed SFS x,C and SFC x,C
72                         Fixed SR setting in IBL
73                         Fixed interpretation of SR<0>
74                         Revised IBL loader
75                         Implemented DMA SRQ (follows FLG)
76    25-Apr-03    RMS     Revised for extended file support
77                         Fixed bug(s) in boot (found by Terry Newton)
78    10-Nov-02    RMS     Added BOOT command, fixed numerous bugs
79    15-Jan-02    RMS     Fixed INIT handling (found by Bill McDermith)
80    10-Jan-02    RMS     Fixed f(x)write call (found by Bill McDermith)
81    03-Dec-01    RMS     Changed DEVNO to use extended SET/SHOW
82    24-Nov-01    RMS     Changed STA to be an array
83    07-Sep-01    RMS     Moved function prototypes
84    29-Nov-00    RMS     Made variable names unique
85    21-Nov-00    RMS     Fixed flag, buffer power up state
86 
87    References:
88      - 7900A Disc Drive Operating and Service Manual
89          (07900-90002, February 1975)
90      - 13210A Disc Drive Interface Kit Operating and Service Manual
91          (13210-90003, May 1978)
92      - 12557A Cartridge Disc Interface Kit Operating and Service Manual
93          (12557-90001, Sepember 1970)
94 
95 
96    The simulator uses a number of state variables:
97 
98    dpc_busy             set to drive number + 1 when the controller is busy
99                         of the unit in use
100    dpd_xfer             set to 1 if the data channel is executing a data transfer
101    dpd_wval             set to 1 by OTx if either !dpc_busy or dpd_xfer
102    dpc_poll             set to 1 if attention polling is enabled
103 
104    dpc_busy and dpd_xfer are set together at the start of a read, write, refine,
105    or init.  When data transfers are complete (CLC DC), dpd_xfer is cleared, but the
106    operation is not necessarily over.  When the operation is complete, dpc_busy
107    is cleared and the command channel flag is set.
108 
109    dpc_busy && !dpd_xfer && STC DC (controller is busy, data channel transfer has
110    been terminated by CLC DC, but a word has been placed in the data channel buffer)
111    indicates data overrun.
112 
113    dpd_wval is used in write operations to fill out the sector buffer with 0's
114    if only a partial sector has been transferred.
115 
116    dpc_poll indicates whether seek completion polling can occur.  It is cleared
117    by reset and CLC CC and set by issuance of a seek or completion of check status.
118 
119    The controller's "Record Address Register" (RAR) contains the CHS address of
120    the last Seek or Address Record command executed.  The RAR is shared among
121    all drives on the controller.  In addition, each drive has an internal
122    position register that contains the last cylinder position transferred to the
123    drive during Seek command execution (data operations always start with the
124    RAR head and sector position).
125 
126    In a real drive, the address field of the sector under the head is read and
127    compared to the RAR.  When they match, the target sector is under the head
128    and is ready for reading or writing.  If a match doesn't occur, an Address
129    Error is indicated.  In the simulator, the address field is obtained from the
130    drive's current position register during a read, i.e., the "on-disc" address
131    field is assumed to match the current position.
132 
133    Each 7900 drive contains Attention and First Status flip-flops.  The First
134    Status flip-flop sets when the HEADS LOADED (i.e., DRIVE READY) signal first
135    asserts.  It clears when the CLEAR STATUS signal asserts.
136 
137    The Attention flip-flop sets when the ACCESS READY (i.e., a seek completes)
138    or DRIVE UNSAFE signals assert.  It clears when the CLEAR STATUS or DRIVE SET
139    CYLINDER (i.e., SET CYLINDER * DRIVE SELECT) signals assert.
140 
141    The CONTROL line to the drive enables the selected drive to execute the
142    command present on OUTBUS0-2.  If OUTBUS7 is also asserted, the CLEAR STATUS
143    signal is asserted, which clears the selected drive's Attention and First
144    Status flip-flops.  The 13210A controller asserts OUTBUS7 during ROM state 1,
145    which is entered for the Write, Read, Check Data, Initialize, and Status
146    Check commands.  Notably, it is not entered for Seek, so First Status will
147    not be cleared by a Seek command.  However, because Seek does assert SET
148    CYLINDER, the Attention flip-flop will be cleared by a Seek command.
149 
150    NOTE: 13210A manuals dated November 1974 and earlier contain errors in the
151    schematics.  See the comments preceding the "dpcio" routine for details.
152 
153 
154    The 13210A interfaces respond to I/O instructions as follows:
155 
156    Output Data Word format (OTA and OTB):
157 
158       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
159      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
160      |    command    | -   - | P | D | -   -   -   -   -   - | unit  | command
161      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
162      |                          write data                           | data
163      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
164      | -   -   -   -   -   -   -   - |       cylinder address        | data
165      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
166      | -   -   -   -   -   - | head  | -   -   - |  sector address   | data
167      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
168      | -   -   -   -   -   -   -   -   -   - |     sector count      | data
169      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
170 
171    Where:
172 
173      D = Defective Track
174      P = Protected Track
175 
176    Command:
177 
178      0000 = Status Check
179      0001 = Write Data
180      0010 = Read Data
181      0011 = Seek Record
182      0101 = Refine Sector
183      0110 = Check Data
184      1001 = Initialize Data
185      1011 = Address Record
186 
187    The 12557A interface responds identically, except that the sector address and
188    sector count fields use one fewer bit each, i.e., use bits 3-0 and 4-0,
189    respectively.
190 
191 
192    Input Data Word format (LIA and LIB):
193 
194       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
195      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
196      | -   -   -   -   -   -   -   -   -   -   -   - |   attention   | command
197      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
198      |                           read data                           | data
199      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
200      | - | F | O | - | U | P | - | S | - | N | C | A | G | B | D | E | data
201      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
202 
203    Where:
204 
205      F = First Status
206      O = Overrun
207      U = Drive Unsafe
208      P = Data Protected
209      S = Seek Check
210      N = Not Ready
211      C = End of Cylinder
212      A = Address Error
213      G = Flagged Cylinder
214      B = Drive Busy
215      D = Data Error
216      E = Any Error
217 
218    The 12557A interface responds identically, except that the status word is
219    extended as follows:
220 
221       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
222      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
223      | T | F | O | R | U | H | I | S | - | N | C | A | G | B | D | E | data
224      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
225 
226    Where the differing bits are:
227 
228      T = Attention
229      R = Read/Write Unsafe
230      H = Access Hunting
231      I = Seek Incomplete
232 
233 
234    Implementation notes:
235 
236     1. The following implemented behaviors have been inferred from secondary
237        sources (diagnostics, operating system drivers, etc.), due to absent or
238        contradictory authoritative information; future correction may be needed:
239 
240         - 12557A status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR).
241 
242         - 12557A clears status after a Check Status command, but 13210A does
243           not.
244 
245         - Omitting STC DC before Status Check does not set DC flag but does
246           poll.
247 */
248 
249 
250 
251 #include "hp2100_defs.h"
252 #include "hp2100_io.h"
253 
254 
255 
256 #define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
257 #define UNIT_V_UNLOAD   (UNIT_V_UF + 1)                 /* heads unloaded */
258 #define UNIT_WLK        (1 << UNIT_V_WLK)
259 #define UNIT_UNLOAD     (1 << UNIT_V_UNLOAD)
260 #define FNC             u3                              /* saved function */
261 #define DRV             u4                              /* drive number (DC) */
262 #define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write prot */
263 
264 #define DP_N_NUMWD      7
265 #define DP_NUMWD        (1 << DP_N_NUMWD)               /* words/sector */
266 #define DP_NUMSC2       12                              /* sectors/srf 12557 */
267 #define DP_NUMSC3       24                              /* sectors/srf 13210 */
268 #define DP_NUMSC        (dp_ctype ? DP_NUMSC3 : DP_NUMSC2)
269 #define DP_NUMSF        4                               /* surfaces/cylinder */
270 #define DP_NUMCY        203                             /* cylinders/disk */
271 #define DP_SIZE2        (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD)
272 #define DP_SIZE3        (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)
273 #define DP_NUMDRV       4                               /* # drives */
274 
275 /* Command word.
276 
277       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
278      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
279      |    command    | -   - | P | D | -   -   -   -   -   - | unit  |
280      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
281 */
282 
283 #define CW_V_FNC        12                              /* function */
284 #define CW_M_FNC        017
285 #define CW_GETFNC(x)    (((x) >> CW_V_FNC) & CW_M_FNC)
286 #define  FNC_STA        000                             /* status check */
287 #define  FNC_WD         001                             /* write */
288 #define  FNC_RD         002                             /* read */
289 #define  FNC_SEEK       003                             /* seek */
290 #define  FNC_REF        005                             /* refine */
291 #define  FNC_CHK        006                             /* check */
292 #define  FNC_INIT       011                             /* init */
293 #define  FNC_AR         013                             /* address */
294 #define  FNC_SEEK1      020                             /* fake - seek1 */
295 #define  FNC_SEEK2      021                             /* fake - seek2 */
296 #define  FNC_SEEK3      022                             /* fake - seek3 */
297 #define  FNC_CHK1       023                             /* fake - check1 */
298 #define  FNC_AR1        024                             /* fake - arec1 */
299 #define CW_V_DRV        0                               /* drive */
300 #define CW_M_DRV        03
301 #define CW_GETDRV(x)    (((x) >> CW_V_DRV) & CW_M_DRV)
302 
303 /* Disk address words */
304 
305 #define DA_V_CYL        0                               /* cylinder */
306 #define DA_M_CYL        0377
307 #define DA_GETCYL(x)    (((x) >> DA_V_CYL) & DA_M_CYL)
308 #define DA_V_HD         8                               /* head */
309 #define DA_M_HD         03
310 #define DA_GETHD(x)     (((x) >> DA_V_HD) & DA_M_HD)
311 #define DA_V_SC         0                               /* sector */
312 #define DA_M_SC2        017
313 #define DA_M_SC3        037
314 #define DA_M_SC         (dp_ctype ? DA_M_SC3 : DA_M_SC2)
315 #define DA_GETSC(x)     (((x) >> DA_V_SC) & DA_M_SC)
316 #define DA_CKMASK2      037                             /* check mask */
317 #define DA_CKMASK3      077
318 #define DA_CKMASK       (dp_ctype ? DA_CKMASK3 : DA_CKMASK2)
319 
320 /* Status in dpc_sta [drv].
321 
322       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
323      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
324      | - | F | O | - | U | P | - | S | - | N | C | A | G | B | D | E | 13210A
325      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
326      | T | F | O | R | U | H | I | S | - | N | C | A | G | B | D | E | 12557A
327      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
328 
329 
330    Implementation notes:
331 
332     1. The Data Protected, Not Ready, and Any Error bits are determined
333        dynamically.  The other status bits are stored in the drive status array.
334 */
335 
336 #define STA_ATN         0100000                         /* (T) Attention (12557) */
337 #define STA_1ST         0040000                         /* (F) First status */
338 #define STA_OVR         0020000                         /* (O) Overrun */
339 #define STA_RWU         0010000                         /* (R) Read/Write Unsafe (12557) */
340 #define STA_ACU         0004000                         /* (U) Drive Unsafe */
341 #define STA_PROT        0002000                         /* (P) Data Protected (13210) */
342 #define STA_HUNT        0002000                         /* (H) Access Hunting (12557) */
343 #define STA_SKI         0001000                         /* (I) Seek Incomplete (12557) */
344 #define STA_SKE         0000400                         /* (S) Seek Check */
345 /*                      0000200                            (unused) */
346 #define STA_NRDY        0000100                         /* (N) Not Ready */
347 #define STA_EOC         0000040                         /* (C) End of Cylinder */
348 #define STA_AER         0000020                         /* (A) Address Error */
349 #define STA_FLG         0000010                         /* (G) Flagged Cylinder */
350 #define STA_BSY         0000004                         /* (B) Drive Busy */
351 #define STA_DTE         0000002                         /* (D) Data Error */
352 #define STA_ERR         0000001                         /* (E) Any Error */
353 
354 #define STA_ERSET2      (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
355                          STA_SKI | STA_SKE | STA_NRDY | \
356                          STA_EOC | STA_AER | STA_DTE)   /* 12557A error set */
357 
358 #define STA_ERSET3      (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
359                          STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \
360                          STA_FLG | STA_BSY | STA_DTE)   /* 13210A error set */
361 
362 #define STA_ANYERR      (dp_ctype ? STA_ERSET3 : STA_ERSET2)
363 #define STA_UNLOADED    (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)
364 
365 #define STA_MBZ13       (STA_ATN | STA_RWU | STA_SKI)   /* zero in 13210 */
366 
367 
368 /* Interface state */
369 
370 typedef struct {
371     FLIP_FLOP  command;                         /* command flip-flop */
372     FLIP_FLOP  control;                         /* control flip-flop */
373     FLIP_FLOP  flag;                            /* flag flip-flop */
374     FLIP_FLOP  flag_buffer;                     /* flag buffer flip-flop */
375     } CARD_STATE;
376 
377 static CARD_STATE dpd;                          /* per-card state */
378 static CARD_STATE dpc;                          /* per-card state */
379 
380 
381 /* Controller types */
382 
383 typedef enum {
384     A12557,
385     A13210
386     } CNTLR_TYPE;
387 
388 static CNTLR_TYPE dp_ctype = A13210;            /* ctrl type */
389 static int32 dpc_busy = 0;                      /* cch unit */
390 static int32 dpc_poll = 0;                      /* cch poll enable */
391 static int32 dpc_cnt = 0;                       /* check count */
392 static int32 dpc_eoc = 0;                       /* end of cyl */
393 static int32 dpc_stime = 100;                   /* seek time */
394 static int32 dpc_ctime = 100;                   /* command time */
395 static int32 dpc_xtime = 5;                     /* xfer time */
396 static int32 dpc_dtime = 2;                     /* dch time */
397 static int32 dpd_obuf = 0, dpd_ibuf = 0;        /* dch buffers */
398 static int32 dpc_obuf = 0;                      /* cch buffers */
399 
400 static int32 dpd_xfer = 0;                      /* xfer in prog */
401 static int32 dpd_wval = 0;                      /* write data valid */
402 static int32 dp_ptr = 0;                        /* buffer ptr */
403 static uint8 dpc_rarc = 0;                      /* RAR cylinder */
404 static uint8 dpc_rarh = 0;                      /* RAR head */
405 static uint8 dpc_rars = 0;                      /* RAR sector */
406 static uint8 dpc_ucyl[DP_NUMDRV] = { 0 };       /* unit cylinder */
407 static uint16 dpc_sta[DP_NUMDRV] = { 0 };       /* status regs */
408 static uint16 dpxb[DP_NUMWD];                   /* sector buffer */
409 
410 
411 /* Interface local SCP support routines */
412 
413 static INTERFACE dpd_interface;
414 static INTERFACE dpc_interface;
415 
416 
417 /* Interface local SCP support routines */
418 
419 static t_stat dpc_svc (UNIT *uptr);
420 static t_stat dpd_svc (UNIT *uptr);
421 static t_stat dpc_reset (DEVICE *dptr);
422 static t_stat dpc_attach (UNIT *uptr, char *cptr);
423 static t_stat dpc_detach (UNIT* uptr);
424 static t_stat dpc_boot (int32 unitno, DEVICE *dptr);
425 static void dp_god (int32 fnc, int32 drv, int32 time);
426 static void dp_goc (int32 fnc, int32 drv, int32 time);
427 static t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);
428 static t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
429 static t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
430 
431 
432 /* Device information blocks */
433 
434 static DIB dp_dib [] = {
435     { &dpd_interface,                                                       /* the device's I/O interface function pointer */
436       DPD,                                                                  /* the device's select code (02-77) */
437       0,                                                                    /* the card index */
438       "12557A Cartridge Disc/13210A Disc Drive Interface Data Channel",     /* the card description */
439       NULL },                                                               /* the ROM description */
440 
441     { &dpc_interface,                                                       /* the device's I/O interface function pointer */
442       DPC,                                                                  /* the device's select code (02-77) */
443       0,                                                                    /* the card index */
444       "12557A Cartridge Disc/13210A Disc Drive Interface Command Channel",  /* the card description */
445       "12992F 2870/7900/7901 Disc Loader" }                                 /* the ROM description */
446     };
447 
448 #define dpd_dib             dp_dib [0]
449 #define dpc_dib             dp_dib [1]
450 
451 
452 /* Data card SCP data structures */
453 
454 
455 /* Unit list */
456 
457 static UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) };
458 
459 
460 /* Register list */
461 
462 static REG dpd_reg[] = {
463     { ORDATA (IBUF, dpd_ibuf, 16) },
464     { ORDATA (OBUF, dpd_obuf, 16) },
465     { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },
466     { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },
467     { FLDATA (CMD, dpd.command, 0) },
468     { FLDATA (CTL, dpd.control, 0) },
469     { FLDATA (FLG, dpd.flag,    0) },
470     { FLDATA (FBF, dpd.flag_buffer, 0) },
471     { FLDATA (XFER, dpd_xfer, 0) },
472     { FLDATA (WVAL, dpd_wval, 0) },
473 
474       DIB_REGS (dpd_dib),
475 
476     { NULL }
477     };
478 
479 
480 /* Modifier list */
481 
482 static MTAB dpd_mod [] = {
483 /*    Entry Flags          Value  Print String  Match String  Validation    Display        Descriptor       */
484 /*    -------------------  -----  ------------  ------------  ------------  -------------  ---------------- */
485     { MTAB_XDV,              2u,  "SC",         "SC",         &hp_set_dib,  &hp_show_dib,  (void *) &dp_dib },
486     { MTAB_XDV | MTAB_NMO,  ~2u,  "DEVNO",      "DEVNO",      &hp_set_dib,  &hp_show_dib,  (void *) &dp_dib },
487     { 0 }
488     };
489 
490 
491 /* Debugging trace list */
492 
493 static DEBTAB dpd_deb [] = {
494     { "IOBUS", TRACE_IOBUS },                   /* trace I/O bus signals and data words received and returned */
495     { NULL,    0           }
496     };
497 
498 
499 /* Device descriptor */
500 
501 DEVICE dpd_dev = {
502     "DPD",                                      /* device name */
503     &dpd_unit,                                  /* unit array */
504     dpd_reg,                                    /* register array */
505     dpd_mod,                                    /* modifier array */
506     1,                                          /* number of units */
507     10,                                         /* address radix */
508     DP_N_NUMWD,                                 /* address width = 4 GB */
509     1,                                          /* address increment */
510     8,                                          /* data radix */
511     16,                                         /* data width */
512     NULL,                                       /* examine routine */
513     NULL,                                       /* deposit routine */
514     &dpc_reset,                                 /* reset routine */
515     NULL,                                       /* boot routine */
516     NULL,                                       /* attach routine */
517     NULL,                                       /* detach routine */
518     &dpd_dib,                                   /* device information block pointer */
519     DEV_DISABLE | DEV_DEBUG,                    /* device flags */
520     0,                                          /* debug control flags */
521     dpd_deb,                                    /* debug flag name array */
522     NULL,                                       /* memory size change routine */
523     NULL                                        /* logical device name */
524     };
525 
526 
527 /* Control card SCP data structures */
528 
529 
530 /* Unit list */
531 
532 #define UNIT_FLAGS          (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD)
533 
534 static UNIT dpc_unit[] = {
535     { UDATA (&dpc_svc, UNIT_FLAGS, DP_SIZE3) },
536     { UDATA (&dpc_svc, UNIT_FLAGS, DP_SIZE3) },
537     { UDATA (&dpc_svc, UNIT_FLAGS, DP_SIZE3) },
538     { UDATA (&dpc_svc, UNIT_FLAGS, DP_SIZE3) }
539     };
540 
541 
542 /* Register list */
543 
544 static REG dpc_reg[] = {
545     { ORDATA (OBUF, dpc_obuf, 16) },
546     { ORDATA (BUSY, dpc_busy, 4), REG_RO },
547     { ORDATA (CNT, dpc_cnt, 5) },
548     { FLDATA (CMD, dpc.command, 0) },
549     { FLDATA (CTL, dpc.control, 0) },
550     { FLDATA (FLG, dpc.flag,    0) },
551     { FLDATA (FBF, dpc.flag_buffer, 0) },
552     { FLDATA (EOC, dpc_eoc, 0) },
553     { FLDATA (POLL, dpc_poll, 0) },
554     { DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT },
555     { DRDATA (RARH, dpc_rarh, 2), PV_RZRO | REG_FIT },
556     { DRDATA (RARS, dpc_rars, 5), PV_RZRO | REG_FIT },
557     { BRDATA (CYL, dpc_ucyl, 10, 8, DP_NUMDRV), PV_RZRO },
558     { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },
559     { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT },
560     { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT },
561     { DRDATA (STIME, dpc_stime, 24), PV_LEFT },
562     { DRDATA (XTIME, dpc_xtime, 24), REG_NZ | PV_LEFT },
563     { FLDATA (CTYPE, dp_ctype, 0), REG_HRO },
564     { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0,
565               DP_NUMDRV, REG_HRO) },
566     { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0,
567               DP_NUMDRV, PV_LEFT | REG_HRO) },
568 
569       DIB_REGS (dpc_dib),
570 
571     { NULL }
572     };
573 
574 
575 /* Modifier list */
576 
577 static MTAB dpc_mod [] = {
578 /*    Mask Value    Match Value   Print String       Match String     Validation         Display  Descriptor */
579 /*    ------------  ------------  -----------------  ---------------  -----------------  -------  ---------- */
580     { UNIT_UNLOAD,  UNIT_UNLOAD,  "heads unloaded",  "UNLOADED",      &dpc_load_unload,  NULL,    NULL       },
581     { UNIT_UNLOAD,  0,            "heads loaded",    "LOADED",        &dpc_load_unload,  NULL,    NULL       },
582     { UNIT_WLK,     UNIT_WLK,     "protected",       "PROTECT",       NULL,              NULL,    NULL       },
583     { UNIT_WLK,     0,            "unprotected",     "UNPROTECT",     NULL,              NULL,    NULL       },
584     { UNIT_WLK,     UNIT_WLK,     NULL,              "LOCKED",        NULL,              NULL,    NULL       },
585     { UNIT_WLK,     0,            NULL,              "WRITEENABLED",  NULL,              NULL,    NULL       },
586 
587 /*    Entry Flags          Value  Print String  Match String  Validation    Display        Descriptor       */
588 /*    -------------------  -----  ------------  ------------  ------------  -------------  ---------------- */
589     { MTAB_XDV,              1,   NULL,         "13210A",     &dp_settype,  NULL,          NULL             },
590     { MTAB_XDV,              0,   NULL,         "12557A",     &dp_settype,  NULL,          NULL             },
591     { MTAB_XDV,              0,   "TYPE",       NULL,         NULL,         &dp_showtype,  NULL             },
592     { MTAB_XDV,              2u,  "SC",         "SC",         &hp_set_dib,  &hp_show_dib,  (void *) &dp_dib },
593     { MTAB_XDV | MTAB_NMO,  ~2u,  "DEVNO",      "DEVNO",      &hp_set_dib,  &hp_show_dib,  (void *) &dp_dib },
594     { 0 }
595     };
596 
597 
598 /* Debugging trace list */
599 
600 static DEBTAB dpc_deb [] = {
601     { "IOBUS", TRACE_IOBUS },                   /* trace I/O bus signals and data words received and returned */
602     { NULL,    0           }
603     };
604 
605 
606 /* Device descriptor */
607 
608 DEVICE dpc_dev = {
609     "DPC",                                      /* device name */
610     dpc_unit,                                   /* unit array */
611     dpc_reg,                                    /* register array */
612     dpc_mod,                                    /* modifier array */
613     DP_NUMDRV,                                  /* number of units */
614     8,                                          /* address radix */
615     24,                                         /* address width = 4 GB */
616     1,                                          /* address increment */
617     8,                                          /* data radix */
618     16,                                         /* data width */
619     NULL,                                       /* examine routine */
620     NULL,                                       /* deposit routine */
621     &dpc_reset,                                 /* reset routine */
622     &dpc_boot,                                  /* boot routine */
623     &dpc_attach,                                /* attach routine */
624     &dpc_detach,                                /* detach routine */
625     &dpc_dib,                                   /* device information block pointer */
626     DEV_DISABLE | DEV_DEBUG,                    /* device flags */
627     0,                                          /* debug control flags */
628     dpc_deb,                                    /* debug flag name array */
629     NULL,                                       /* memory size change routine */
630     NULL                                        /* logical device name */
631     };
632 
633 
634 /* Data channel interface.
635 
636    For the 12557A, the card contains the usual control, flag, and flag buffer
637    flip-flops.  PRL, IRQ, and SRQ are standard.  A command flip-flop indicates
638    that data is available.
639 
640    For the 13210A, the card has a flag and a flag buffer flip-flop, but no
641    control or interrupt flip-flop.  SRQ is standard.  IRQ and PRL are not
642    driven, and the card does not respond to IAK.  STC sets the command flip-flop
643    to initiate a data transfer.  CLC has no effect.
644 
645    Implementation notes:
646 
647     1. The CRS signal clears the drive attention register.  Under simulation,
648        drive attention status is generated dynamically, so there is no attention
649        register.
650 */
651 
dpd_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)652 static SIGNALS_VALUE dpd_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
653 {
654 INBOUND_SIGNAL signal;
655 INBOUND_SET    working_set = inbound_signals;
656 SIGNALS_VALUE  outbound    = { ioNONE, 0 };
657 t_bool         irq_enabled = FALSE;
658 
659 while (working_set) {                                   /* while signals remain */
660     signal = IONEXTSIG (working_set);                   /*   isolate the next signal */
661 
662     switch (signal) {                                   /* dispatch the I/O signal */
663 
664         case ioCLF:                                     /* Clear Flag flip-flop */
665             dpd.flag_buffer = CLEAR;                    /* reset the flag buffer */
666             dpd.flag        = CLEAR;                    /*   and flag flip-flops */
667             break;
668 
669 
670         case ioSTF:                                     /* Set Flag flip-flop */
671             dpd.flag_buffer = SET;                      /* set the flag buffer flip-flop */
672             break;
673 
674 
675         case ioENF:                                     /* Enable Flag */
676             if (dpd.flag_buffer == SET)                 /* if the flag buffer flip-flop is set */
677                 dpd.flag = SET;                         /*   then set the flag flip-flop */
678             break;
679 
680 
681         case ioSFC:                                     /* Skip if Flag is Clear */
682             if (dpd.flag == CLEAR)                      /* if the flag flip-flop is clear */
683                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
684             break;
685 
686 
687         case ioSFS:                                     /* Skip if Flag is Set */
688             if (dpd.flag == SET)                        /* if the flag flip-flop is set */
689                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
690             break;
691 
692 
693         case ioIOI:                                     /* I/O data input */
694             outbound.value = dpd_ibuf;                  /* return data */
695             break;
696 
697 
698         case ioIOO:                                     /* I/O data output */
699             dpd_obuf = inbound_value;                   /* clear supplied status */
700 
701             if (!dpc_busy || dpd_xfer)                  /* if !overrun */
702                 dpd_wval = 1;                           /* valid */
703             break;
704 
705 
706         case ioPOPIO:                                   /* Power-On Preset to I/O */
707             dpd.flag_buffer = SET;                      /* set the flag buffer flip-flop */
708 
709             if (dp_ctype == A12557)                     /* 12557? */
710                 dpd_obuf = 0;                           /* clear output buffer */
711             break;
712 
713 
714         case ioCRS:                                     /* Control Reset */
715             dpd.command = CLEAR;                        /* clear command */
716 
717             if (dp_ctype == A12557)                     /* 12557? */
718                 dpd.control = CLEAR;                    /* clear control */
719 
720             else {                                      /* 13210 */
721                 dpc_rarc = 0;                           /* clear controller cylinder address */
722                 dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0;    /* clear last drive addressed cylinder */
723                 }
724             break;
725 
726 
727         case ioCLC:                                     /* Clear Control flip-flop */
728             if (dp_ctype == A12557)                     /* 12557? */
729                 dpd.control = CLEAR;                    /* clear control */
730 
731             dpd_xfer = 0;                               /* clr xfer in progress */
732             break;
733 
734 
735         case ioSTC:                                     /* Set Control flip-flop */
736             if (dp_ctype == A12557)                     /* 12557? */
737                 dpd.control = SET;                      /* set control */
738 
739             dpd.command = SET;                          /* set cmd */
740 
741             if (dpc_busy && !dpd_xfer)                  /* overrun? */
742                 dpc_sta[dpc_busy - 1] |= STA_OVR;
743             break;
744 
745 
746         case ioSIR:                                         /* Set Interrupt Request */
747             if (dp_ctype == A12557) {                       /* 12557? */
748                 if (dpd.control & dpd.flag)                 /* if the control and flag flip-flops are set */
749                     outbound.signals |= cnVALID;            /*   then deny PRL */
750                 else                                        /* otherwise */
751                     outbound.signals |= cnPRL | cnVALID;    /*   conditionally assert PRL */
752 
753                 if (dpd.control & dpd.flag & dpd.flag_buffer)   /* if the control, flag, and flag buffer flip-flops are set */
754                     outbound.signals |= cnIRQ | cnVALID;        /*   then conditionally assert IRQ */
755                 }
756 
757             if (dpd.flag == SET)                        /* if the flag flip-flop is set */
758                 outbound.signals |= ioSRQ;              /*   then assert SRQ */
759             break;
760 
761 
762         case ioIAK:                                     /* Interrupt Acknowledge */
763             if (dp_ctype == A12557)                     /* 12557? */
764                 dpd.flag_buffer = CLEAR;                /* clear the flag buffer flip-flop */
765             break;
766 
767 
768         case ioIEN:                                     /* Interrupt Enable */
769             irq_enabled = TRUE;                         /* permit IRQ to be asserted */
770             break;
771 
772 
773         case ioPRH:                                         /* Priority High */
774             if (irq_enabled && outbound.signals & cnIRQ)    /* if IRQ is enabled and conditionally asserted */
775                 outbound.signals |= ioIRQ | ioFLG;          /*   then assert IRQ and FLG */
776 
777             if (!irq_enabled || outbound.signals & cnPRL)   /* if IRQ is disabled or PRL is conditionally asserted */
778                 outbound.signals |= ioPRL;                  /*   then assert it unconditionally */
779             break;
780 
781 
782         case ioEDT:                                     /* not used by this interface */
783         case ioPON:                                     /* not used by this interface */
784             break;
785         }
786 
787     IOCLEARSIG (working_set, signal);                   /* remove the current signal from the set */
788     }                                                   /*   and continue until all signals are processed */
789 
790 return outbound;                                        /* return the outbound signals and value */
791 }
792 
793 
794 /* Command channel interface.
795 
796    The 12557A and 13210A have the usual control, flag, and flag buffer
797    flip-flops.  Only the 12557A has a command flip-flop.  IRQ, PRL, and SRQ are
798    standard.
799 
800 
801    Implementation notes:
802 
803     1. In hardware, the command channel card passes PRH to PRL.  The data card
804        actually drives PRL with the command channel's control and flag states,
805        even though the command channel's control, flag, and flag buffer drive
806        IRQH.  That is, the priority chain is broken at the data card, although
807        the command card is interrupting.  This works in hardware, but we must
808        break PRL at the command card under simulation to allow the command card
809        to interrupt.
810 
811     2. The 13210 manual says that a Check Status command clears the status
812        register, which consists of status word bits 14, 13, 11, 10, 8, 5, 4, 3,
813        1, and 0, i.e., all except bit 6 "Not Ready" and bit 2 "Drive Busy",
814        which are direct pass-throughs from the drive.  However, the schematic
815        shows that the register is cleared on STC assertion for any command
816        OTHER than Check Status.  In other words, every command except Check
817        Status clears the old status in order to assert new status (so two
818        successive Check Status commands will return the same status word,
819        contrary to the manual).  The simulator implements the schematic
820        behavior.
821 
822     3. The schematics contained in 13210A manuals dated November 1974 and
823        earlier show that CRS does not clear the status register, but examining
824        the hardware PCA shows that it does.  The simulator implements the
825        hardware behavior.
826 
827     4. The schematics contained in 13210A manuals dated November 1974 and
828        earlier show that CRS clears the attention register, but examining the
829        hardware PCA shows that it does not.  The signal marked CRS is actually
830        the XFER CYL signal from the sequencer, so the register is actually
831        cleared when a Check Status or Seek command is issued.  However, later
832        PCAs did add CRS to the other two clearing conditions.  The simulator
833        implements this later behavior.
834 */
835 
dpc_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)836 static SIGNALS_VALUE dpc_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
837 {
838 int32          i, fnc, drv;
839 INBOUND_SIGNAL signal;
840 INBOUND_SET    working_set = inbound_signals;
841 SIGNALS_VALUE  outbound    = { ioNONE, 0 };
842 t_bool         irq_enabled = FALSE;
843 
844 while (working_set) {                                   /* while signals remain */
845     signal = IONEXTSIG (working_set);                   /*   isolate the next signal */
846 
847     switch (signal) {                                   /* dispatch the I/O signal */
848 
849         case ioCLF:                                     /* Clear Flag flip-flop */
850             dpc.flag_buffer = CLEAR;                    /* reset the flag buffer */
851             dpc.flag        = CLEAR;                    /*   and flag flip-flops */
852             break;
853 
854 
855         case ioSTF:                                     /* Set Flag flip-flop */
856             dpc.flag_buffer = SET;                      /* set the flag buffer flip-flop */
857             break;
858 
859 
860         case ioENF:                                     /* Enable Flag */
861             if (dpc.flag_buffer == SET)                 /* if the flag buffer flip-flop is set */
862                 dpc.flag = SET;                         /*   then set the flag flip-flop */
863             break;
864 
865 
866         case ioSFC:                                     /* Skip if Flag is Clear */
867             if (dpc.flag == CLEAR)                      /* if the flag flip-flop is clear */
868                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
869             break;
870 
871 
872         case ioSFS:                                     /* Skip if Flag is Set */
873             if (dpc.flag == SET)                        /* if the flag flip-flop is set */
874                 outbound.signals |= ioSKF;              /*   then assert the Skip on Flag signal */
875             break;
876 
877 
878         case ioIOI:                                     /* I/O data input */
879             outbound.value = 0;
880 
881             for (i = 0; i < DP_NUMDRV; i++)             /* form attention register value */
882                 if (dpc_sta[i] & STA_ATN)
883                     outbound.value |= 1u << i;
884             break;
885 
886 
887         case ioIOO:                                     /* I/O data output */
888             dpc_obuf = inbound_value;                   /* clear supplied status */
889 
890             if (dp_ctype == A13210)                     /* 13210? */
891                 working_set |= ioCLC;                   /* OTx causes CLC */
892             break;
893 
894 
895         case ioPOPIO:                                   /* Power-On Preset to I/O */
896             dpc.flag_buffer = SET;                      /* set the flag buffer flip-flop */
897 
898             if (dp_ctype == A12557)                     /* 12557? */
899                 dpd_obuf = 0;                           /* clear output buffer */
900             break;
901 
902 
903         case ioCRS:                                     /* Control Reset */
904             dpc.control = CLEAR;                        /* clear control */
905 
906             if (dp_ctype == A12557)                     /* 12557? */
907                 dpc.command = CLEAR;                    /* clear command */
908 
909             for (drv = 0; drv < DP_NUMDRV; drv++)       /* clear drive status */
910                 dpc_sta [drv] &=                        /*   for each drive */
911                   ~(STA_1ST | STA_OVR | STA_RWU | STA_ACU | STA_EOC
912                     | STA_AER | STA_FLG | STA_DTE);
913             break;
914 
915 
916         case ioCLC:                                     /* Clear Control flip-flop */
917             dpc.control = CLEAR;                        /* clr ctl */
918 
919             if (dp_ctype == A12557)                     /* 12557? */
920                 dpc.command = CLEAR;                    /* cancel non-seek */
921 
922             if (dpc_busy)
923                 sim_cancel (&dpc_unit[dpc_busy - 1]);
924 
925             sim_cancel (&dpd_unit);                     /* cancel dch */
926             dpd_xfer = 0;                               /* clr dch xfer */
927             dpc_busy = 0;                               /* clr cch busy */
928             dpc_poll = 0;                               /* clr cch poll */
929             break;
930 
931 
932         case ioSTC:                                     /* Set Control flip-flop */
933             dpc.control = SET;                          /* set ctl */
934 
935             if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */
936                 if (dp_ctype == A12557)                 /* 12557? */
937                     dpc.command = SET;                  /* set command */
938 
939                 drv = CW_GETDRV (dpc_obuf);             /* get fnc, drv */
940                 fnc = CW_GETFNC (dpc_obuf);             /* from cmd word */
941 
942                 if (fnc != FNC_STA)                     /* if this is not a status command */
943                     dpc_sta [drv] &=                    /*   then clear the status register */
944                       ~(STA_OVR | STA_RWU | STA_ACU | STA_EOC
945                         | STA_AER | STA_FLG | STA_DTE);
946 
947                 switch (fnc) {                          /* case on fnc */
948 
949                     case FNC_SEEK:                      /* seek */
950                         dpc_poll = 1;                   /* enable polling */
951                         dp_god (fnc, drv, dpc_dtime);   /* sched dch xfr */
952                         break;
953 
954                     case FNC_STA:                       /* rd sta */
955                         if (dp_ctype == A13210) {       /* 13210? clr dch flag */
956                             dpd.flag_buffer = CLEAR;    /* reset the flag buffer */
957                             dpd.flag        = CLEAR;    /*   and flag flip-flops */
958                             }
959 
960                     /* fall through into the FNC_CHK and FNC_AR cases */
961 
962                     case FNC_CHK:                       /* check */
963                     case FNC_AR:                        /* addr rec */
964                         dp_god (fnc, drv, dpc_dtime);   /* sched dch xfr */
965                         break;
966 
967                     case FNC_RD: case FNC_WD:           /* read, write */
968                     case FNC_REF: case FNC_INIT:        /* refine, init */
969                         dp_goc (fnc, drv, dpc_ctime);   /* sched drive */
970                         break;
971                     }                                   /* end case */
972                 }                                       /* end if */
973             break;
974 
975 
976         case ioSIR:                                     /* Set Interrupt Request */
977             if (dpc.control & dpc.flag)                 /* if the control and flag flip-flops are set */
978                 outbound.signals |= cnVALID;            /*   then deny PRL */
979             else                                        /* otherwise */
980                 outbound.signals |= cnPRL | cnVALID;    /*   conditionally assert PRL */
981 
982             if (dpc.control & dpc.flag & dpc.flag_buffer)   /* if the control, flag, and flag buffer flip-flops are set */
983                 outbound.signals |= cnIRQ | cnVALID;        /*   then conditionally assert IRQ */
984 
985             if (dpc.flag == SET)                        /* if the flag flip-flop is set */
986                 outbound.signals |= ioSRQ;              /*   then assert SRQ */
987             break;
988 
989 
990         case ioIAK:                                     /* Interrupt Acknowledge */
991             dpc.flag_buffer = CLEAR;                    /* clear the flag buffer flip-flop */
992             break;
993 
994 
995         case ioIEN:                                     /* Interrupt Enable */
996             irq_enabled = TRUE;                         /* permit IRQ to be asserted */
997             break;
998 
999 
1000         case ioPRH:                                         /* Priority High */
1001             if (irq_enabled && outbound.signals & cnIRQ)    /* if IRQ is enabled and conditionally asserted */
1002                 outbound.signals |= ioIRQ | ioFLG;          /*   then assert IRQ and FLG */
1003 
1004             if (!irq_enabled || outbound.signals & cnPRL)   /* if IRQ is disabled or PRL is conditionally asserted */
1005                 outbound.signals |= ioPRL;                  /*   then assert it unconditionally */
1006             break;
1007 
1008 
1009         case ioEDT:                                     /* not used by this interface */
1010         case ioPON:                                     /* not used by this interface */
1011             break;
1012         }
1013 
1014     IOCLEARSIG (working_set, signal);                   /* remove the current signal from the set */
1015     }                                                   /*   and continue until all signals are processed */
1016 
1017 return outbound;                                        /* return the outbound signals and value */
1018 }
1019 
1020 
1021 /* Start data channel operation */
1022 
dp_god(int32 fnc,int32 drv,int32 time)1023 static void dp_god (int32 fnc, int32 drv, int32 time)
1024 {
1025 dpd_unit.DRV = drv;                                     /* save unit */
1026 dpd_unit.FNC = fnc;                                     /* save function */
1027 sim_activate (&dpd_unit, time);
1028 return;
1029 }
1030 
1031 
1032 /* Start controller operation */
1033 
dp_goc(int32 fnc,int32 drv,int32 time)1034 static void dp_goc (int32 fnc, int32 drv, int32 time)
1035 {
1036 int32 t;
1037 
1038 t = sim_activate_time (&dpc_unit[drv]);
1039 if (t) {                                                /* still seeking? */
1040     sim_cancel (&dpc_unit[drv]);                        /* stop seek */
1041     dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY;             /* clear busy */
1042     time = time + t;                                    /* include seek time */
1043     }
1044 dp_ptr = 0;                                             /* init buf ptr */
1045 dpc_eoc = 0;                                            /* clear end cyl */
1046 dpc_busy = drv + 1;                                     /* set busy */
1047 dpd_xfer = 1;                                           /* xfer in prog */
1048 dpc_unit[drv].FNC = fnc;                                /* save function */
1049 dpc_sta[drv] &= ~(STA_ATN | STA_1ST);                   /* clear Attention and First Status */
1050 sim_activate (&dpc_unit[drv], time);                    /* activate unit */
1051 return;
1052 }
1053 
1054 
1055 /* Data channel unit service
1056 
1057    This routine handles the data channel transfers.  It also handles
1058    data transfers that are blocked by seek in progress.
1059 
1060    uptr->DRV    =       target drive
1061    uptr->FNC    =       target function
1062 
1063    Seek substates
1064         seek    -       transfer cylinder
1065         seek1   -       transfer head/surface
1066    Address record
1067         ar      -       transfer cylinder
1068         ar1     -       transfer head/surface, finish operation
1069    Status check -       transfer status, finish operation
1070    Check data
1071         chk     -       transfer sector count
1072 
1073    The 12557A clears controller status after a Check Status command.  The 13210A
1074    does not; however, the selected drive's Attention and First Status
1075    flip-flops are cleared by a status request..
1076 */
1077 
dpd_svc(UNIT * uptr)1078 static t_stat dpd_svc (UNIT *uptr)
1079 {
1080 int32 i, drv, st;
1081 
1082 drv = uptr->DRV;                                        /* get drive no */
1083 switch (uptr->FNC) {                                    /* case function */
1084 
1085     case FNC_AR:                                        /* arec, need cyl */
1086     case FNC_SEEK:                                      /* seek, need cyl */
1087         if (dpd.command) {                              /* dch active? */
1088             dpc_rarc = DA_GETCYL (dpd_obuf);            /* set RAR from cyl word */
1089             dpd_wval = 0;                               /* clr data valid */
1090 
1091             dpd.command = CLEAR;                        /* clr dch cmd */
1092             dpd.flag_buffer = SET;                      /* set the flag buffer */
1093             io_assert (&dpd_dev, ioa_ENF);              /*   and flag flip-flops */
1094 
1095             if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1;
1096             else uptr->FNC = FNC_SEEK1;                 /* advance state */
1097             }
1098         sim_activate (uptr, dpc_xtime);                 /* no, wait more */
1099         break;
1100 
1101     case FNC_AR1:                                       /* arec, need hd/sec */
1102     case FNC_SEEK1:                                     /* seek, need hd/sec */
1103         if (dpd.command) {                              /* dch active? */
1104             dpc_rarh = DA_GETHD (dpd_obuf);             /* set RAR from head */
1105             dpc_rars = DA_GETSC (dpd_obuf);             /* set RAR from sector */
1106             dpd_wval = 0;                               /* clr data valid */
1107 
1108             dpd.command = CLEAR;                        /* clr dch cmd */
1109             dpd.flag_buffer = SET;                      /* set the flag buffer */
1110             io_assert (&dpd_dev, ioa_ENF);              /*   and flag flip-flops */
1111 
1112             if (uptr->FNC == FNC_AR1) {
1113                 dpc.command = CLEAR;                    /* clr cch cmd */
1114                 dpc.flag_buffer = SET;                  /* set the flag buffer */
1115                 io_assert (&dpc_dev, ioa_ENF);          /*   and flag flip-flops */
1116 
1117                 dpc_sta[drv] = dpc_sta[drv] | STA_ATN;  /* set drv attn */
1118                 break;                                  /* done if Address Record */
1119                 }
1120             if (sim_is_active (&dpc_unit[drv])) {       /* if busy, */
1121                 dpc_sta[drv] = dpc_sta[drv] | STA_SKE;  /* seek check */
1122                 break;                                  /* allow prev seek to cmpl */
1123                 }
1124             if ((dpc_rarc >= DP_NUMCY) ||               /* invalid cyl? */
1125                 ((dp_ctype == A13210) &&                /*   or 13210A */
1126                  (dpc_rars >= DP_NUMSC3))) {            /*   and invalid sector? */
1127                 dpc_sta[drv] = dpc_sta[drv] | STA_SKE;  /* seek check */
1128                 sim_activate (&dpc_unit[drv], 1);       /* schedule drive no-wait */
1129                 dpc_unit[drv].FNC = FNC_SEEK3;          /* do immed compl w/poll */
1130                 break;
1131                 }
1132             st = abs (dpc_rarc - dpc_ucyl[drv]) * dpc_stime;
1133             if (st == 0) st = dpc_stime;                /* min time */
1134             dpc_ucyl[drv] = dpc_rarc;                   /* transfer RAR */
1135             sim_activate (&dpc_unit[drv], st);          /* schedule drive */
1136             dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) &
1137                 ~(STA_SKE | STA_SKI | STA_HUNT);
1138             dpc_unit[drv].FNC = FNC_SEEK2;              /* set operation */
1139             }
1140         else sim_activate (uptr, dpc_xtime);            /* no, wait more */
1141         break;
1142 
1143     case FNC_STA:                                       /* read status */
1144         if (dpd.command || (dp_ctype == A13210)) {      /* dch act or 13210? */
1145             if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) {  /* drive up? */
1146                 dpd_ibuf = dpc_sta[drv] & ~STA_ERR;     /* clear err */
1147                 if (dp_ctype == A13210) dpd_ibuf =      /* 13210? */
1148                     (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) |
1149                     (dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0);
1150                 }
1151             else dpd_ibuf = STA_UNLOADED;               /* not ready */
1152             if (dpd_ibuf & STA_ANYERR)                  /* errors? set flg */
1153                 dpd_ibuf = dpd_ibuf | STA_ERR;
1154 
1155             dpc.command = CLEAR;                        /* clr cch cmd */
1156             dpd.command = CLEAR;                        /* clr dch cmd */
1157             dpd.flag_buffer = SET;                      /* set the flag buffer */
1158             io_assert (&dpd_dev, ioa_ENF);              /*   and flag flip-flops */
1159             }
1160 
1161         if (dp_ctype == A13210)                         /* for the 13210, requesting status */
1162             dpc_sta [drv] &= ~(STA_ATN | STA_1ST);      /*   clears the attention and first status bits */
1163         else
1164             dpc_sta[drv] &=
1165               ~(STA_ATN | STA_1ST | STA_OVR |
1166                 STA_RWU | STA_ACU | STA_EOC |
1167                 STA_AER | STA_FLG | STA_DTE);
1168 
1169         dpc_poll = 1;                                   /* enable polling */
1170         for (i = 0; i < DP_NUMDRV; i++) {               /* loop thru drives */
1171             if (dpc_sta[i] & STA_ATN) {                 /* any ATN set? */
1172                 dpc.flag_buffer = SET;                  /* set the flag buffer */
1173                 io_assert (&dpc_dev, ioa_ENF);          /*   and flag flip-flops */
1174                 break;
1175                 }
1176             }
1177         break;
1178 
1179     case FNC_CHK:                                       /* check, need cnt */
1180         if (dpd.command) {                              /* dch active? */
1181             dpc_cnt = dpd_obuf & DA_CKMASK;             /* get count */
1182             dpd_wval = 0;                               /* clr data valid */
1183             dp_goc (FNC_CHK1, drv, dpc_xtime);          /* sched drv */
1184             }
1185         else sim_activate (uptr, dpc_xtime);            /* wait more */
1186         break;
1187 
1188     default:
1189         return SCPE_IERR;
1190         }
1191 
1192 return SCPE_OK;
1193 }
1194 
1195 
1196 /* Drive unit service
1197 
1198    This routine handles the data transfers.
1199 
1200    Seek substates
1201         seek2   -       done
1202    Refine sector -      erase sector, finish operation
1203    Check data
1204         chk1    -       finish operation
1205    Read
1206    Write
1207 */
1208 
1209 #define GETDA(x,y,z) \
1210     (((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD
1211 
dpc_svc(UNIT * uptr)1212 static t_stat dpc_svc (UNIT *uptr)
1213 {
1214 int32 da, drv, err;
1215 
1216 err = 0;                                                /* assume no err */
1217 drv = uptr - dpc_unit;                                  /* get drive no */
1218 if (uptr->flags & UNIT_UNLOAD) {                        /* drive down? */
1219 
1220     dpc.command = CLEAR;                                /* clr cch cmd */
1221     dpc.flag_buffer = SET;                              /* set the flag buffer */
1222     io_assert (&dpc_dev, ioa_ENF);                      /*   and flag flip-flops */
1223 
1224     dpc_sta[drv] = 0;                                   /* clr status */
1225     dpc_busy = 0;                                       /* ctlr is free */
1226     dpc_poll = 0;                                       /* polling disabled */
1227     dpd_xfer = 0;
1228     dpd_wval = 0;
1229     return SCPE_OK;
1230     }
1231 switch (uptr->FNC) {                                    /* case function */
1232 
1233     case FNC_SEEK2:                                     /* positioning done */
1234         dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY;
1235 
1236     /* fall through into cmpl */
1237 
1238     case FNC_SEEK3:                                     /* seek complete */
1239         if (dpc_poll) {                                 /* polling enabled? */
1240             dpc.command = CLEAR;                        /* clr cch cmd */
1241             dpc.flag_buffer = SET;                      /* set the flag buffer */
1242             io_assert (&dpc_dev, ioa_ENF);              /*   and flag flip-flops */
1243             }
1244         return SCPE_OK;
1245 
1246     case FNC_REF:                                       /* refine sector */
1247         break;                                          /* just a NOP */
1248 
1249     case FNC_RD:                                        /* read */
1250     case FNC_CHK1:                                      /* check */
1251         if (dp_ptr == 0) {                              /* new sector? */
1252             if (!dpd.command && (uptr->FNC != FNC_CHK1)) break;
1253             if (dpc_rarc != dpc_ucyl[drv])              /* RAR cyl miscompare? */
1254                 dpc_sta[drv] = dpc_sta[drv] | STA_AER;  /* set flag, read */
1255             if (dpc_rars >= DP_NUMSC) {                 /* bad sector? */
1256                 dpc_sta[drv] = dpc_sta[drv] | STA_AER;  /* set flag, stop */
1257                 break;
1258                 }
1259             if (dpc_eoc) {                              /* end of cyl? */
1260                 dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
1261                 break;
1262                 }
1263             da = GETDA (dpc_rarc, dpc_rarh, dpc_rars);  /* calc disk addr */
1264             dpc_rars = (dpc_rars + 1) % DP_NUMSC;       /* incr sector */
1265             if (dpc_rars == 0) {                        /* wrap? */
1266                 dpc_rarh = dpc_rarh ^ 1;                /* incr head */
1267                 dpc_eoc = ((dpc_rarh & 1) == 0);        /* calc eoc */
1268                 }
1269             err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);
1270             if (err)                                    /* error? */
1271                  break;
1272             fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
1273             err = ferror (uptr->fileref);
1274             if (err)                                    /* error? */
1275                  break;
1276             }
1277         dpd_ibuf = dpxb[dp_ptr++];                      /* get word */
1278         if (dp_ptr >= DP_NUMWD) {                       /* end of sector? */
1279             if (uptr->FNC == FNC_CHK1) {                /* check? */
1280                 dpc_cnt = (dpc_cnt - 1) & DA_CKMASK;    /* decr count */
1281                 if (dpc_cnt == 0) break;                /* stop at zero */
1282                 }
1283             dp_ptr = 0;                                 /* wrap buf ptr */
1284             }
1285         if (dpd.command && dpd_xfer) {                  /* dch on, xfer? */
1286             dpd.flag_buffer = SET;                      /* set the flag buffer */
1287             io_assert (&dpd_dev, ioa_ENF);              /*   and flag flip-flops */
1288             }
1289 
1290         dpd.command = CLEAR;                            /* clr dch cmd */
1291         sim_activate (uptr, dpc_xtime);                 /* sched next word */
1292         return SCPE_OK;
1293 
1294     case FNC_INIT:                                      /* init */
1295     case FNC_WD:                                        /* write */
1296         if (dp_ptr == 0) {                              /* start sector? */
1297             if (!dpd.command && !dpd_wval) break;       /* xfer done? */
1298             if (uptr->flags & UNIT_WPRT) {              /* wr prot? */
1299                 dpc_sta[drv] = dpc_sta[drv] | STA_FLG;  /* set status */
1300                 break;                                  /* done */
1301                 }
1302             if ((dpc_rarc != dpc_ucyl[drv]) ||          /* RAR cyl miscompare? */
1303                 (dpc_rars >= DP_NUMSC)) {               /* bad sector? */
1304                 dpc_sta[drv] = dpc_sta[drv] | STA_AER;  /* address error */
1305                 break;
1306                 }
1307             if (dpc_eoc) {                              /* end of cyl? */
1308                 dpc_sta[drv] = dpc_sta[drv] | STA_EOC;  /* set status */
1309                 break;                                  /* done */
1310                 }
1311             }
1312         dpxb[dp_ptr++] = dpd_wval ? (uint16) dpd_obuf : 0;  /* store word/fill */
1313         dpd_wval = 0;                                   /* clr data valid */
1314         if (dp_ptr >= DP_NUMWD) {                       /* buffer full? */
1315             da = GETDA (dpc_rarc, dpc_rarh, dpc_rars);  /* calc disk addr */
1316             dpc_rars = (dpc_rars + 1) % DP_NUMSC;       /* incr sector */
1317             if (dpc_rars == 0) {                        /* wrap? */
1318                 dpc_rarh = dpc_rarh ^ 1;                /* incr head */
1319                 dpc_eoc = ((dpc_rarh & 1) == 0);        /* calc eoc */
1320                 }
1321             err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);
1322             if (err)                                    /* error? */
1323                  break;
1324             fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
1325             err = ferror (uptr->fileref);
1326             if (err)                                    /* error? */
1327                  break;
1328             dp_ptr = 0;                                 /* next sector */
1329             }
1330         if (dpd.command && dpd_xfer) {                  /* dch on, xfer? */
1331             dpd.flag_buffer = SET;                      /* set the flag buffer */
1332             io_assert (&dpd_dev, ioa_ENF);              /*   and flag flip-flops */
1333             }
1334 
1335         dpd.command = CLEAR;                            /* clr dch cmd */
1336         sim_activate (uptr, dpc_xtime);                 /* sched next word */
1337         return SCPE_OK;
1338 
1339     default:
1340         return SCPE_IERR;
1341         }                                               /* end case fnc */
1342 
1343 dpc_sta[drv] = dpc_sta[drv] | STA_ATN;                  /* set ATN */
1344 
1345 dpc.command = CLEAR;                                    /* clr cch cmd */
1346 dpc.flag_buffer = SET;                                  /* set the flag buffer */
1347 io_assert (&dpc_dev, ioa_ENF);                          /*   and flag flip-flops */
1348 
1349 dpc_busy = 0;                                           /* ctlr is free */
1350 dpd_xfer = dpd_wval = 0;
1351 
1352 if (err != 0) {                                         /* error? */
1353     cprintf ("%s simulator DP disc I/O error: %s\n",    /*   then report the error to the console */
1354              sim_name, strerror (errno));
1355 
1356     clearerr (uptr->fileref);                           /* clear the error */
1357     return SCPE_IOERR;
1358     }
1359 return SCPE_OK;
1360 }
1361 
1362 
1363 /* Reset routine */
1364 
dpc_reset(DEVICE * dptr)1365 static t_stat dpc_reset (DEVICE *dptr)
1366 {
1367 int32 drv;
1368 
1369 hp_enbdis_pair (dptr,                                   /* make pair cons */
1370     (dptr == &dpd_dev) ? &dpc_dev : &dpd_dev);
1371 
1372 if (sim_switches & SWMASK ('P')) {                      /* initialization reset? */
1373     dpd_ibuf = dpd_obuf = 0;                            /* clear buffers */
1374     dpc_obuf = 0;                                       /* clear buffer */
1375     dpc_rarc = dpc_rarh = dpc_rars = 0;                 /* clear RAR */
1376     }
1377 
1378 io_assert (dptr, ioa_POPIO);                            /* PRESET the device */
1379 
1380 dpc_busy = 0;                                           /* reset controller state */
1381 dpc_poll = 0;
1382 dpd_xfer = 0;
1383 dpd_wval = 0;
1384 dpc_eoc = 0;
1385 dp_ptr = 0;
1386 
1387 sim_cancel (&dpd_unit);                                 /* cancel dch */
1388 
1389 for (drv = 0; drv < DP_NUMDRV; drv++) {                 /* loop thru drives */
1390     sim_cancel (&dpc_unit[drv]);                        /* cancel activity */
1391     dpc_unit[drv].FNC = 0;                              /* clear function */
1392     dpc_ucyl[drv] = 0;                                  /* clear drive pos */
1393     if (dpc_unit[drv].flags & UNIT_ATT)
1394         dpc_sta[drv] = dpc_sta[drv] & STA_1ST;          /* first seek status */
1395     else dpc_sta[drv] = 0;                              /* clear status */
1396     }
1397 
1398 return SCPE_OK;
1399 }
1400 
1401 
1402 /* Attach a drive unit.
1403 
1404    The specified file is attached to the indicated drive unit, and the heads are
1405    loaded, which will will set the First Status and Attention bits in the drive
1406    status.  If a new file is specified, the file is initialized to its capacity
1407    by writing a zero to the last byte in the file.
1408 
1409 
1410    Implementation notes:
1411 
1412     1. The C standard says, "A binary stream need not meaningfully support fseek
1413        calls with a whence value of SEEK_END," so instead we determine the
1414        offset from the start of the file to the last byte and seek there.
1415 */
1416 
dpc_attach(UNIT * uptr,char * cptr)1417 static t_stat dpc_attach (UNIT *uptr, char *cptr)
1418 {
1419 t_stat      result;
1420 t_addr      offset;
1421 const uint8 zero = 0;
1422 
1423 result = attach_unit (uptr, cptr);                      /* attach the drive */
1424 
1425 if (result == SCPE_OK) {                                /* if the attach was successful */
1426     dpc_load_unload (uptr, 0, NULL, NULL);              /*   then load the heads */
1427 
1428     if (sim_switches & SWMASK ('N')) {                  /* if this is a new disc image */
1429         offset = (t_addr)                               /*   then determine the offset of */
1430           (uptr->capac * sizeof (int16) - sizeof zero); /*     the last byte in a full-sized file */
1431 
1432         if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0    /* seek to the last byte */
1433           || fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /*   and write a zero to fill */
1434           || fflush (uptr->fileref) != 0)                       /*     the file to its capacity */
1435             clearerr (uptr->fileref);                           /* clear and ignore any errors */
1436         }
1437     }
1438 
1439 return result;                                          /* return the result of the attach */
1440 }
1441 
1442 
1443 /* Detach routine */
1444 
dpc_detach(UNIT * uptr)1445 static t_stat dpc_detach (UNIT* uptr)
1446 {
1447 dpc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL);        /* unload heads */
1448 return detach_unit (uptr);                              /* detach unit */
1449 }
1450 
1451 
1452 /* Load and unload heads */
1453 
dpc_load_unload(UNIT * uptr,int32 value,char * cptr,void * desc)1454 static t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)
1455 {
1456 int32 drv;
1457 
1458 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;   /* must be attached to load */
1459 
1460 if (value == UNIT_UNLOAD)                               /* unload heads? */
1461     uptr->flags = uptr->flags | UNIT_UNLOAD;            /* indicate unload */
1462 else {                                                  /* load heads */
1463     uptr->flags = uptr->flags & ~UNIT_UNLOAD;           /* indicate load */
1464     drv = uptr - dpc_unit;                              /* get drive no */
1465     dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST;    /* update status */
1466     if (dpc_poll) {                                     /* polling enabled? */
1467         dpc.flag_buffer = SET;                          /* set the flag buffer */
1468         io_assert (&dpc_dev, ioa_ENF);                  /*   and flag flip-flops */
1469         }
1470     }
1471 return SCPE_OK;
1472 }
1473 
1474 
1475 /* Set controller type */
1476 
dp_settype(UNIT * uptr,int32 val,char * cptr,void * desc)1477 static t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
1478 {
1479 int32 i;
1480 
1481 if ((val < 0) || (val > 1) || (cptr != NULL))
1482     return SCPE_ARG;
1483 
1484 for (i = 0; i < DP_NUMDRV; i++) {
1485     if (dpc_unit[i].flags & UNIT_ATT)
1486         return SCPE_ALATT;
1487     }
1488 
1489 for (i = 0; i < DP_NUMDRV; i++)
1490     dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2);
1491 
1492 dp_ctype = (CNTLR_TYPE) val;
1493 return SCPE_OK;
1494 }
1495 
1496 
1497 /* Show controller type */
1498 
dp_showtype(FILE * st,UNIT * uptr,int32 val,void * desc)1499 static t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
1500 {
1501 if (dp_ctype == A13210)
1502     fprintf (st, "13210A");
1503 else
1504     fprintf (st, "12557A");
1505 
1506 return SCPE_OK;
1507 }
1508 
1509 
1510 /* 7900/2870 disc bootstrap loaders (BMDL and 12992F).
1511 
1512    The Basic Moving-Head Disc Loader (BMDL) consists of two programs.  The
1513    program starting at address x7700 loads absolute paper tapes into memory.
1514    The program starting at address x7750 loads a disc-resident bootstrap from
1515    the 7900 or 2870 disc drive into memory.  The S register setting does not
1516    affect loader operation.
1517 
1518    For a 2100/14/15/16 CPU, entering a LOAD DPC or BOOT DPC command loads the
1519    BMDL into memory and executes the disc portion starting at x7750.  The
1520    bootstrap reads 6144 (for a 7900) or 3072 (for a 2870) words from cylinder 0,
1521    head 0, sector 0 into memory starting at location 2011 octal.  Loader
1522    execution ends with the following instruction:
1523 
1524      * JSB 2055,I - the disc read completed.
1525 
1526    The BMDL configures DMA for an oversize (~32000 word) transfer and expects
1527    the disc to terminate the operation with End of Cylinder (EOC) status.
1528 
1529    The HP 1000 uses the 12992F boot loader ROM to bootstrap the 7900 disc.  Bit
1530    0 of the S register determines whether the boot extension is read from
1531    subchannel 0 (the fixed platter) or subchannel 1 (the removable platter).
1532    The loader reads 6144 words from cylinder 0 sector 0 of the specified
1533    subchannel into memory starting at location 2011 octal.  Loader execution
1534    ends with one of the following instructions:
1535 
1536      * HLT 30     - a drive fault occurred.
1537      * JSB 2055,I - the disc read succeeded.
1538 
1539    The loader automatically retries the operations for all disc errors other
1540    than a drive fault.
1541 
1542 
1543    Implementation notes:
1544 
1545     1. After the BMDL has been loaded into memory, the paper tape portion may be
1546        executed manually by setting the P register to the starting address
1547        (x7700).
1548 
1549     2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
1550        instructions address select codes 10 and 11.
1551 
1552     3. As published, the BMDL is configured to read from head 0 (the removable
1553        platter, a.k.a. subchannel 1).  To read from head 2 (the fixed platter,
1554        subchannel 0), the head/sector control word must be changed.
1555 */
1556 
1557 #define BMDL_SUBCHANNEL_0   031000              /* BMDL control word to address subchannel 0 instead of 1 */
1558 
1559 static const LOADER_ARRAY dp_loaders = {
1560     {                               /* HP 21xx Basic Moving-Head Disc Loader (BMDL-7900) */
1561       050,                          /*   loader starting index */
1562       077,                          /*   DMA index */
1563       034,                          /*   FWA index */
1564       { 0002401,                    /*   77700:  PTAPE CLA,RSS             Paper Tape start */
1565         0063721,                    /*   77701:        LDA 77721           */
1566         0107700,                    /*   77702:        CLC 0,C             */
1567         0002307,                    /*   77703:        CCE,INA,SZA,RSS     */
1568         0102077,                    /*   77704:        HLT 77              */
1569         0017735,                    /*   77705:        JSB 77735           */
1570         0007307,                    /*   77706:        CMB,CCE,INB,SZB,RSS */
1571         0027702,                    /*   77707:        JMP 77702           */
1572         0077733,                    /*   77710:        STB 77733           */
1573         0017735,                    /*   77711:        JSB 77735           */
1574         0017735,                    /*   77712:        JSB 77735           */
1575         0074000,                    /*   77713:        STB 0               */
1576         0077747,                    /*   77714:        STB 77747           */
1577         0047734,                    /*   77715:        ADB 77734           */
1578         0002140,                    /*   77716:        SEZ,CLE             */
1579         0102055,                    /*   77717:        HLT 55              */
1580         0017735,                    /*   77720:        JSB 77735           */
1581         0177747,                    /*   77721:        STB 77747,I         */
1582         0040001,                    /*   77722:        ADA 1               */
1583         0067747,                    /*   77723:        LDB 77747           */
1584         0006104,                    /*   77724:        CLE,INB             */
1585         0037733,                    /*   77725:        ISZ 77733           */
1586         0027714,                    /*   77726:        JMP 77714           */
1587         0017735,                    /*   77727:        JSB 77735           */
1588         0054000,                    /*   77730:        CPB 0               */
1589         0027701,                    /*   77731:        JMP 77701           */
1590         0102011,                    /*   77732:        HLT 11              */
1591         0000000,                    /*   77733:        OCT 000000          */
1592         0100100,                    /*   77734:        OCT 1n0100          */
1593         0000000,                    /*   77735:        NOP                 */
1594         0006400,                    /*   77736:        CLB                 */
1595         0103710,                    /*   77737:        STC 10,C            */
1596         0102310,                    /*   77740:        SFS 10              */
1597         0027740,                    /*   77741:        JMP 77740           */
1598         0107410,                    /*   77742:        MIB 10,C            */
1599         0002240,                    /*   77743:        SEZ,CME             */
1600         0127735,                    /*   77744:        JMP 77735,I         */
1601         0005727,                    /*   77745:        BLF,BLF             */
1602         0027737,                    /*   77746:        JMP 77737           */
1603         0000000,                    /*   77747:        OCT 000000          */
1604         0030000,                    /*   77750:  DISC  IOR 0               Disc start */
1605         0067741,                    /*   77751:        LDB 77741           */
1606         0106611,                    /*   77752:        OTB 11              */
1607         0103711,                    /*   77753:        STC 11,C            */
1608         0063750,                    /*   77754:        LDA 77750           */
1609         0102610,                    /*   77755:        OTA 10              */
1610         0103710,                    /*   77756:        STC 10,C            */
1611         0102611,                    /*   77757:        OTA 11              */
1612         0103711,                    /*   77760:        STC 11,C            */
1613         0063777,                    /*   77761:        LDA 77777           */
1614         0102606,                    /*   77762:        OTA 6               */
1615         0063732,                    /*   77763:        LDA 77732           */
1616         0102602,                    /*   77764:        OTA 2               */
1617         0103710,                    /*   77765:        STC 10,C            */
1618         0102702,                    /*   77766:        STC 2               */
1619         0102602,                    /*   77767:        OTA 2               */
1620         0106611,                    /*   77770:        OTB 11              */
1621         0103710,                    /*   77771:        STC 10,C            */
1622         0103706,                    /*   77772:        STC 6,C             */
1623         0103711,                    /*   77773:        STC 11,C            */
1624         0102311,                    /*   77774:        SFS 11              */
1625         0027774,                    /*   77775:        JMP 77774           */
1626         0117717,                    /*   77776:        JSB 77717,I         */
1627         0120010 } },                /*   77777:        OCT 120010          */
1628 
1629     {                               /* HP 1000 Loader ROM (12992F) */
1630       IBL_START,                    /*   loader starting index */
1631       IBL_DMA,                      /*   DMA index */
1632       IBL_FWA,                      /*   FWA index */
1633       { 0106710,                    /*   77700:  ST    CLC DC             ; clr dch */
1634         0106711,                    /*   77701:        CLC CC             ; clr cch */
1635         0017757,                    /*   77702:        JSB STAT           ; get status */
1636         0067746,                    /*   77703:  SK    LDB SKCMD          ; seek cmd */
1637         0106610,                    /*   77704:        OTB DC             ; cyl # */
1638         0103710,                    /*   77705:        STC DC,C           ; to dch */
1639         0106611,                    /*   77706:        OTB CC             ; seek cmd */
1640         0103711,                    /*   77707:        STC CC,C           ; to cch */
1641         0102310,                    /*   77710:        SFS DC             ; addr wd ok? */
1642         0027710,                    /*   77711:        JMP *-1            ; no, wait */
1643         0006400,                    /*   77712:        CLB                */
1644         0102501,                    /*   77713:        LIA 1              ; read switches */
1645         0002011,                    /*   77714:        SLA,RSS            ; <0> set? */
1646         0047747,                    /*   77715:        ADB BIT9           ; head 2 = removable */
1647         0106610,                    /*   77716:        OTB DC             ; head/sector */
1648         0103710,                    /*   77717:        STC DC,C           ; to dch */
1649         0102311,                    /*   77720:        SFS CC             ; seek done? */
1650         0027720,                    /*   77721:        JMP *-1            ; no, wait */
1651         0017757,                    /*   77722:        JSB STAT           ; get status */
1652         0067776,                    /*   77723:        LDB DMACW          ; DMA control */
1653         0106606,                    /*   77724:        OTB 6              */
1654         0067750,                    /*   77725:        LDB ADDR1          ; memory addr */
1655         0106602,                    /*   77726:        OTB 2              */
1656         0102702,                    /*   77727:        STC 2              ; flip DMA ctrl */
1657         0067752,                    /*   77730:        LDB CNT            ; word count */
1658         0106602,                    /*   77731:        OTB 2              */
1659         0063745,                    /*   77732:        LDB RDCMD          ; read cmd */
1660         0102611,                    /*   77733:        OTA CC             ; to cch */
1661         0103710,                    /*   77734:        STC DC,C           ; start dch */
1662         0103706,                    /*   77735:        STC 6,C            ; start DMA */
1663         0103711,                    /*   77736:        STC CC,C           ; start cch */
1664         0102311,                    /*   77737:        SFS CC             ; done? */
1665         0027737,                    /*   77740:        JMP *-1            ; no, wait */
1666         0017757,                    /*   77741:        JSB STAT           ; get status */
1667         0027775,                    /*   77742:        JMP XT             ; done */
1668         0037766,                    /*   77743:  FSMSK OCT 037766         ; status mask */
1669         0004000,                    /*   77744:  STMSK OCT 004000         ; unsafe mask */
1670         0020000,                    /*   77745:  RDCMD OCT 020000         ; read cmd */
1671         0030000,                    /*   77746:  SKCMD OCT 030000         ; seek cmd */
1672         0001000,                    /*   77747:  BIT9  OCT 001000         ; head 2 select */
1673         0102011,                    /*   77750:  ADDR1 OCT 102011         */
1674         0102055,                    /*   77751:  ADDR2 OCT 102055         */
1675         0164000,                    /*   77752:  CNT   DEC -6144.         */
1676         0000000,                    /*   77753:        NOP                */
1677         0000000,                    /*   77754:        NOP                */
1678         0000000,                    /*   77755:        NOP                */
1679         0000000,                    /*   77756:        NOP                */
1680         0000000,                    /*   77757:  STAT  NOP                */
1681         0002400,                    /*   77760:        CLA                ; status request */
1682         0102611,                    /*   77761:        OTC CC             ; to cch */
1683         0103711,                    /*   77762:        STC CC,C           ; start cch */
1684         0102310,                    /*   77763:        SFS DC             ; done? */
1685         0027763,                    /*   77764:        JMP *-1            */
1686         0102510,                    /*   77765:        LIA DC             ; get status */
1687         0013743,                    /*   77766:        AND FSMSK          ; mask 15,14,3,0 */
1688         0002003,                    /*   77767:        SZA,RSS            ; drive ready? */
1689         0127757,                    /*   77770:        JMP STAT,I         ; yes */
1690         0013744,                    /*   77771:        AND STMSK          ; fault? */
1691         0002002,                    /*   77772:        SZA                */
1692         0102030,                    /*   77773:        HLT 30             ; yes */
1693         0027700,                    /*   77774:        JMP ST             ; no, retry */
1694         0117751,                    /*   77775:  XT    JSB ADDR2,I        ; start program */
1695         0120010,                    /*   77776:  DMACW ABS 120000+DC      */
1696         0000000 } }                 /*   77777:        ABS -ST            */
1697     };
1698 
1699 
1700 /* Device boot routine.
1701 
1702    This routine is called directly by the BOOT DPC and LOAD DPC commands to copy
1703    the device bootstrap into the upper 64 words of the logical address space.
1704    It is also called indirectly by a BOOT CPU or LOAD CPU command when the
1705    specified HP 1000 loader ROM socket contains a 12992F ROM.
1706 
1707    When called in response to a BOOT DPC or LOAD DPC command, the "unitno"
1708    parameter indicates the unit number specified in the BOOT command or is zero
1709    for the LOAD command, and "dptr" points at the DPC device structure.  The
1710    bootstrap supports loading only from unit 0, and the command will be rejected
1711    if another unit is specified (e.g., BOOT DPC1).  Otherwise, depending on the
1712    current CPU model, the BMDL or 12992F loader ROM will be copied into memory
1713    and configured for the DPD/DPC select code pair.  If the CPU is a 1000, the S
1714    register will be set as it would be by the front-panel microcode.
1715 
1716    When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
1717    select code to be used for configuration, and "dptr" will be NULL.  As above,
1718    the BMDL or 12992F loader ROM will be copied into memory and configured for
1719    the specified select code.  The S register is assumed to be set correctly on
1720    entry and is not modified.
1721 
1722    In either case, if the CPU is a 21xx model, the paper tape portion of the
1723    BMDL will be automatically configured for the select code of the paper tape
1724    reader.
1725 
1726    For the 12992F boot loader ROM for the HP 1000, the S register is set as
1727    follows:
1728 
1729       15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
1730      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1731      | ROM # | 0   0 |      select code      | reserved  | 0   0 | S |
1732      +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1733 
1734    Where:
1735 
1736      S = the subchannel number
1737 
1738    Bit 0 specifies the subchannel containing the operating system.  For the
1739    7900, either the fixed (0) or removable (1) platter may be specified.  For
1740    the 7901, bit 0 must be 1.  If the -R switch is specified for the BOOT or
1741    LOAD command, the loader ROM will be configured to boot from the removable
1742    platter instead of the fixed platter.
1743 
1744    Bits 5-3 are nominally zero but are reserved for the target operating system.
1745    For example, RTE uses bit 5 to indicate whether a standard (0) or
1746    reconfiguration (1) boot is desired.
1747 
1748 
1749    Implementation notes:
1750 
1751     1. In hardware, the BMDL was hand-configured for the disc and paper tape
1752        reader select codes when it was installed on a given system.  Under
1753        simulation, the LOAD and BOOT commands automatically configure the BMDL
1754        to the current select codes of the PTR and DP devices.
1755 
1756     2. As installed, the BMDL is configured to read from the removable platter
1757        (a.k.a. subchannel 1).  If the -R switch is specified to read from the
1758        fixed platter (subchannel 0), the head number in the head/sector control
1759        word in memory is changed from 0 to 2.
1760 */
1761 
dpc_boot(int32 unitno,DEVICE * dptr)1762 static t_stat dpc_boot (int32 unitno, DEVICE *dptr)
1763 {
1764 static const HP_WORD dp_preserved = 0000070u;                   /* S-register bits 5-3 are preserved */
1765 const uint32 subchannel = sim_switches & SWMASK ('R') ? 1 : 0;  /* the selected boot subchannel */
1766 uint32 start;
1767 
1768 if (dptr == NULL)                                           /* if we are being called for a BOOT/LOAD CPU */
1769     start = cpu_copy_loader (dp_loaders, unitno,            /*   then copy the boot loader to memory */
1770                              IBL_S_NOCLEAR, IBL_S_NOSET);   /*     but do not alter the S register */
1771 
1772 else if (unitno != 0)                                       /* otherwise a BOOT DPC for a non-zero unit */
1773     return SCPE_NOFNC;                                      /*   is rejected as unsupported */
1774 
1775 else                                                            /* otherwise this is a BOOT/LOAD DPC */
1776     start = cpu_copy_loader (dp_loaders, dpd_dib.select_code,   /*   so copy the boot loader to memory */
1777                              dp_preserved, subchannel);         /*     and configure the S register if 1000 CPU */
1778 
1779 if (start == 0)                                         /* if the copy failed */
1780     return SCPE_NOFNC;                                  /*   then reject the command */
1781 
1782 else {                                                      /* otherwise */
1783     if (subchannel == 0                                     /*   if the boot is from subchannel 0 */
1784       && (start & IBL_MASK) == dp_loaders [0].start_index)  /*     and the BMDL was installed */
1785         mem_deposit (start, BMDL_SUBCHANNEL_0);             /*       then change the control word to use head 2 */
1786 
1787     return SCPE_OK;                                         /* the boot loader was successfully copied */
1788     }
1789 }
1790