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