1 /* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator
2
3 Copyright (c) 2004-2012, Robert M. Supnik
4 Copyright (c) 2012-2021, 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 DS 13037D/13175D disc controller/interface
28
29 09-Apr-21 JDB Replaced "find_reg" call with inline search in "ds_reset"
30 02-Apr-21 JDB Changed u3-u6 synonyms to title case to avoid conflicts
31 09-Dec-20 JDB Replaced "io_assert" with "io_assert_ENF/SIR"
32 02-Dec-20 JDB RESET no longer presets the interface
33 13-Jun-18 JDB Revised I/O model
34 07-May-18 JDB Removed "dl_clear_controller" status return
35 27-Feb-18 JDB Added the BMDL
36 21-Feb-18 JDB ATTACH -N now creates a full-size disc image
37 11-Jul-17 JDB Renamed "ibl_copy" to "cpu_ibl"
38 15-Mar-17 JDB Trace flags are now global
39 Changed DEBUG_PRI calls to tprintfs
40 10-Mar-17 JDB Added IOBUS to the debug table
41 09-Mar-17 JDB Deprecated LOCKED/WRITEENABLED for PROTECT/UNPROTECT
42 13-May-16 JDB Modified for revised SCP API function parameter types
43 04-Mar-16 JDB Name changed to "hp2100_disclib" until HP 3000 integration
44 30-Dec-14 JDB Added S-register parameters to ibl_copy
45 24-Dec-14 JDB Use T_ADDR_FMT with t_addr values for 64-bit compatibility
46 18-Mar-13 JDB Fixed poll_drives definition to match declaration
47 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash
48 29-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library
49 ioIOO now notifies controller service of parameter output
50 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection
51 Corrected Clear command to conform to the hardware
52 Fixed Request Status to return Unit Unavailable if illegal
53 Seek and Cold Load Read now Seek Check if seek in progress
54 Remodeled command wait for seek completion
55 10-Feb-12 JDB Deprecated DEVNO in favor of SC
56 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek
57 beyond drive limits, Request Sector Address and Wakeup
58 with invalid or offline unit
59 Address verification reenabled if auto-seek during
60 Read Without Verify
61 28-Mar-11 JDB Tidied up signal handling
62 26-Oct-10 JDB Changed I/O signal handler for revised signal model
63 26-Jun-08 JDB Rewrote device I/O to model backplane signals
64 31-Dec-07 JDB Corrected and verified ioCRS action
65 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA
66 28-Dec-06 JDB Added ioCRS state to I/O decoders
67 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1
68 Removed redundant attached test in "ds_detach"
69 18-Mar-05 RMS Added attached test to detach routine
70 01-Mar-05 JDB Added SET UNLOAD/LOAD
71
72 References:
73 - 13037 Disc Controller Technical Information Package
74 (13037-90902, August 1980)
75 - 7925D Disc Drive Service Manual
76 (07925-90913, April 1984)
77 - HP 12992 Loader ROMs Installation Manual
78 (12992-90001, April 1986)
79 - DVR32 RTE Moving Head Driver source
80 (92084-18711, Revision 5000)
81
82
83 The 13037D multiple-access (MAC) disc controller supports from one to eight
84 HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives
85 accessed by one to eight CPUs. The controller hardware consists of a 16-bit
86 microprogrammed processor constructed from 74S181 bit slices operating at 5
87 MHz, a device controller providing the interconnections to the drives and CPU
88 interfaces, and an error correction controller that enables the correction of
89 up to 32-bit error bursts. 1024 words of 24-bit firmware are stored in ROM.
90
91 The 13175D disc interface is used to connect the HP 1000 CPU to the 13037
92 device controller. In a multiple-CPU system, one interface is strapped to
93 reset the controller when the CPU's front panel PRESET button is pressed.
94
95 This module simulates a 13037D connected to a single 13175D interface. From
96 one to eight drives may be connected, and drive types may be freely
97 intermixed. A unit that is enabled but not attached appears to be a
98 connected drive that does not have a disc pack in place. A unit that is
99 disabled appears to be disconnected.
100
101 This simulator is an adaptation of the code originally written by Bob Supnik.
102 The functions of the controller have been separated from the functions of the
103 interface, with the former placed into a separate disc controller library.
104 This allows the library to support other CPU interfaces, such as the 12821A
105 HP-IB disc interface, that use substantially different communication
106 protocols. The library functions implement the controller command set for
107 the drive units. The interface functions handle the transfer of commands and
108 data to and from the CPU.
109
110 In hardware, the controller runs continuously in one of three states: in the
111 Poll Loop (idle state), in the Command Wait Loop (wait state), or in command
112 execution (busy state). In simulation, the controller is run only when a
113 command is executing or when a transition into or out of the two loops might
114 occur. Internally, the controller handles these transitions:
115
116 - when a command other than End terminates (busy => wait)
117 - when the End command terminates (busy => idle)
118 - when a command timeout occurs (wait => idle)
119 - when a parameter timeout occurs (busy => idle)
120 - when a seek completes (if idle and interrupts are enabled, idle => wait)
121
122 The interface must call the controller library to handle these transitions:
123
124 - when a command is received from the CPU (idle or wait => busy)
125 - when interrupts are enabled (if idle and drive Attention, idle => wait)
126
127 In addition, each transition to the wait state must check for a pending
128 command, and each transition to the idle state must check for both a pending
129 command and a drive with Attention status asserted.
130
131
132 Implementation notes:
133
134 1. Although the 13175D has a 16-word FIFO, the "full" level is set at 5
135 entries in hardware to avoid a long DCPC preemption time at the start of
136 a disc write as the FIFO fills.
137 */
138
139
140
141 #include "hp2100_defs.h"
142 #include "hp2100_io.h"
143 #include "hp2100_disclib.h"
144
145
146
147 /* Program constants */
148
149 #define DS_DRIVES (DL_MAXDRIVE + 1) /* number of disc drive units */
150 #define DS_UNITS (DS_DRIVES + DL_AUXUNITS) /* total number of units */
151
152 #define ds_cntlr ds_unit [DL_MAXDRIVE + 1] /* controller unit alias */
153
154 #define FIFO_SIZE 16 /* FIFO depth */
155
156 #define FIFO_EMPTY (ds.fifo_count == 0) /* FIFO empty test */
157 #define FIFO_STOP (ds.fifo_count >= 5) /* FIFO stop filling test */
158 #define FIFO_FULL (ds.fifo_count == FIFO_SIZE) /* FIFO full test */
159
160 #define PRESET_ENABLE TRUE /* Preset Jumper (W4) is enabled */
161
162
163 /* Per-card state variables */
164
165 typedef struct {
166 FLIP_FLOP control; /* control flip-flop */
167 FLIP_FLOP flag; /* flag flip-flop */
168 FLIP_FLOP flag_buffer; /* flag buffer flip-flop */
169 FLIP_FLOP srq; /* SRQ flip-flop */
170 FLIP_FLOP edt; /* EDT flip-flop */
171 FLIP_FLOP cmfol; /* command follows flip-flop */
172 FLIP_FLOP cmrdy; /* command ready flip-flop */
173 uint16 fifo [FIFO_SIZE]; /* FIFO buffer */
174 uint32 fifo_count; /* FIFO occupancy counter */
175 REG *fifo_reg; /* FIFO register pointer */
176 } CARD_STATE;
177
178
179 /* MAC disc state variables */
180
181 static UNIT ds_unit [DS_UNITS]; /* unit array */
182
183 static CARD_STATE ds; /* card state */
184
185 static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */
186
187 static CNTLR_VARS mac_cntlr = /* MAC controller */
188 { CNTLR_INIT (MAC, buffer, &ds_cntlr) };
189
190
191
192 /* Interface local SCP support routines */
193
194 static IO_INTERFACE ds_interface;
195
196
197 /* Interface local SCP support routines */
198
199 static t_stat ds_service_drive (UNIT *uptr);
200 static t_stat ds_service_controller (UNIT *uptr);
201 static t_stat ds_service_timer (UNIT *uptr);
202 static t_stat ds_reset (DEVICE *dptr);
203 static t_stat ds_attach (UNIT *uptr, char *cptr);
204 static t_stat ds_detach (UNIT *uptr);
205 static t_stat ds_boot (int32 unitno, DEVICE *dptr);
206 static t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);
207
208
209 /* MAC disc local utility routines */
210
211 static void start_command (void);
212 static void poll_interface (void);
213 static void poll_drives (void);
214 static void fifo_load (uint16 data);
215 static uint16 fifo_unload (void);
216 static void fifo_clear (void);
217 static t_stat activate_unit (UNIT *uptr);
218
219
220 /* Interface SCP data structures */
221
222
223 /* Device information block */
224
225 static DIB ds_dib = {
226 &ds_interface, /* the device's I/O interface function pointer */
227 NULL, /* the power state function pointer */
228 DS, /* the device's select code (02-77) */
229 0, /* the card index */
230 "13175D Disc Controller Interface", /* the card description */
231 "12992B 7905/7906/7920/7925 Disc Loader" /* the ROM description */
232 };
233
234
235 /* Units list */
236
237 #define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD)
238
239 static UNIT ds_unit [] = {
240 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 0 */
241 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 1 */
242 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 2 */
243 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 3 */
244 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 4 */
245 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 5 */
246 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 6 */
247 { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 7 */
248 { UDATA (&ds_service_controller, UNIT_DIS, 0) }, /* controller unit */
249 { UDATA (&ds_service_timer, UNIT_DIS, 0) } /* timer unit */
250 };
251
252
253 /* Register list */
254
255 static REG ds_reg [] = {
256 /* Macro Name Location Radix Width Offset Depth Flags */
257 /* ------ ------ ------------------------ ----- ---------- ------ ------------- ----------------- */
258 { FLDATA (CMFOL, ds.cmfol, 0) },
259 { FLDATA (CMRDY, ds.cmrdy, 0) },
260 { DRDATA (FCNT, ds.fifo_count, 5) },
261 { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC },
262 { ORDATA (FREG, ds.fifo_reg, 32), REG_HRO },
263
264 { ORDATA (CNTYPE, mac_cntlr.type, 2), REG_HRO },
265 { ORDATA (STATE, mac_cntlr.state, 2) },
266 { ORDATA (OPCODE, mac_cntlr.opcode, 6) },
267 { ORDATA (STATUS, mac_cntlr.status, 6) },
268 { FLDATA (EOC, mac_cntlr.eoc, 0) },
269 { FLDATA (EOD, mac_cntlr.eod, 0) },
270 { ORDATA (SPDU, mac_cntlr.spd_unit, 16) },
271 { ORDATA (FLMASK, mac_cntlr.file_mask, 4) },
272 { ORDATA (RETRY, mac_cntlr.retry, 4), REG_HRO },
273 { ORDATA (CYL, mac_cntlr.cylinder, 16) },
274 { ORDATA (HEAD, mac_cntlr.head, 6) },
275 { ORDATA (SECTOR, mac_cntlr.sector, 8) },
276 { ORDATA (VFYCNT, mac_cntlr.verify_count, 16) },
277 { ORDATA (LASPOL, mac_cntlr.poll_unit, 3) },
278 { HRDATA (BUFPTR, mac_cntlr.buffer, 32), REG_HRO },
279 { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) },
280 { DRDATA (INDEX, mac_cntlr.index, 8) },
281 { DRDATA (LENGTH, mac_cntlr.length, 8) },
282 { HRDATA (AUXPTR, mac_cntlr.aux, 32), REG_HRO },
283 { DRDATA (STIME, mac_cntlr.seek_time, 24), PV_LEFT | REG_NZ },
284 { DRDATA (ITIME, mac_cntlr.sector_time, 24), PV_LEFT | REG_NZ },
285 { DRDATA (CTIME, mac_cntlr.cmd_time, 24), PV_LEFT | REG_NZ },
286 { DRDATA (DTIME, mac_cntlr.data_time, 24), PV_LEFT | REG_NZ },
287 { DRDATA (WTIME, mac_cntlr.wait_time, 31), PV_LEFT | REG_NZ },
288
289 { FLDATA (CTL, ds.control, 0) },
290 { FLDATA (FLG, ds.flag, 0) },
291 { FLDATA (FBF, ds.flag_buffer, 0) },
292 { FLDATA (SRQ, ds.srq, 0) },
293 { FLDATA (EDT, ds.edt, 0) },
294
295 { URDATA (UCYL, ds_unit[0].Cyl, 10, 10, 0, DS_UNITS, PV_LEFT) },
296 { URDATA (UOP, ds_unit[0].Op, 8, 6, 0, DS_UNITS, PV_RZRO) },
297 { URDATA (USTAT, ds_unit[0].Stat, 2, 8, 0, DS_UNITS, PV_RZRO) },
298 { URDATA (UPHASE, ds_unit[0].Phase, 8, 3, 0, DS_UNITS, PV_RZRO) },
299 { URDATA (UPOS, ds_unit[0].pos, 8, T_ADDR_W, 0, DS_UNITS, PV_LEFT) },
300 { URDATA (UWAIT, ds_unit[0].wait, 8, 32, 0, DS_UNITS, PV_LEFT) },
301
302 DIB_REGS (ds_dib),
303
304 { NULL }
305 };
306
307
308 /* Modifier list.
309
310 For the drive models, the modifiers provide this SHOW behavior:
311
312 - when detached and autosized, prints "autosize"
313 - when detached and not autosized, prints the model number
314 - when attached, prints the model number (regardless of autosizing)
315
316
317 Implementation notes:
318
319 1. The validation routine does not allow the model number or autosizing
320 option to be changed when the unit is attached. Therefore, specifying
321 UNIT_ATT in the mask field has no adverse effect.
322
323 2. The modifier DEVNO is deprecated in favor of SC but is retained for
324 compatibility.
325 */
326
327 static MTAB ds_mod [] = {
328 /* Mask Value Match Value Print String Match String Validation Display Descriptor */
329 /* ------------ ------------ ----------------- --------------- ---------------- ------- ---------- */
330 { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL },
331 { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL },
332
333 { UNIT_WLK, UNIT_WLK, "protected", "PROTECT", NULL, NULL, NULL },
334 { UNIT_WLK, 0, "unprotected", "UNPROTECT", NULL, NULL, NULL },
335
336 { UNIT_WLK, UNIT_WLK, NULL, "LOCKED", NULL, NULL, NULL },
337 { UNIT_WLK, 0, NULL, "WRITEENABLED", NULL, NULL, NULL },
338
339 { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL },
340 { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL },
341
342 /* Print Match */
343 /* Mask Value Match Value String String Validation Disp Desc */
344 /* --------------------------------- --------------------- ---------- ---------- ------------- ---- ---- */
345 { UNIT_AUTO | UNIT_ATT, UNIT_AUTO, "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL },
346 { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905, "7905", "7905", &dl_set_model, NULL, NULL },
347 { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906, "7906", "7906", &dl_set_model, NULL, NULL },
348 { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7920, "7920", "7920", &dl_set_model, NULL, NULL },
349 { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7925, "7925", "7925", &dl_set_model, NULL, NULL },
350 { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7905, "7905", NULL, NULL, NULL, NULL },
351 { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7906, "7906", NULL, NULL, NULL, NULL },
352 { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7920, "7920", NULL, NULL, NULL, NULL },
353 { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7925, "7925", NULL, NULL, NULL, NULL },
354
355 /* Entry Flags Value Print String Match String Validation Display Descriptor */
356 /* ------------------- ----- ------------ ------------ ------------ ------------- ---------------- */
357 { MTAB_XDV, 1u, "SC", "SC", &hp_set_dib, &hp_show_dib, (void *) &ds_dib },
358 { MTAB_XDV | MTAB_NMO, ~1u, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &ds_dib },
359 { 0 }
360 };
361
362
363 /* Debugging trace list */
364
365 static DEBTAB ds_deb [] = {
366 { "RWSC", DEB_RWSC },
367 { "CMDS", DEB_CMDS },
368 { "CPU", DEB_CPU },
369 { "BUF", DEB_BUF },
370 { "SERV", TRACE_SERV },
371 { "IOBUS", TRACE_IOBUS },
372 { NULL, 0 }
373 };
374
375
376 /* Device descriptor */
377
378 DEVICE ds_dev = {
379 "DS", /* device name */
380 ds_unit, /* unit array */
381 ds_reg, /* register array */
382 ds_mod, /* modifier array */
383 DS_UNITS, /* number of units */
384 8, /* address radix */
385 27, /* address width = 128 MB */
386 1, /* address increment */
387 8, /* data radix */
388 16, /* data width */
389 NULL, /* examine routine */
390 NULL, /* deposit routine */
391 &ds_reset, /* reset routine */
392 &ds_boot, /* boot routine */
393 &ds_attach, /* attach routine */
394 &ds_detach, /* detach routine */
395 &ds_dib, /* device information block */
396 DEV_DISABLE | DEV_DEBUG, /* device flags */
397 0, /* debug control flags */
398 ds_deb, /* debug flag name table */
399 NULL, /* memory size change routine */
400 NULL /* logical device name */
401 };
402
403
404
405 /* Interface local SCP support routines */
406
407
408
409 /* Disc interface.
410
411 The 13175D disc interface data path consists of an input multiplexer/latch
412 and a 16-word FIFO buffer. The FIFO source may be either the CPU's I/O
413 input bus or the controller's interface data bus. The output of the FIFO may
414 be enabled either to the CPU's I/O output bus or the interface data bus.
415
416 The control path consists of the usual control, flag buffer, flag, and SRQ
417 flip-flops, although flag and SRQ are decoupled to allow the full DCPC
418 transfer rate through the FIFO (driving SRQ from the flag limits transfers to
419 every other cycle). SRQ is based on the FIFO level: if data or room in the
420 FIFO is available, SRQ is set to initiate a transfer. The flag is only used
421 to signal an interrupt at the end of a command.
422
423 One unusual aspect is that SFC and SFS test different things, rather than
424 complementary states of the same thing. SFC tests the controller busy state,
425 and SFS tests the flag flip-flop.
426
427 In addition, the card contains end-of-data-transfer, command-follows, and
428 command-ready flip-flops. EDT is set when the DCPC EDT signal is asserted
429 and is used in conjunction with the FIFO level to assert the end-of-data
430 signal to the controller. The command-follows flip-flop is set by a CLC to
431 indicate that the next data word output from the CPU is a disc command. The
432 command-ready flip-flop is set when a command is received to schedule an
433 interface poll.
434
435
436 Implementation notes:
437
438 1. In hardware, SRQ is enabled only when the controller is reading or
439 writing the disc (IFIN or IFOUT functions are asserted) and set when the
440 FIFO is not empty (read) or not full (write). In simulation, SRQ is set
441 by the unit service read/write data phase transfers and cleared in the
442 IOI and IOO signal handlers when the FIFO is empty (read) or full
443 (write).
444
445 2. The DCPC EDT signal cannot set the controller's end-of-data flag directly
446 because a write EOD must occur only after the FIFO has been drained.
447
448 3. Polling the interface or drives must be deferred to the end of I/O signal
449 handling. If they are performed in the IOO/STC handlers themselves, an
450 associated CLF might clear the flag that was set by the poll.
451
452 4. Executing a CLC sets the controller's end-of-data flag, which will abort
453 a read or write data transfer in progress. Parameter transfers are not
454 affected. If a command is received when a parameter is expected, the
455 word is interpreted as data, even though the command-ready flip-flop is
456 set. The controller firmware only checks DTRDY for a parameter transfer,
457 and DTRDY is asserted whenever the FIFO is not empty.
458
459 5. The hardware Interface Function and Flag Buses are not implemented
460 explicitly. Instead, interface functions and signals are inferred by the
461 interface from the current command operation and phase.
462 */
463
ds_interface(const DIB * dibptr,INBOUND_SET inbound_signals,HP_WORD inbound_value)464 static SIGNALS_VALUE ds_interface (const DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
465 {
466 static const char * const output_state [] = { "Data", "Command" };
467 const char * const hold_or_clear = (inbound_signals & ioCLF ? ",C" : "");
468 INBOUND_SIGNAL signal;
469 INBOUND_SET working_set = inbound_signals;
470 SIGNALS_VALUE outbound = { ioNONE, 0 };
471 t_bool irq_enabled = FALSE;
472 t_bool command_issued = FALSE;
473 t_bool interrupt_enabled = FALSE;
474
475 while (working_set) {
476 signal = IONEXTSIG (working_set); /* isolate the next signal */
477
478 switch (signal) { /* dispatch the I/O signal */
479
480 case ioCLF: /* clear flag flip-flop */
481 ds.flag_buffer = CLEAR; /* clear the flag buffer */
482 ds.flag = CLEAR; /* and flag */
483
484 tprintf (ds_dev, DEB_CMDS, "[CLF] Flag cleared\n");
485 break;
486
487
488 case ioSTF: /* set flag flip-flop */
489 ds.flag_buffer = SET; /* set the flag buffer */
490
491 tprintf (ds_dev, DEB_CMDS, "[STF] Flag set\n");
492 break;
493
494
495 case ioENF: /* enable flag */
496 if (ds.flag_buffer == SET) /* if the flag buffer flip-flop is set */
497 ds.flag = SET; /* then set the flag flip-flop */
498 break;
499
500
501 case ioSFC: /* skip if flag is clear */
502 if (mac_cntlr.state != cntlr_busy) /* skip if the controller is not busy */
503 outbound.signals |= ioSKF;
504 break;
505
506
507 case ioSFS: /* skip if flag is set */
508 if (ds.flag == SET) /* assert SKF if the flag is set */
509 outbound.signals |= ioSKF;
510 break;
511
512
513 case ioIOI: /* I/O data input */
514 outbound.value = fifo_unload (); /* unload the next word from the FIFO */
515
516 tprintf (ds_dev, DEB_CPU, "[LIx%s] Data = %06o\n", hold_or_clear, outbound.value);
517
518 if (FIFO_EMPTY) { /* is the FIFO now empty? */
519 if (ds.srq == SET)
520 tprintf (ds_dev, DEB_CMDS, "[LIx%s] SRQ cleared\n", hold_or_clear);
521
522 ds.srq = CLEAR; /* clear SRQ */
523
524 if (ds_cntlr.Phase == data_phase) { /* is this an outbound parameter? */
525 ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */
526 activate_unit (&ds_cntlr); /* to acknowledge the data */
527 }
528 }
529 break;
530
531
532 case ioIOO: /* I/O data output */
533 tprintf (ds_dev, DEB_CPU, "[OTx%s] %s = %06o\n",
534 hold_or_clear, output_state [ds.cmfol], inbound_value);
535
536 fifo_load ((uint16) inbound_value); /* load the word into the FIFO */
537
538 if (ds.cmfol == SET) { /* are we expecting a command? */
539 ds.cmfol = CLEAR; /* clear the command follows flip-flop */
540 ds.cmrdy = SET; /* set the command ready flip-flop */
541 command_issued = TRUE; /* and request an interface poll */
542 }
543
544 else { /* not a command */
545 if (ds_cntlr.Phase == data_phase) { /* is this an inbound parameter? */
546 ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */
547 activate_unit (&ds_cntlr); /* to receive the data */
548 }
549
550 if (FIFO_STOP) { /* is the FIFO now full enough? */
551 if (ds.srq == SET)
552 tprintf (ds_dev, DEB_CMDS, "[OTx%s] SRQ cleared\n", hold_or_clear);
553
554 ds.srq = CLEAR; /* clear SRQ to stop filling */
555 }
556 }
557 break;
558
559
560 case ioPOPIO: /* power-on preset to I/O */
561 ds.flag_buffer = SET; /* set flag buffer */
562 ds.cmrdy = CLEAR; /* clear the command ready flip-flop */
563
564 tprintf (ds_dev, DEB_CMDS, "[POPIO] Flag set\n");
565 break;
566
567
568 case ioCRS: /* control reset */
569 tprintf (ds_dev, DEB_CMDS, "[CRS] Master reset\n");
570
571 ds.control = CLEAR; /* clear the control */
572 ds.cmfol = CLEAR; /* and command follows flip-flops */
573
574 if (PRESET_ENABLE) { /* is preset enabled for this interface? */
575 fifo_clear (); /* clear the FIFO */
576
577 dl_clear_controller (&mac_cntlr, ds_unit, /* do a hard clear of the controller */
578 hard_clear);
579 }
580 break;
581
582
583 case ioCLC: /* clear control flip-flop */
584 tprintf (ds_dev, DEB_CMDS, "[CLC%s] Control cleared\n", hold_or_clear);
585
586 ds.control = CLEAR; /* clear the control */
587 ds.edt = CLEAR; /* and EDT flip-flops */
588 ds.cmfol = SET; /* set the command follows flip-flop */
589 mac_cntlr.eod = SET; /* set the controller's EOD flag */
590
591 fifo_clear (); /* clear the FIFO */
592 break;
593
594
595 case ioSTC: /* set control flip-flop */
596 ds.control = SET; /* set the control flip-flop */
597
598 interrupt_enabled = TRUE; /* check for drive attention */
599
600 tprintf (ds_dev, DEB_CMDS, "[STC%s] Control set\n", hold_or_clear);
601 break;
602
603
604 case ioEDT: /* end data transfer */
605 ds.edt = SET; /* set the EDT flip-flop */
606
607 tprintf (ds_dev, DEB_CPU, "[EDT] DCPC transfer ended\n");
608 break;
609
610
611 case ioSIR: /* set interrupt request */
612 if (ds.control & ds.flag) /* if control and flag are set */
613 outbound.signals |= cnVALID; /* then deny PRL */
614 else /* otherwise */
615 outbound.signals |= cnPRL | cnVALID; /* conditionally assert PRL */
616
617 if (ds.control & ds.flag & ds.flag_buffer) /* if control and flag and flag buffer are set */
618 outbound.signals |= cnIRQ; /* then conditionally assert IRQ */
619
620 if (ds.srq == SET) /* if the SRQ flip-flop is set */
621 outbound.signals |= ioSRQ; /* then assert SRQ */
622 break;
623
624
625 case ioIAK: /* interrupt acknowledge */
626 ds.flag_buffer = CLEAR;
627 break;
628
629
630 case ioIEN: /* interrupt enable */
631 irq_enabled = TRUE;
632 break;
633
634
635 case ioPRH: /* priority high */
636 if (irq_enabled && outbound.signals & cnIRQ) /* if IRQ is enabled and conditionally asserted */
637 outbound.signals |= ioIRQ | ioFLG; /* then assert IRQ and FLG */
638
639 if (not irq_enabled || outbound.signals & cnPRL) /* if IRQ is disabled or PRL is conditionally asserted */
640 outbound.signals |= ioPRL; /* then assert it unconditionally */
641 break;
642
643
644 case ioPON: /* not used by this interface */
645 break;
646 }
647
648 IOCLEARSIG (working_set, signal); /* remove the current signal from the set */
649 }
650
651
652 if (command_issued) /* was a command received? */
653 poll_interface (); /* poll the interface for the next command */
654 else if (interrupt_enabled) /* were interrupts enabled? */
655 poll_drives (); /* poll the drives for Attention */
656
657 return outbound; /* return the outbound signals and value */
658 }
659
660
661 /* Service the disc drive unit.
662
663 The unit service routine is called to execute scheduled controller commands
664 for the specified unit. The actions to be taken depend on the current state
665 of the controller and the unit.
666
667 Generally, the controller library service routine handles all of the disc
668 operations except data transfer to and from the interface. Read transfers
669 are responsible for loading words from the sector buffer into the FIFO and
670 enabling SRQ. If the current sector transfer is complete, either due to EDT
671 assertion or buffer exhaustion, the controller is moved to the end phase to
672 complete or continue the read with the next sector. In either case, the unit
673 is rescheduled. If the FIFO overflows, the read terminates with a data
674 overrun error.
675
676 Write transfers set the initial SRQ to request words from the CPU. As each
677 word arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is
678 enabled. If the current sector transfer is complete, the controller is moved
679 to the end phase. If the FIFO underflows, the write terminates with a data
680 overrun error.
681
682 The synchronous nature of the disc drive requires that data be supplied or
683 accepted continuously by the CPU. DCPC generally assures that this occurs,
684 and the FIFO allows for some latency before an overrun or underrun occurs.
685
686 The other operation the interface must handle is seek completion. The
687 controller handles seek completion by setting Attention status in the drive's
688 status word. The interface is responsible for polling the drives if the
689 controller is idle and interrupts are enabled.
690
691
692 Implementation notes:
693
694 1. Every command except Seek, Recalibrate, and End sets the flag when the
695 command completes. A command completes when the controller is no longer
696 busy (it becomes idle for Seek, Recalibrate, and End, or it becomes
697 waiting for all others). Seek and Recalibrate may generate errors (e.g.,
698 heads unloaded), in which case the flag must be set. But in these cases,
699 the controller state is waiting, not idle.
700
701 However, it is insufficient simply to check that the controller has moved
702 to the wait state, because a seek may complete while the controller is
703 waiting for the next command. For example, a Seek is started on unit 0,
704 and the controller moves to the idle state. But before the seek
705 completes, another command is issued that attempts to access unit 1,
706 which is not ready. The command fails with a Status-2 error, and the
707 controller moves to the wait state. When the seek completes, the
708 controller is waiting with error status. We must determine whether the
709 seek completed successfully or not, as we must interrupt in the latter
710 case.
711
712 Therefore, we determine seek completion by checking if the Attention
713 status was set. Attention sets only if the seek completes successfully.
714
715 (Actually, Attention sets if a seek check occurs, but in that case, the
716 command terminated before the seek ever started. Also, a seek may
717 complete while the controller is busy, waiting, or idle.)
718
719 2. For debug printouts, we want to print the name of the command that has
720 completed when the controller returns to the idle or wait state.
721 Normally, we would use the controller's "opcode" field to identify the
722 command that completed. However, while waiting for Seek or Recalibrate
723 completion, "opcode" may be set to another command if that command does
724 not access this drive. For example, it might be set to a Read of another
725 unit, or a Request Status for this unit. So we can't rely on "opcode" to
726 report the correct name of the completed positioning command.
727
728 However, we cannot rely on "uptr->Op" either, as that can be changed
729 during the course of a command. For example, Read Without Verify is
730 changed to Read after a track crossing.
731
732 Instead, we have to determine whether a seek is completing. If it is,
733 then we report "uptr->Op"; otherwise, we report "opcode".
734
735 3. The initial write SRQ must set only at the transition from the start
736 phase to the data phase. If a write command begins with an auto-seek,
737 the drive service will be entered twice in the start phase (the first
738 entry performs the seek, and the second begins the write). In hardware,
739 SRQ does not assert until the write begins.
740
741 4. The DCPC EDT signal cannot set the controller's end-of-data flag
742 directly because a write EOD must only occur after the FIFO has been
743 drained.
744 */
745
ds_service_drive(UNIT * uptr)746 static t_stat ds_service_drive (UNIT *uptr)
747 {
748 t_stat result;
749 t_bool seek_completion;
750 FLIP_FLOP entry_srq = ds.srq; /* get the SRQ state on entry */
751 CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->Phase; /* get the operation phase on entry */
752 uint32 entry_status = uptr->Stat; /* get the drive status on entry */
753
754 result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */
755
756 if ((CNTLR_PHASE) uptr->Phase == data_phase) /* is the drive in the data phase? */
757 switch ((CNTLR_OPCODE) uptr->Op) { /* dispatch the current operation */
758
759 case Read: /* read operations */
760 case Read_Full_Sector:
761 case Read_With_Offset:
762 case Read_Without_Verify:
763 if (mac_cntlr.length == 0 || ds.edt == SET) { /* is the data phase complete? */
764 mac_cntlr.eod = ds.edt; /* set EOD if DCPC is done */
765 uptr->Phase = end_phase; /* set the end phase */
766 uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */
767 }
768
769 else if (FIFO_FULL) /* is the FIFO already full? */
770 dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an overrun */
771
772 else {
773 fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */
774 mac_cntlr.length--; /* count it */
775 ds.srq = SET; /* ask DCPC to pick it up */
776 io_assert_SIR (&ds_dib); /* and assert SRQ */
777 uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */
778 }
779
780 break;
781
782
783 case Write: /* write operations */
784 case Write_Full_Sector:
785 case Initialize:
786 if (entry_phase == start_phase) { /* is this the phase transition? */
787 ds.srq = SET; /* start the DCPC transfer */
788 io_assert_SIR (&ds_dib); /* and assert SRQ */
789 }
790
791 else if (FIFO_EMPTY) /* is the FIFO empty? */
792 dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an underrun */
793
794 else {
795 buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */
796 mac_cntlr.length--; /* count it */
797
798 if (ds.edt == SET && FIFO_EMPTY) /* if DCPC is complete and the FIFO is empty */
799 mac_cntlr.eod = SET; /* then set the end-of-data flag */
800
801 if (mac_cntlr.length == 0 || mac_cntlr.eod == SET) { /* is the data phase complete? */
802 uptr->Phase = end_phase; /* set the end phase */
803 uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */
804 }
805
806 else {
807 if (ds.edt == CLEAR) { /* if DCPC is still transferring */
808 ds.srq = SET; /* then request the next word */
809 io_assert_SIR (&ds_dib); /* and assert SRQ */
810 }
811
812 uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */
813 }
814 }
815
816 break;
817
818
819 default: /* we were entered with an invalid state */
820 result = SCPE_IERR; /* return an internal (programming) error */
821 break;
822 } /* end of data phase operation dispatch */
823
824
825 if (entry_srq != ds.srq)
826 tprintf (ds_dev, DEB_CMDS, "SRQ %s\n", ds.srq == SET ? "set" : "cleared");
827
828 if (uptr->wait) /* was service requested? */
829 activate_unit (uptr); /* schedule the next event */
830
831 seek_completion = ~entry_status & uptr->Stat & DL_S2ATN; /* seek is complete when Attention sets */
832
833 if (mac_cntlr.state != cntlr_busy) { /* is the command complete? */
834 if (mac_cntlr.state == cntlr_wait && not seek_completion) { /* is it command but not seek completion? */
835 ds.flag_buffer = SET; /* set the data flag */
836 io_assert_ENF (&ds_dib); /* to interrupt the CPU */
837 }
838
839 poll_interface (); /* poll the interface for the next command */
840 poll_drives (); /* poll the drives for Attention */
841 }
842
843
844 if (result == SCPE_IERR) /* did an internal error occur? */
845 tprintf (ds_dev, DEB_RWSC, "Unit %d %s command %s phase service not handled\n",
846 uptr - ds_unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->Op),
847 dl_phase_name ((CNTLR_PHASE) uptr->Phase));
848
849 else if (seek_completion) /* if a seek has completed */
850 tprintf (ds_dev, DEB_RWSC, "Unit %d %s command completed\n", /* report the unit command */
851 uptr - ds_unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->Op));
852
853 else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */
854 tprintf (ds_dev, DEB_RWSC, "Unit %d %s command completed\n", /* report the controller command */
855 uptr - ds_unit, dl_opcode_name (MAC, mac_cntlr.opcode));
856
857 return result; /* return the result of the service */
858 }
859
860
861 /* Service the controller unit.
862
863 The controller service routine is called to execute scheduled controller
864 commands that do not access drive units. It is also called to obtain command
865 parameters from the interface and to return command result values to the
866 interface.
867
868 Most controller commands are handled completely in the library's service
869 routine, so we call that first. Commands that neither accept nor supply
870 parameters are complete when the library routine returns, so all we have to
871 do is set the interface flag if required.
872
873 For parameter transfers in the data phase, the interface is responsible for
874 moving words between the sector buffer and the FIFO and setting the flag to
875 notify the CPU.
876
877
878 Implementation notes:
879
880 1. In hardware, the Read With Offset command sets the data flag after the
881 offset parameter has been read and the head positioner has been moved by
882 the indicated amount. The intent is to delay the DCPC start until the
883 drive is ready to supply data from the disc.
884
885 In simulation, the flag is set as soon as the parameter is received.
886 */
887
ds_service_controller(UNIT * uptr)888 static t_stat ds_service_controller (UNIT *uptr)
889 {
890 t_stat result;
891 const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->Op;
892
893 result = dl_service_controller (&mac_cntlr, uptr); /* service the controller */
894
895 switch ((CNTLR_PHASE) uptr->Phase) { /* dispatch the current phase */
896
897 case start_phase: /* most controller operations */
898 case end_phase: /* start and end on the same phase */
899 switch (opcode) { /* dispatch the current operation */
900
901 case Request_Status:
902 case Request_Sector_Address:
903 case Address_Record:
904 case Request_Syndrome:
905 case Load_TIO_Register:
906 case Request_Disc_Address:
907 case End:
908 break; /* complete the operation without setting the flag */
909
910
911 case Clear:
912 case Set_File_Mask:
913 case Wakeup:
914 ds.flag_buffer = SET; /* complete the operation */
915 io_assert_ENF (&ds_dib); /* and set the flag */
916 break;
917
918
919 default: /* we were entered with an invalid state */
920 result = SCPE_IERR; /* return an internal (programming) error */
921 break;
922 } /* end of operation dispatch */
923 break; /* end of start and end phase handlers */
924
925
926 case data_phase:
927 switch (opcode) { /* dispatch the current operation */
928
929 case Seek: /* operations that accept parameters */
930 case Verify:
931 case Address_Record:
932 case Read_With_Offset:
933 case Load_TIO_Register:
934 buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */
935 mac_cntlr.length--; /* count it */
936
937 if (mac_cntlr.length) { /* are there more words to transfer? */
938 ds.flag_buffer = SET; /* set the flag */
939 io_assert_ENF (&ds_dib); /* to request the next one */
940 }
941
942 else { /* all parameters have been received */
943 uptr->Phase = end_phase; /* set the end phase */
944
945 if (opcode == Read_With_Offset) { /* a Read With Offset command sets the flag */
946 ds.flag_buffer = SET; /* to indicate that offsetting */
947 io_assert_ENF (&ds_dib); /* is complete */
948 }
949
950 start_command (); /* the command is now ready to execute */
951 }
952 break;
953
954
955 case Request_Status: /* operations that supply parameters */
956 case Request_Sector_Address:
957 case Request_Syndrome:
958 case Request_Disc_Address:
959 if (mac_cntlr.length) { /* are there more words to return? */
960 fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */
961 mac_cntlr.length--; /* count it */
962
963 ds.flag_buffer = SET; /* set the data flag */
964 io_assert_ENF (&ds_dib); /* to request pickup by the CPU */
965 }
966
967 else { /* all parameters have been sent */
968 uptr->Phase = end_phase; /* set the end phase */
969 uptr->wait = mac_cntlr.cmd_time; /* schedule the controller */
970 activate_unit (uptr); /* to complete the command */
971 }
972 break;
973
974
975 default: /* we were entered with an invalid state */
976 result = SCPE_IERR; /* return an internal (programming) error */
977 break;
978 } /* end of operation dispatch */
979 break; /* end of data phase handlers */
980 } /* end of phase dispatch */
981
982
983 if (result == SCPE_IERR) /* did an internal error occur? */
984 tprintf (ds_dev, DEB_RWSC, "Controller %s command %s phase service not handled\n",
985 dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->Phase));
986
987
988 if (mac_cntlr.state != cntlr_busy) { /* has the controller stopped? */
989 poll_interface (); /* poll the interface for the next command */
990 poll_drives (); /* poll the drives for Attention status */
991
992 tprintf (ds_dev, DEB_RWSC, "Controller %s command completed\n",
993 dl_opcode_name (MAC, opcode));
994 }
995
996 return result; /* return the result of the service */
997 }
998
999
1000 /* Service the command wait timer unit.
1001
1002 The command wait timer service routine is called if the command wait timer
1003 expires. The library is called to reset the file mask and idle the
1004 controller. Then the interface is polled for a command and the drives are
1005 polled for Attention status.
1006 */
1007
ds_service_timer(UNIT * uptr)1008 static t_stat ds_service_timer (UNIT *uptr)
1009 {
1010 t_stat result;
1011
1012 result = dl_service_timer (&mac_cntlr, uptr); /* service the timer */
1013
1014 poll_interface (); /* poll the interface for the next command */
1015 poll_drives (); /* poll the drives for Attention status */
1016
1017 return result; /* return the result of the service */
1018 }
1019
1020
1021 /* Reset the simulator.
1022
1023 In hardware, the PON signal clears the Interface Selected flip-flop,
1024 disconnecting the interface from the disc controller. In simulation, the
1025 interface always remains connected to the controller, so no special action is
1026 needed.
1027
1028
1029 Implementation notes:
1030
1031 1. During a power-on reset, a pointer to the FIFO simulation register is
1032 saved to allow access to the "qptr" field during FIFO loading and
1033 unloading. This enables SCP to view the FIFO as a circular queue, so
1034 that the bottom word of the FIFO is always displayed as FIFO[0],
1035 regardless of where it is in the actual FIFO array.
1036
1037 2. SRQ is denied because neither IFIN nor IFOUT is asserted when the
1038 interface is not selected.
1039 */
1040
ds_reset(DEVICE * dptr)1041 static t_stat ds_reset (DEVICE *dptr)
1042 {
1043 uint32 unit;
1044 REG *rptr;
1045
1046 if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */
1047 for (rptr = dptr->registers; /* find the FIFO register entry */
1048 rptr->loc != &ds.fifo && rptr->loc != NULL; /* in the register array */
1049 rptr++);
1050
1051 if (rptr == NULL) /* if it cannot be found, */
1052 return SCPE_IERR; /* report a programming error */
1053
1054 else { /* otherwise */
1055 ds.fifo_reg = rptr; /* save the pointer to the register */
1056 ds.fifo_reg->qptr = 0; /* and reset the FIFO bottom index */
1057 ds.fifo_count = 0; /* and clear the FIFO */
1058 }
1059
1060 for (unit = 0; unit < dptr->numunits; unit++) { /* loop through all of the units */
1061 sim_cancel (dptr->units + unit); /* cancel activation */
1062 dptr->units [unit].Cyl = 0; /* reset the head position to cylinder 0 */
1063 dptr->units [unit].pos = 0; /* (irrelevant for the controller and timer) */
1064 }
1065 }
1066
1067 ds.srq = CLEAR; /* clear SRQ */
1068
1069 return SCPE_OK;
1070 }
1071
1072
1073 /* Attach a drive unit.
1074
1075 The specified file is attached to the indicated drive unit. The library
1076 attach routine will load the heads. This will set the First Status and
1077 Attention bits in the drive status, so we poll the drives to ensure that the
1078 CPU is notified that the drive is now online.
1079
1080 If a new file is specified, the file is initialized to its capacity by
1081 writing a zero to the last byte in the file.
1082
1083
1084 Implementation notes:
1085
1086 1. If we are called during a RESTORE command, the drive status will not be
1087 changed, so polling the drives will have no effect.
1088
1089 2. The C standard says, "A binary stream need not meaningfully support fseek
1090 calls with a whence value of SEEK_END," so instead we determine the
1091 offset from the start of the file to the last byte and seek there.
1092 */
1093
ds_attach(UNIT * uptr,char * cptr)1094 static t_stat ds_attach (UNIT *uptr, char *cptr)
1095 {
1096 t_stat result;
1097 t_addr offset;
1098 const uint8 zero = 0;
1099
1100 result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */
1101
1102 if (result == SCPE_OK) { /* if the attach was successful */
1103 poll_drives (); /* then poll the drives to notify the CPU */
1104
1105 if (sim_switches & SWMASK ('N')) { /* if this is a new disc image */
1106 offset = (t_addr) /* then determine the offset of */
1107 (uptr->capac * sizeof (int16) - sizeof zero); /* the last byte in a full-sized file */
1108
1109 if (sim_fseek (uptr->fileref, offset, SEEK_SET) != 0 /* seek to the last byte */
1110 || fwrite (&zero, sizeof zero, 1, uptr->fileref) == 0 /* and write a zero to fill */
1111 || fflush (uptr->fileref) != 0) /* the file to its capacity */
1112 clearerr (uptr->fileref); /* clear and ignore any errors */
1113 }
1114 }
1115
1116 return result; /* return the result of the attach */
1117 }
1118
1119
1120 /* Detach a drive unit.
1121
1122 The specified file is detached from the indicated drive unit. The library
1123 detach routine will unload the heads. This will set the Attention bit in the
1124 drive status, so we poll the drives to ensure that the CPU is notified that
1125 the drive is now offline.
1126 */
1127
ds_detach(UNIT * uptr)1128 static t_stat ds_detach (UNIT *uptr)
1129 {
1130 t_stat result;
1131
1132 result = dl_detach (&mac_cntlr, uptr); /* detach the drive */
1133
1134 if (result == SCPE_OK) /* was the detach successful? */
1135 poll_drives (); /* poll the drives to notify the CPU */
1136
1137 return result;
1138 }
1139
1140
1141 /* MAC disc bootstrap loaders (BMDL and 12992B).
1142
1143 The Basic Moving-Head Disc Loader (BMDL) consists of two programs. The
1144 program starting at address x7700 loads absolute paper tapes into memory.
1145 The program starting at address x7750 loads a disc-resident bootstrap from
1146 the MAC disc drive into memory. The S register specifies the head to use.
1147
1148 For a 2100/14/15/16 CPU, entering a LOAD DS or BOOT DS command loads the BMDL
1149 into memory and executes the disc portion starting at x7750. The bootstrap
1150 reads 2047 words from cylinder 0 sector 0 of the specified head into memory
1151 starting at location 2011 octal. Loader execution ends with one of the
1152 following instructions:
1153
1154 * HLT 11B - the disc read failed.
1155 * JSB 2055,I - the disc read completed.
1156
1157 The HP 1000 uses the 12992B boot loader ROM to bootstrap the disc. The head
1158 number is obtained from bits 2-0 of the existing S-register value when the
1159 loader is executed. Bits 5-3 of the existing S-register value are also
1160 retained and are available to the boot extension program. The loader reads
1161 6144 words from cylinder 0 sector 0 of the specified head into memory
1162 starting at location 2011 octal. Loader execution ends with one of the
1163 following instructions:
1164
1165 * HLT 30 - the drive is not ready..
1166 * JSB 2055,I - the disc read succeeded.
1167
1168 The loader automatically retries the operations for all disc errors other
1169 than a drive fault.
1170
1171
1172 Implementation notes:
1173
1174 1. After the BMDL has been loaded into memory, the paper tape portion may be
1175 executed manually by setting the P register to the starting address
1176 (x7700).
1177
1178 2. For compatibility with the "cpu_copy_loader" routine, the BMDL device I/O
1179 instructions address select codes 10 and 11.
1180 */
1181
1182 static const LOADER_ARRAY ds_loaders = {
1183 { /* HP 21xx Basic Moving-Head Disc Loader (BMDL-7905) */
1184 050, /* loader starting index */
1185 076, /* DMA index */
1186 034, /* FWA index */
1187 { 0002401, /* 77700: PTAPE CLA,RSS Paper Tape start */
1188 0063722, /* 77701: LDA 77722 */
1189 0107700, /* 77702: CLC 0,C */
1190 0002307, /* 77703: CCE,INA,SZA,RSS */
1191 0102077, /* 77704: HLT 77 */
1192 0017735, /* 77705: JSB 77735 */
1193 0007307, /* 77706: CMB,CCE,INB,SZB,RSS */
1194 0027702, /* 77707: JMP 77702 */
1195 0077733, /* 77710: STB 77733 */
1196 0017735, /* 77711: JSB 77735 */
1197 0017735, /* 77712: JSB 77735 */
1198 0074000, /* 77713: STB 0 */
1199 0077747, /* 77714: STB 77747 */
1200 0047734, /* 77715: ADB 77734 */
1201 0002140, /* 77716: SEZ,CLE */
1202 0102055, /* 77717: HLT 55 */
1203 0017735, /* 77720: JSB 77735 */
1204 0040001, /* 77721: ADA 1 */
1205 0177747, /* 77722: STB 77747,I */
1206 0067747, /* 77723: LDB 77747 */
1207 0006104, /* 77724: CLE,INB */
1208 0037733, /* 77725: ISZ 77733 */
1209 0027714, /* 77726: JMP 77714 */
1210 0017735, /* 77727: JSB 77735 */
1211 0054000, /* 77730: CPB 0 */
1212 0027701, /* 77731: JMP 77701 */
1213 0102011, /* 77732: HLT 11 */
1214 0000000, /* 77733: NOP */
1215 0100100, /* 77734: RRL 16 */
1216 0000000, /* 77735: NOP */
1217 0006400, /* 77736: CLB */
1218 0103710, /* 77737: STC 10,C */
1219 0102310, /* 77740: SFS 10 */
1220 0027740, /* 77741: JMP 77740 */
1221 0106410, /* 77742: MIB 10 */
1222 0002240, /* 77743: SEZ,CME */
1223 0127735, /* 77744: JMP 77735,I */
1224 0005727, /* 77745: BLF,BLF */
1225 0027737, /* 77746: JMP 77737 */
1226 0000000, /* 77747: NOP */
1227 0067777, /* 77750: DISC LDB 77777 */
1228 0174001, /* 77751: STB 1,I */
1229 0006004, /* 77752: INB */
1230 0063732, /* 77753: LDA 77732 */
1231 0170001, /* 77754: STA 1,I */
1232 0067776, /* 77755: LDB 77776 */
1233 0106606, /* 77756: OTB 6 */
1234 0106702, /* 77757: CLC 2 */
1235 0102602, /* 77760: OTA 2 */
1236 0102702, /* 77761: STC 2 */
1237 0063751, /* 77762: LDA 77751 */
1238 0102602, /* 77763: OTA 2 */
1239 0102501, /* 77764: LIA 1 */
1240 0001027, /* 77765: ALS,ALF */
1241 0013767, /* 77766: AND 77767 */
1242 0000160, /* 77767: CLE,ALS */
1243 0106710, /* 77770: CLC 10 */
1244 0103610, /* 77771: OTA 10,C */
1245 0103706, /* 77772: STC 6,C */
1246 0102310, /* 77773: SFS 10 */
1247 0027773, /* 77774: JMP 77773 */
1248 0117717, /* 77775: JSB 77717,I */
1249 0000010, /* 77776: SLA */
1250 0002055 } }, /* 77777: SEZ,SLA,INA,RSS */
1251
1252 { /* HP 1000 Loader ROM (12992B) */
1253 IBL_START, /* loader starting index */
1254 IBL_DMA, /* DMA index */
1255 IBL_FWA, /* FWA index */
1256 { 0017727, /* 77700: START JSB STAT GET STATUS */
1257 0002021, /* 77701: SSA,RSS IS DRIVE READY ? */
1258 0027742, /* 77702: JMP DMA YES, SET UP DMA */
1259 0013714, /* 77703: AND B20 NO, CHECK STATUS BITS */
1260 0002002, /* 77704: SZA IS DRIVE FAULTY OR HARD DOWN ? */
1261 0102030, /* 77705: HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */
1262 0027700, /* 77706: JMP START NO, TRY AGAIN FOR DISC READY */
1263 0102011, /* 77707: ADDR1 OCT 102011 */
1264 0102055, /* 77710: ADDR2 OCT 102055 */
1265 0164000, /* 77711: CNT DEC -6144 */
1266 0000007, /* 77712: D7 OCT 7 */
1267 0001400, /* 77713: STCMD OCT 1400 */
1268 0000020, /* 77714: B20 OCT 20 */
1269 0017400, /* 77715: STMSK OCT 17400 */
1270 0000000, /* 77716: NOP */
1271 0000000, /* 77717: NOP */
1272 0000000, /* 77720: NOP */
1273 0000000, /* 77721: NOP */
1274 0000000, /* 77722: NOP */
1275 0000000, /* 77723: NOP */
1276 0000000, /* 77724: NOP */
1277 0000000, /* 77725: NOP */
1278 0000000, /* 77726: NOP */
1279 0000000, /* 77727: STAT NOP STATUS CHECK SUBROUTINE */
1280 0107710, /* 77730: CLC DC,C SET STATUS COMMAND MODE */
1281 0063713, /* 77731: LDA STCMD GET STATUS COMMAND */
1282 0102610, /* 77732: OTA DC OUTPUT STATUS COMMAND */
1283 0102310, /* 77733: SFS DC WAIT FOR STATUS#1 WORD */
1284 0027733, /* 77734: JMP *-1 */
1285 0107510, /* 77735: LIB DC,C B-REG = STATUS#1 WORD */
1286 0102310, /* 77736: SFS DC WAIT FOR STATUS#2 WORD */
1287 0027736, /* 77737: JMP *-1 */
1288 0103510, /* 77740: LIA DC,C A-REG = STATUS#2 WORD */
1289 0127727, /* 77741: JMP STAT,I RETURN */
1290 0067776, /* 77742: DMA LDB DMACW GET DMA CONTROL WORD */
1291 0106606, /* 77743: OTB 6 OUTPUT DMA CONTROL WORD */
1292 0067707, /* 77744: LDB ADDR1 GET MEMORY ADDRESS */
1293 0106702, /* 77745: CLC 2 SET MEMORY ADDRESS INPUT MODE */
1294 0106602, /* 77746: OTB 2 OUTPUT MEMORY ADDRESS TO DMA */
1295 0102702, /* 77747: STC 2 SET WORD COUNT INPUT MODE */
1296 0067711, /* 77750: LDB CNT GET WORD COUNT */
1297 0106602, /* 77751: OTB 2 OUTPUT WORD COUNT TO DMA */
1298 0106710, /* 77752: CLDLD CLC DC SET COMMAND INPUT MODE */
1299 0102501, /* 77753: LIA 1 LOAD SWITCH */
1300 0106501, /* 77754: LIB 1 REGISTER SETTINGS */
1301 0013712, /* 77755: AND D7 ISOLATE HEAD NUMBER */
1302 0005750, /* 77756: BLF,CLE,SLB BIT 12=0? */
1303 0027762, /* 77757: JMP *+3 NO,MANUAL BOOT */
1304 0002002, /* 77760: SZA YES,RPL BOOT. HEAD#=0? */
1305 0001000, /* 77761: ALS NO,HEAD#1, MAKE HEAD#=2 */
1306 0001720, /* 77762: ALF,ALS FORM COLD LOAD */
1307 0001000, /* 77763: ALS COMMAND WORD */
1308 0103706, /* 77764: STC 6,C ACTIVATE DMA */
1309 0103610, /* 77765: OTA DC,C OUTPUT COLD LOAD COMMAND */
1310 0102310, /* 77766: SFS DC IS COLD LOAD COMPLETED ? */
1311 0027766, /* 77767: JMP *-1 NO, WAIT */
1312 0017727, /* 77770: JSB STAT YES, GET STATUS */
1313 0060001, /* 77771: LDA 1 */
1314 0013715, /* 77772: AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */
1315 0002002, /* 77773: SZA IS TRANSFER OK ? */
1316 0027700, /* 77774: JMP START NO,TRY AGAIN */
1317 0117710, /* 77775: EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM @ 2055B */
1318 0000010, /* 77776: DMACW ABS DC */
1319 0170100 } } /* 77777: ABS -START */
1320 };
1321
1322
1323 /* Device boot routine.
1324
1325 This routine is called directly by the BOOT DS and LOAD DS commands to copy
1326 the device bootstrap into the upper 64 words of the logical address space.
1327 It is also called indirectly by a BOOT CPU or LOAD CPU command when the
1328 specified HP 1000 loader ROM socket contains a 12992B ROM.
1329
1330 When called in response to a BOOT DS or LOAD DS command, the "unitno"
1331 parameter indicates the unit number specified in the BOOT command or is zero
1332 for the LOAD command, and "dptr" points at the DS device structure. The
1333 bootstrap supports loading only from unit 0, and the command will be rejected
1334 if another unit is specified (e.g., BOOT DS1). Otherwise, depending on the
1335 current CPU model, the BMDL or 12992B loader ROM will be copied into memory
1336 and configured for the DS select code. If the CPU is a 1000, the S register
1337 will be set as it would be by the front-panel microcode.
1338
1339 When called for a BOOT/LOAD CPU command, the "unitno" parameter indicates the
1340 select code to be used for configuration, and "dptr" will be NULL. As above,
1341 the BMDL or 12992B loader ROM will be copied into memory and configured for
1342 the specified select code. The S register is assumed to be set correctly on
1343 entry and is not modified.
1344
1345 In either case, if the CPU is a 21xx model, the paper tape portion of the
1346 BMDL will be automatically configured for the select code of the paper tape
1347 reader.
1348
1349 For the 12992B boot loader ROM for the HP 1000, the S register is set as
1350 follows:
1351
1352 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1353 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1354 | ROM # | 0 1 | select code | reserved | 0 | head |
1355 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1356
1357 Bit 12 must be 1 for a manual boot. Bits 5-3 are nominally zero but are
1358 reserved for the target operating system. For example, RTE uses bit 5 to
1359 indicate whether a standard (0) or reconfiguration (1) boot is desired.
1360
1361
1362 Implementation notes:
1363
1364 1. In hardware, the BMDL was hand-configured for the disc and paper tape
1365 reader select codes when it was installed on a given system. Under
1366 simulation, the LOAD and BOOT commands automatically configure the BMDL
1367 to the current select codes of the PTR and DS devices.
1368
1369 2. The HP 1000 Loader ROMs manual indicates that bits 2-0 select the head to
1370 use, implying that heads 0-7 are valid. However, Table 5 has entries
1371 only for heads 0-3, and the boot loader code will malfunction if heads
1372 4-7 are specified. The code masks the head number to three bits but
1373 forms the Cold Load Read command by shifting the head number six bits to
1374 the left. As the head field in the command is only two bits wide,
1375 specifying heads 4-7 will result in bit 2 being shifted into the opcode
1376 field, resulting in a Recalibrate command.
1377 */
1378
ds_boot(int32 unitno,DEVICE * dptr)1379 static t_stat ds_boot (int32 unitno, DEVICE *dptr)
1380 {
1381 static const HP_WORD ds_preserved = 0000073u; /* S-register bits 5-3 and 1-0 are preserved */
1382 static const HP_WORD ds_manual_boot = 0010000u; /* S-register bit 12 set for a manual boot */
1383 uint32 start;
1384
1385 if (dptr == NULL) /* if we are being called for a BOOT/LOAD CPU */
1386 start = cpu_copy_loader (ds_loaders, unitno, /* then copy the boot loader to memory */
1387 IBL_S_NOCLEAR, IBL_S_NOSET); /* but do not alter the S register */
1388
1389 else if (unitno != 0) /* otherwise a BOOT DS for a non-zero unit */
1390 return SCPE_NOFNC; /* is rejected as unsupported */
1391
1392 else /* otherwise this is a BOOT/LOAD DS */
1393 start = cpu_copy_loader (ds_loaders, ds_dib.select_code, /* so copy the boot loader to memory */
1394 ds_preserved, ds_manual_boot); /* and configure the S register if 1000 CPU */
1395
1396 if (start == 0) /* if the copy failed */
1397 return SCPE_NOFNC; /* then reject the command */
1398 else /* otherwise */
1399 return SCPE_OK; /* the boot loader was successfully copied */
1400 }
1401
1402
1403
1404 /* MAC disc global SCP routines */
1405
1406
1407 /* Load or unload the drive heads.
1408
1409 The SCP command SET DSn UNLOADED simulates setting the hardware RUN/STOP
1410 switch to STOP. The heads are unloaded, and the drive is spun down.
1411
1412 The SET DSn LOADED command simulates setting the switch to RUN. The drive is
1413 spun up, and the heads are loaded.
1414
1415 The library handles command validation and setting the appropriate drive unit
1416 status.
1417 */
1418
ds_load_unload(UNIT * uptr,int32 value,char * cptr,void * desc)1419 static t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)
1420 {
1421 const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */
1422
1423 return dl_load_unload (&mac_cntlr, uptr, load); /* load or unload the heads */
1424 }
1425
1426
1427
1428 /* MAC disc local utility routines */
1429
1430
1431 /* Start a command.
1432
1433 The previously prepared command is executed by calling the corresponding
1434 library routine. On entry, the controller's opcode field contains the
1435 command to start, and the buffer contains the command word in element 0 and
1436 the parameters required by the command, if any, beginning in element 1.
1437
1438 If the command started, the returned pointer will point at the unit to
1439 activate (if that unit's "wait" field is non-zero). If the returned pointer
1440 is NULL, the command failed to start, and the controller status has been set
1441 to indicate the reason. The interface flag is set to notify the CPU of the
1442 failure.
1443
1444
1445 Implementation notes:
1446
1447 1. If a command that accesses the drive is attempted on a drive currently
1448 seeking, the returned pointer will be valid, but the unit's "wait" time
1449 will be zero. The unit must not be activated (as it already is active).
1450 When the seek completes, the command will be executed automatically.
1451
1452 If a Seek or Cold Load Read command is attempted on a drive currently
1453 seeking, seek completion will occur normally, but Seek Check status will
1454 be set.
1455
1456 2. For debug printouts, we want to print the name of the command (Seek or
1457 Recalibrate) in progress when a new command is started. However, when
1458 the library routine returns, the unit operation and controller opcode
1459 have been changed to reflect the new command. Therefore, we must record
1460 the operation in progress before calling the library.
1461
1462 The problem is in determining which unit's operation code to record. We
1463 cannot blindly use the unit field from the new command, as recorded in
1464 the controller, as preparation has ensured only that the target unit
1465 number is legal but not necessarily valid. Therefore, we must validate
1466 the unit number before accessing the unit's operation code.
1467
1468 If the unit number is invalid, the command will not start, but the
1469 compiler does not know this. Therefore, we must ensure that the saved
1470 operation code is initialized, or a "variable used uninitialized" warning
1471 will occur.
1472 */
1473
start_command(void)1474 static void start_command (void)
1475 {
1476 int32 unit, time;
1477 UNIT *uptr;
1478 CNTLR_OPCODE drive_command;
1479
1480 unit = GET_S1UNIT (mac_cntlr.spd_unit); /* get the (prepared) unit from the command */
1481
1482 if (unit <= DL_MAXDRIVE) /* is the unit number valid? */
1483 drive_command = (CNTLR_OPCODE) ds_unit [unit].Op; /* get the opcode from the unit that will be used */
1484 else /* the unit is invalid, so the command will not start */
1485 drive_command = End; /* but the compiler doesn't know this! */
1486
1487 uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */
1488
1489 if (uptr) { /* did the command start? */
1490 time = uptr->wait; /* save the activation time */
1491
1492 if (time) /* was the unit scheduled? */
1493 activate_unit (uptr); /* activate it (and clear the "wait" field) */
1494
1495 if (time == 0) /* was the unit busy? */
1496 tprintf (ds_dev, DEB_RWSC, "Unit %d %s in progress\n",
1497 uptr - ds_unit, dl_opcode_name (MAC, drive_command));
1498
1499 if (uptr - ds_unit > DL_MAXDRIVE)
1500 tprintf (ds_dev, DEB_RWSC, "Controller %s command initiated\n",
1501 dl_opcode_name (MAC, mac_cntlr.opcode));
1502 else
1503 tprintf (ds_dev, DEB_RWSC, "Unit %d position %" T_ADDR_FMT "d %s command initiated\n",
1504 uptr - ds_unit, uptr->pos, dl_opcode_name (MAC, mac_cntlr.opcode));
1505 }
1506
1507 else { /* the command failed to start */
1508 ds.flag_buffer = SET; /* so set the data flag */
1509 io_assert_ENF (&ds_dib); /* then assert it to notify the CPU */
1510 }
1511
1512 return;
1513 }
1514
1515
1516 /* Poll the interface for a new command.
1517
1518 If a new command is available, and the controller is not busy, prepare the
1519 command for execution. If preparation succeeded, and the command needs
1520 parameters before executing, set the flag to request the first one from the
1521 CPU. If no parameters are needed, the command is ready to execute.
1522
1523 If preparation failed, set the flag to notify the CPU. The controller
1524 status contains the reason for the failure.
1525 */
1526
poll_interface(void)1527 static void poll_interface (void)
1528 {
1529 if (ds.cmrdy == SET && mac_cntlr.state != cntlr_busy) { /* are the interface and controller ready? */
1530 buffer [0] = fifo_unload (); /* unload the command into the buffer */
1531
1532 if (dl_prepare_command (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* prepare the command; did it succeed? */
1533 if (mac_cntlr.length) { /* does the command require parameters? */
1534 ds.flag_buffer = SET; /* set the data flag */
1535 io_assert_ENF (&ds_dib); /* then assert it to request the first parameter */
1536 }
1537
1538 else /* otherwise if not waiting for parameters */
1539 start_command (); /* then start the command immediately */
1540
1541 else { /* otherwise command preparation failed */
1542 ds.flag_buffer = SET; /* so set the data flag */
1543 io_assert_ENF (&ds_dib); /* then and assert it to request an interrupt */
1544 }
1545
1546 ds.cmrdy = CLEAR; /* flush the command from the interface */
1547 }
1548
1549 return;
1550 }
1551
1552
1553 /* Poll the drives for attention requests.
1554
1555 If the controller is idle and interrupts are allowed, the drives are polled
1556 to see if any drive is requesting attention. If one is found, the controller
1557 resets that drive's Attention status, saves the drive's unit number, sets
1558 Drive Attention status, and waits for a command from the CPU. The interface
1559 sets the flag to notify the CPU.
1560 */
1561
poll_drives(void)1562 static void poll_drives (void)
1563 {
1564 if (mac_cntlr.state == cntlr_idle && ds.control == SET) { /* is the controller idle and interrupts are allowed? */
1565 tprintf (ds_dev, DEB_RWSC, "Controller polled drives for attention\n");
1566
1567 if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) { /* poll the drives; was Attention seen? */
1568 ds.flag_buffer = SET; /* set the data flag */
1569
1570 tprintf (ds_dev, DEB_RWSC, "Unit %u requested attention\n",
1571 mac_cntlr.poll_unit);
1572
1573 io_assert_ENF (&ds_dib); /* assert it to request an interrupt */
1574 }
1575 }
1576
1577 return;
1578 }
1579
1580
1581 /* Load a word into the FIFO.
1582
1583 A word is loaded into the next available location in the FIFO, and the FIFO
1584 occupancy count is incremented. If the FIFO is full on entry, the load is
1585 ignored.
1586
1587
1588 Implementation notes:
1589
1590 1. The FIFO is implemented as circular queue to take advantage of REG_CIRC
1591 EXAMINE semantics. REG->qptr is the index of the first word currently in
1592 the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always
1593 display the words in load order, regardless of the actual array index of
1594 the start of the list. The number of words currently present in the FIFO
1595 is kept in fifo_count (0 = empty, 1-16 = number of words available).
1596
1597 If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the
1598 index of the new word location. Loading stores the word there and then
1599 increments fifo_count.
1600
1601 2. Because the load and unload routines need access to qptr in the REG
1602 structure for the FIFO array, a pointer to the REG is stored in the
1603 fifo_reg variable during device reset.
1604 */
1605
fifo_load(uint16 data)1606 static void fifo_load (uint16 data)
1607 {
1608 uint32 index;
1609
1610 if (FIFO_FULL) { /* is the FIFO already full? */
1611 tprintf (ds_dev, DEB_BUF, "Attempted load to full FIFO, data %06o\n", data);
1612
1613 return; /* return with the load ignored */
1614 }
1615
1616 index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE; /* calculate the index of the next available location */
1617
1618 ds.fifo [index] = data; /* store the word in the FIFO */
1619 ds.fifo_count = ds.fifo_count + 1; /* increment the count of words stored */
1620
1621 tprintf (ds_dev, DEB_BUF, "Data %06o loaded into FIFO [%d]\n",
1622 data, ds.fifo_count);
1623
1624 return;
1625 }
1626
1627
1628 /* Unload a word from the FIFO.
1629
1630 A word is unloaded from the first location in the FIFO, and the FIFO
1631 occupancy count is decremented. If the FIFO is empty on entry, the unload
1632 returns dummy data.
1633
1634
1635 Implementation notes:
1636
1637 1. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal
1638 gets the word and then increments qptr (mod FIFO_SIZE) and decrements
1639 fifo_count.
1640 */
1641
fifo_unload(void)1642 static uint16 fifo_unload (void)
1643 {
1644 uint16 data;
1645
1646 if (FIFO_EMPTY) { /* is the FIFO already empty? */
1647 tprintf (ds_dev, DEB_BUF, "Attempted unload from empty FIFO\n");
1648 return 0; /* return with no data */
1649 }
1650
1651 data = ds.fifo [ds.fifo_reg->qptr]; /* get the word from the FIFO */
1652
1653 ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE; /* update the FIFO queue pointer */
1654 ds.fifo_count = ds.fifo_count - 1; /* decrement the count of words stored */
1655
1656 tprintf (ds_dev, DEB_BUF, "Data %06o unloaded from FIFO [%d]\n",
1657 data, ds.fifo_count);
1658
1659 return data;
1660 }
1661
1662
1663 /* Clear the FIFO.
1664
1665 The FIFO is cleared by setting the occupancy counter to zero.
1666 */
1667
fifo_clear(void)1668 static void fifo_clear (void)
1669 {
1670 ds.fifo_count = 0; /* clear the FIFO */
1671
1672 tprintf (ds_dev, DEB_BUF, "FIFO cleared\n");
1673
1674 return;
1675 }
1676
1677
1678 /* Activate the unit.
1679
1680 The specified unit is activated using the unit's "wait" time. If debugging
1681 is enabled, the activation is logged to the debug file.
1682 */
1683
activate_unit(UNIT * uptr)1684 static t_stat activate_unit (UNIT *uptr)
1685 {
1686 t_stat result;
1687
1688 if (uptr == &ds_cntlr)
1689 tprintf (ds_dev, TRACE_SERV, "Controller delay %d service scheduled\n",
1690 uptr->wait);
1691 else
1692 tprintf (ds_dev, TRACE_SERV, "Unit %d delay %d service scheduled\n",
1693 uptr - ds_unit, uptr->wait);
1694
1695 result = sim_activate (uptr, uptr->wait); /* activate the unit */
1696 uptr->wait = 0; /* reset the activation time */
1697
1698 return result; /* return the activation status */
1699 }
1700