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