First Commit of my working state
[simh.git] / HP2100 / hp2100_ds.c
1 /* hp2100_ds.c: HP 2100 13037 disk controller simulator
2
3 Copyright (c) 2004-2007, Robert M. Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 ds 13037 disk controller
27
28 31-Dec-07 JDB Corrected and verified ioCRS action
29 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA
30 28-Dec-06 JDB Added ioCRS state to I/O decoders
31 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1
32 Removed redundant attached test in "ds_detach"
33 18-Mar-05 RMS Added attached test to detach routine
34 01-Mar-05 JDB Added SET UNLOAD/LOAD
35
36 States of the controller: the controller uP runs all the time, but most of
37 the time it is waiting for an event. The simulator only 'runs' the controller
38 when there's an event to process: change in CPU interface state, change in
39 disk state, or timeout. The controller has three states:
40
41 - Idle. No operations other than seek or recalibrate are in progress, and
42 the CPU interface is disconnected. The controller responds both to new
43 commands and to drive attention interrupts.
44 - Wait. No operations other than seek or recalibrate are in progress, but
45 the CPU interface is connected. The controller responds to new commands
46 but not to drive attention interrupts.
47 - Busy. The controller is processing a command. The controller does not
48 respond to new commands or to drive attention interrupts.
49
50 The controller busy state is loosely related to the testable (visible) busy
51 flop. If the visible busy flop is set, the controller is in the busy state;
52 but the controller can also be busy (processing an invalid opcode or invalid
53 unit) while visible busy is clear.
54
55 Omissions: the following features are not implemented:
56
57 - Drive hold. Since this is a single CPU implementation, the drives are
58 always available to the CPU.
59 - Spare, defective, protected. The disk files carry only data.
60 - Formatting. The disk files carry only data.
61 - ECC. Data errors are always uncorrectable.
62
63 Reference:
64 - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980)
65 */
66
67 #include "hp2100_defs.h"
68 #include <math.h>
69
70 #define DS_NUMDR 8 /* max drives */
71 #define DS_DRMASK (DS_NUMDR - 1)
72 #define DS_NUMWD 128 /* data words/sec */
73 #define DS_NUMWDF 138 /* total words/sec */
74 #define DS_FSYNC 0 /* sector offsets */
75 #define DS_FCYL 1
76 #define DS_FHS 2
77 #define DS_FDATA 3
78 #define DS_FIFO_SIZE 16 /* fifo size */
79 #define DS_FIFO_EMPTY (ds_fifo_cnt == 0)
80 #define ds_ctrl ds_unit[DS_NUMDR] /* ctrl thread */
81 #define ds_timer ds_unit[DS_NUMDR + 1] /* timeout thread */
82 #define GET_CURSEC(x,d) ((int32) fmod (sim_gtime() / ((double) (x)), \
83 ((double) (drv_tab[d].sc))))
84
85 /* Flags in the unit flags word */
86
87 #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
88 #define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */
89 #define UNIT_V_DTYPE (UNIT_V_UF + 2) /* disk type */
90 #define UNIT_M_DTYPE 3
91 #define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */
92 #define UNIT_V_FMT (UNIT_V_UF + 5) /* format enabled */
93 #define UNIT_WLK (1 << UNIT_V_WLK)
94 #define UNIT_FMT (1 << UNIT_V_FMT)
95 #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
96 #define UNIT_AUTO (1 << UNIT_V_AUTO)
97 #define UNIT_UNLOAD (1 << UNIT_V_UNLOAD)
98 #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
99 #define UNIT_WPR (UNIT_WLK | UNIT_RO) /* write prot */
100
101 /* Parameters in the unit descriptor */
102
103 #define FNC u3 /* function */
104 #define CYL u4 /* current cylinder */
105 #define STA u5 /* status */
106
107 /* Arguments to subroutines */
108
109 #define CLR_BUSY 0 /* clear visible busy */
110 #define SET_BUSY 1 /* set visible busy */
111
112 /* Command word - <12:8> are opcode, <7:0> are opcode dependent
113
114 cold load read <7:6> = head
115 <5:0> = sector
116 set file mask <7:4> = retry count
117 <3:0> = file mask (auto-seek options)
118 commands with units <7> = hold flag
119 <4:0> = unit number */
120
121 #define DSC_V_OP 8 /* opcode */
122 #define DSC_M_OP 037
123 #define DSC_COLD 000 /* cold load read */
124 #define DSC_RECAL 001 /* recalibrate */
125 #define DSC_SEEK 002 /* seek */
126 #define DSC_RSTA 003 /* request status */
127 #define DSC_RSA 004 /* request sector addr */
128 #define DSC_READ 005 /* read */
129 #define DSC_RFULL 006 /* read full */
130 #define DSC_VFY 007 /* verify */
131 #define DSC_WRITE 010 /* write */
132 #define DSC_WFULL 011 /* write full */
133 #define DSC_CLEAR 012 /* clear */
134 #define DSC_INIT 013 /* initialize */
135 #define DSC_AREC 014 /* address record */
136 #define DSC_RSYN 015 /* request syndrome */
137 #define DSC_ROFF 016 /* read with offset */
138 #define DSC_SFM 017 /* set file mask */
139 #define DSC_RNOVFY 022 /* read no verify */
140 #define DSC_WTIO 023 /* write TIO */
141 #define DSC_RDA 024 /* request disk addr */
142 #define DSC_END 025 /* end */
143 #define DSC_WAKE 026 /* wakeup */
144 #define DSC_ATN 035 /* pseudo: ATN */
145 #define DSC_BADU 036 /* pseudo: bad unit */
146 #define DSC_BADF 037 /* pseudo: bad opcode */
147 #define DSC_NEXT 0040 /* state increment */
148 #define DSC_2ND 0040 /* subcommand states */
149 #define DSC_3RD 0100
150 #define DSC_4TH 0140
151 #define DSC_V_CHD 6 /* cold load head */
152 #define DSC_M_CHD 03
153 #define DSC_V_CSC 0 /* cold load sector */
154 #define DSC_M_CSC 077
155 #define DSC_V_RTY 4 /* retry count */
156 #define DSC_M_RTY 017
157 #define DSC_V_DECR 3 /* seek decrement */
158 #define DSC_V_SPEN 2 /* enable sparing */
159 #define DSC_V_CYLM 1 /* cylinder mode */
160 #define DSC_V_AUTO 0 /* auto seek */
161 #define DSC_V_HOLD 7 /* hold flag */
162 #define DSC_V_UNIT 0 /* unit */
163 #define DSC_M_UNIT 017
164 #define DSC_V_SPAR 15 /* INIT spare */
165 #define DSC_V_PROT 14 /* INIT protected */
166 #define DSC_V_DFCT 13 /* INIT defective */
167
168 #define DSC_HOLD (1u << DSC_V_HOLD)
169 #define DSC_DECR (1u << DSC_V_DECR)
170 #define DSC_SPEN (1u << DSC_V_SPEN)
171 #define DSC_CYLM (1u << DSC_V_CYLM)
172 #define DSC_AUTO (1u << DSC_V_AUTO)
173 #define DSC_FMASK ((DSC_M_RTY << DSC_V_RTY)|DSC_DECR|\
174 DSC_SPEN|DSC_CYLM|DSC_AUTO)
175 #define DSC_GETOP(x) (((x) >> DSC_V_OP) & DSC_M_OP)
176 #define DSC_GETUNIT(x) (((x) >> DSC_V_UNIT) & DSC_M_UNIT)
177 #define DSC_GETCHD(x) (((x) >> DSC_V_CHD) & DSC_M_CHD)
178 #define DSC_GETCSC(x) (((x) >> DSC_V_CSC) & DSC_M_CSC)
179 #define DSC_SPAR (1u << DSC_V_SPAR)
180 #define DSC_PROT (1u << DSC_V_PROT)
181 #define DSC_DFCT (1u << DSC_V_DFCT)
182
183 /* Command flags */
184
185 #define CMF_UNDF 001 /* undefined */
186 #define CMF_CLREC 002 /* clear eoc flag */
187 #define CMF_CLRS 004 /* clear status */
188 #define CMF_UIDLE 010 /* requires unit no */
189
190 /* Cylinder words - 16b */
191
192 /* Head/sector word */
193
194 #define DSHS_V_HD 8 /* head */
195 #define DSHS_M_HD 037
196 #define DSHS_V_SC 0 /* sector */
197 #define DSHS_M_SC 0377
198 #define DSHS_HD (DSHS_M_HD << DSHS_V_HD)
199 #define DSHS_SC (DSHS_M_SC << DSHS_V_SC)
200 #define DSHS_GETHD(x) (((x) >> DSHS_V_HD) & DSHS_M_HD)
201 #define DSHS_GETSC(x) (((x) >> DSHS_V_SC) & DSHS_M_SC)
202
203 /* Status 1 */
204
205 #define DS1_V_SPAR 15 /* spare - na */
206 #define DS1_V_PROT 14 /* protected - na */
207 #define DS1_V_DFCT 13 /* defective - na */
208 #define DS1_V_STAT 8 /* status */
209 #define DS1_OK (000 << DS1_V_STAT) /* normal */
210 #define DS1_ILLOP (001 << DS1_V_STAT) /* illegal opcode */
211 #define DS1_AVAIL (002 << DS1_V_STAT) /* available */
212 #define DS1_CYLCE (007 << DS1_V_STAT) /* cyl compare err */
213 #define DS1_UNCOR (010 << DS1_V_STAT) /* uncor data err */
214 #define DS1_HSCE (011 << DS1_V_STAT) /* h/s compare err */
215 #define DS1_IOPE (012 << DS1_V_STAT) /* IO oper err - na */
216 #define DS1_EOCYL (014 << DS1_V_STAT) /* end cylinder */
217 #define DS1_OVRUN (016 << DS1_V_STAT) /* overrun */
218 #define DS1_CORDE (017 << DS1_V_STAT) /* correctible - na */
219 #define DS1_ILLST (020 << DS1_V_STAT) /* illegal spare - na */
220 #define DS1_DEFTK (021 << DS1_V_STAT) /* defective trk - na */
221 #define DS1_ACCER (022 << DS1_V_STAT) /* access not rdy - na */
222 #define DS1_S2ERR (023 << DS1_V_STAT) /* status 2 error */
223 #define DS1_TKPER (026 << DS1_V_STAT) /* protected trk - na */
224 #define DS1_UNAVL (027 << DS1_V_STAT) /* illegal unit */
225 #define DS1_ATN (037 << DS1_V_STAT) /* attention */
226 #define DS1_V_UNIT 0
227 #define DS1_SPAR (1u << DS1_V_SPAR)
228 #define DS1_PROT (1u << DS1_V_PROT)
229 #define DS1_DFCT (1u << DS1_V_DFCT)
230
231 /* Status 2, ^ = kept in unit status, * = dynamic */
232
233 #define DS2_ERR 0100000 /* *error */
234 #define DS2_V_ID 9 /* drive type */
235 #define DS2_ATN 0000200 /* ^attention */
236 #define DS2_RO 0000100 /* *read only */
237 #define DS2_FRM 0000040 /* *format */
238 #define DS2_FLT 0000020 /* fault - na */
239 #define DS2_FS 0000010 /* ^first status */
240 #define DS2_SC 0000004 /* ^seek error */
241 #define DS2_NR 0000002 /* *not ready */
242 #define DS2_BS 0000001 /* *busy */
243 #define DS2_ALLERR (DS2_FLT|DS2_SC|DS2_NR|DS2_BS)
244
245 /* Controller state */
246
247 #define DS_IDLE 0 /* idle */
248 #define DS_WAIT 1 /* command wait */
249 #define DS_BUSY 2 /* busy */
250
251 /* This controller supports four different disk drive types:
252
253 type #sectors/ #surfaces/ #cylinders/
254 surface cylinder drive
255
256 7905 48 3 411 =15MB
257 7906 48 4 411 =20MB
258 7920 48 5 823 =50MB
259 7925 64 9 823 =120MB
260
261 In theory, each drive can be a different type. The size field in
262 each unit selects the drive capacity for each drive and thus the
263 drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.
264
265 The 7905 and 7906 have fixed and removable platters. Consequently,
266 they are almost always accessed with cylinders limited to each
267 platter. The 7920 and 7925 have multiple-platter packs, and so are
268 almost always accessed with cylinders that span all surfaces.
269
270 Disk image files are arranged as a linear set of tracks. To improve
271 locality, tracks on the 7905 and 7906 images are grouped per-platter,
272 i.e., all tracks on heads 0 and 1, followed by all tracks on head 2
273 (and, for the 7906, head 3), whereas tracks on the 7920 and 7925 are
274 sequential by cylinder and head number.
275
276 This variable-access geometry is accomplished by defining a "heads
277 per cylinder" value for the fixed and removable sections of each
278 drive that indicates the number of heads that should be grouped for
279 locality. The removable values are set to 2 on the 7905 and 7906,
280 indicating that those drives typically use cylinders of two surfaces.
281 They are set to the number of surfaces per drive for the 7920 and
282 7925, as those typically use cylinders encompassing the entire
283 spindle.
284 */
285
286 #define GET_DA(x,y,z,t) \
287 (((((y) < drv_tab[t].rh)? \
288 (x) * drv_tab[t].rh + (y): \
289 drv_tab[t].cyl * drv_tab[t].rh + \
290 ((x) * drv_tab[t].fh + (y) - drv_tab[t].rh)) * \
291 drv_tab[t].sc + (z)) * DS_NUMWD)
292
293 #define D7905_DTYPE 0
294 #define D7905_SECT 48
295 #define D7905_SURF 3
296 #define D7905_RH 2
297 #define D7905_FH (D7905_SURF - D7905_RH)
298 #define D7905_CYL 411
299 #define D7905_ID (2 << DS2_V_ID)
300 #define D7905_SIZE (D7905_SECT * D7905_SURF * D7905_CYL * DS_NUMWD)
301
302 #define D7906_DTYPE 1
303 #define D7906_SECT 48
304 #define D7906_SURF 4
305 #define D7906_RH 2
306 #define D7906_FH (D7906_SURF - D7906_RH)
307 #define D7906_CYL 411
308 #define D7906_ID (0 << DS2_V_ID)
309 #define D7906_SIZE (D7906_SECT * D7906_SURF * D7906_CYL * DS_NUMWD)
310
311 #define D7920_DTYPE 2
312 #define D7920_SECT 48
313 #define D7920_SURF 5
314 #define D7920_RH D7920_SURF
315 #define D7920_FH (D7920_SURF - D7920_RH)
316 #define D7920_CYL 823
317 #define D7920_ID (1 << DS2_V_ID)
318 #define D7920_SIZE (D7920_SECT * D7920_SURF * D7920_CYL * DS_NUMWD)
319
320 #define D7925_DTYPE 3
321 #define D7925_SECT 64
322 #define D7925_SURF 9
323 #define D7925_RH D7925_SURF
324 #define D7925_FH (D7925_SURF - D7925_RH)
325 #define D7925_CYL 823
326 #define D7925_ID (3 << DS2_V_ID)
327 #define D7925_SIZE (D7925_SECT * D7925_SURF * D7925_CYL * DS_NUMWD)
328
329 struct drvtyp {
330 uint32 sc; /* sectors */
331 uint32 hd; /* surfaces */
332 uint32 cyl; /* cylinders */
333 uint32 size; /* #blocks */
334 uint32 id; /* device type */
335 uint32 rh; /* removable surfaces */
336 uint32 fh; /* fixed surfaces */
337 };
338
339 static struct drvtyp drv_tab[] = {
340 { D7905_SECT, D7905_SURF, D7905_CYL, D7905_SIZE, D7905_ID, D7905_RH, D7905_FH },
341 { D7906_SECT, D7906_SURF, D7906_CYL, D7906_SIZE, D7906_ID, D7906_RH, D7906_FH },
342 { D7920_SECT, D7920_SURF, D7920_CYL, D7920_SIZE, D7920_ID, D7920_RH, D7920_FH },
343 { D7925_SECT, D7925_SURF, D7925_CYL, D7925_SIZE, D7925_ID, D7925_RH, D7925_FH },
344 { 0 }
345 };
346
347 extern uint32 PC, SR;
348 extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
349 extern int32 sim_switches;
350
351 uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */
352 uint32 ds_fifo_ip = 0; /* insertion ptr */
353 uint32 ds_fifo_rp = 0; /* removal ptr */
354 uint32 ds_fifo_cnt = 0; /* count */
355 uint32 ds_cmd = 0; /* command word */
356 uint32 ds_sr1 = 0; /* status word 1 */
357 uint32 ds_busy = 0; /* busy flag */
358 uint32 ds_eoc = 0; /* end of cylinder */
359 uint32 ds_eod = 0; /* end of data */
360 uint32 ds_fmask = 0; /* file mask */
361 uint32 ds_cmdf = 0; /* command follows */
362 uint32 ds_cmdp = 0; /* command present */
363 uint32 ds_cyl = 0; /* disk address: cyl */
364 uint32 ds_hs = 0; /* disk address: hs */
365 uint32 ds_vctr = 0; /* verify counter */
366 uint32 ds_state = 0; /* controller state */
367 uint32 ds_lastatn = 0; /* last atn intr */
368 int32 ds_stime = 100; /* seek time */
369 int32 ds_rtime = 100; /* inter-sector time */
370 int32 ds_ctime = 3; /* command time */
371 int32 ds_dtime = 1; /* dch time */
372 int32 ds_tmo = 2749200; /* timeout = 1.74 sec */
373 uint32 ds_ptr = 0; /* buffer ptr */
374 uint16 dsxb[DS_NUMWDF]; /* sector buffer */
375
376 static const uint32 ds_opflags[32] = { /* flags for ops */
377 CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* cold read */
378 CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* recalibrate */
379 CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* seek */
380 0, /* read status */
381 CMF_CLRS, /* read sector */
382 CMF_CLRS|CMF_UIDLE, /* read */
383 CMF_CLRS|CMF_UIDLE, /* read full */
384 CMF_CLRS|CMF_UIDLE, /* verify */
385 CMF_CLRS|CMF_UIDLE, /* write */
386 CMF_CLRS|CMF_UIDLE, /* write full */
387 CMF_CLRS, /* clear */
388 CMF_CLRS|CMF_UIDLE, /* init */
389 CMF_CLREC|CMF_CLRS, /* addr record */
390 0, /* read syndrome */
391 CMF_CLRS|CMF_UIDLE, /* read offset */
392 CMF_CLRS, /* set file mask */
393 CMF_UNDF|CMF_CLRS, /* undefined */
394 CMF_UNDF|CMF_CLRS, /* undefined */
395 CMF_CLRS|CMF_UIDLE, /* read no verify */
396 CMF_CLRS, /* write TIO */
397 CMF_CLRS, /* read disk addr */
398 CMF_CLRS, /* end */
399 CMF_CLRS, /* wake */
400 CMF_UNDF|CMF_CLRS, /* undefined */
401 CMF_UNDF|CMF_CLRS, /* undefined */
402 CMF_UNDF|CMF_CLRS, /* undefined */
403 CMF_UNDF|CMF_CLRS, /* undefined */
404 CMF_UNDF|CMF_CLRS, /* undefined */
405 CMF_UNDF|CMF_CLRS, /* undefined */
406 CMF_UNDF|CMF_CLRS, /* undefined */
407 CMF_UNDF|CMF_CLRS, /* undefined */
408 CMF_UNDF|CMF_CLRS /* undefined */
409 };
410
411 DEVICE ds_dev;
412 int32 dsio (int32 inst, int32 IR, int32 dat);
413 t_stat ds_svc_c (UNIT *uptr);
414 t_stat ds_svc_u (UNIT *uptr);
415 t_stat ds_svc_t (UNIT *uptr);
416 t_stat ds_reset (DEVICE *dptr);
417 t_stat ds_attach (UNIT *uptr, char *cptr);
418 t_stat ds_detach (UNIT *uptr);
419 t_stat ds_boot (int32 unitno, DEVICE *dptr);
420 t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);
421 t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
422 void ds_poll (void);
423 void ds_docmd (uint32 cmd);
424 void ds_doatn (void);
425 uint32 ds_updds2 (UNIT *uptr);
426 void ds_cmd_done (t_bool sf, uint32 sr1);
427 void ds_wait_for_cpu (UNIT *uptr, uint32 newst);
428 void ds_set_idle (void);
429 void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy);
430 void ds_reqad (uint16 *cyl, uint16 *hs);
431 void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst);
432 t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy);
433 void ds_next_sec (UNIT *uptr);
434 void ds_next_cyl (UNIT *uptr);
435 t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy);
436 void ds_start_wr (UNIT *uptr, t_bool vfy);
437 void ds_cont_rd (UNIT *uptr, uint32 bsize);
438 t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize);
439 void ds_end_rw (UNIT *uptr, uint32 newst);
440 t_stat ds_set_uncorr (UNIT *uptr);
441 t_stat ds_reset_cmn (DEVICE *dptr);
442 void ds_sched_atn (UNIT *uptr);
443 uint32 ds_fifo_read (void);
444 void ds_fifo_write (uint32 dat);
445 void ds_fifo_reset (void);
446
447 /* DS data structures
448
449 ds_dev DS device descriptor
450 ds_unit DS unit list
451 ds_reg DS register list
452 ds_mod DS modifier list
453 */
454
455 DIB ds_dib = { DS, 0, 0, 0, 0, 0, &dsio };
456
457 UNIT ds_unit[] = {
458 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
459 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
460 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
461 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
462 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
463 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
464 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
465 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
466 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
467 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
468 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
469 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
470 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
471 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
472 { UDATA (&ds_svc_u, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |
473 UNIT_DISABLE | UNIT_UNLOAD, D7905_SIZE) },
474 { UDATA (&ds_svc_c, UNIT_DIS, 0) },
475 { UDATA (&ds_svc_t, UNIT_DIS, 0) }
476 };
477
478 REG ds_reg[] = {
479 { ORDATA (CMD, ds_cmd, 16) },
480 { BRDATA (FIFO, ds_fifo, 8, 16, DS_FIFO_SIZE) },
481 { ORDATA (SR1, ds_sr1, 16) },
482 { ORDATA (VCTR, ds_vctr, 16) },
483 { ORDATA (FMASK, ds_fmask, 8) },
484 { ORDATA (CYL, ds_cyl, 16) },
485 { ORDATA (HS, ds_hs, 16) },
486 { ORDATA (STATE, ds_state, 2), REG_RO },
487 { ORDATA (LASTA, ds_lastatn, 3) },
488 { DRDATA (FIP, ds_fifo_ip, 4) },
489 { DRDATA (FRP, ds_fifo_rp, 4) },
490 { DRDATA (FCNT, ds_fifo_cnt, 5) },
491 { FLDATA (CMD, ds_dib.cmd, 0), REG_HRO },
492 { FLDATA (CTL, ds_dib.ctl, 0) },
493 { FLDATA (FLG, ds_dib.flg, 0) },
494 { FLDATA (FBF, ds_dib.fbf, 0) },
495 { FLDATA (SRQ, ds_dib.srq, 0) },
496 { FLDATA (BUSY, ds_busy, 0) },
497 { FLDATA (CMDF, ds_cmdf, 0) },
498 { FLDATA (CMDP, ds_cmdp, 0) },
499 { FLDATA (EOC, ds_eoc, 0) },
500 { FLDATA (EOD, ds_eod, 0) },
501 { BRDATA (DBUF, dsxb, 8, 16, DS_NUMWDF) },
502 { DRDATA (DPTR, ds_ptr, 8) },
503 { DRDATA (CTIME, ds_ctime, 24), PV_LEFT + REG_NZ },
504 { DRDATA (DTIME, ds_dtime, 24), PV_LEFT + REG_NZ },
505 { DRDATA (STIME, ds_stime, 24), PV_LEFT + REG_NZ },
506 { DRDATA (RTIME, ds_rtime, 24), PV_LEFT + REG_NZ },
507 { DRDATA (TIMEOUT, ds_tmo, 31), PV_LEFT + REG_NZ },
508 { URDATA (UCYL, ds_unit[0].CYL, 10, 10, 0,
509 DS_NUMDR + 1, PV_LEFT | REG_HRO) },
510 { URDATA (UFNC, ds_unit[0].FNC, 8, 8, 0,
511 DS_NUMDR + 1, REG_HRO) },
512 { URDATA (USTA, ds_unit[0].STA, 8, 16, 0,
513 DS_NUMDR + 1, REG_HRO) },
514 { URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0,
515 DS_NUMDR, PV_LEFT | REG_HRO) },
516 { ORDATA (DEVNO, ds_dib.devno, 6), REG_HRO },
517 { NULL }
518 };
519
520 MTAB ds_mod[] = {
521 { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", ds_load_unload },
522 { UNIT_UNLOAD, 0, "heads loaded", "LOADED", ds_load_unload },
523 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
524 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
525 { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL },
526 { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL },
527 { (UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
528 "7905", NULL, NULL },
529 { (UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
530 "7906", NULL, NULL },
531 { (UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
532 "7920", NULL, NULL },
533 { (UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
534 "7925", NULL, NULL },
535 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE),
536 "7905", NULL, NULL },
537 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE),
538 "7906", NULL, NULL },
539 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE),
540 "7920", NULL, NULL },
541 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE),
542 "7925", NULL, NULL },
543 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
544 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
545 { (UNIT_AUTO+UNIT_DTYPE), (D7905_DTYPE << UNIT_V_DTYPE),
546 NULL, "7905", &ds_set_size },
547 { (UNIT_AUTO+UNIT_DTYPE), (D7906_DTYPE << UNIT_V_DTYPE),
548 NULL, "7906", &ds_set_size },
549 { (UNIT_AUTO+UNIT_DTYPE), (D7920_DTYPE << UNIT_V_DTYPE),
550 NULL, "7920", &ds_set_size },
551 { (UNIT_AUTO+UNIT_DTYPE), (D7925_DTYPE << UNIT_V_DTYPE),
552 NULL, "7925", &ds_set_size },
553 { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
554 &hp_setdev, &hp_showdev, &ds_dev },
555 { 0 }
556 };
557
558 DEVICE ds_dev = {
559 "DS", ds_unit, ds_reg, ds_mod,
560 DS_NUMDR + 2, 8, 27, 1, 8, 16,
561 NULL, NULL, &ds_reset,
562 &ds_boot, &ds_attach, &ds_detach,
563 &ds_dib, DEV_DISABLE
564 };
565
566 /* IO instructions */
567
568 int32 dsio (int32 inst, int32 IR, int32 dat)
569 {
570 uint32 dev = IR & I_DEVMASK;
571
572 switch (inst) { /* case on opcode */
573
574 case ioFLG: /* flag clear/set */
575 if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
576 break;
577
578 case ioSFS: /* skip flag set */
579 if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
580 break;
581
582 case ioSFC: /* skip flag clear */
583 if (ds_busy == 0) PC = (PC + 1) & VAMASK;
584 break;
585
586 case ioOTX: /* output */
587 if (ds_cmdf) { /* expecting command? */
588 ds_cmd = dat; /* save command */
589 ds_cmdf = 0;
590 ds_cmdp = 1; /* command present */
591 }
592 else ds_fifo_write (dat); /* put in fifo */
593 break;
594
595 case ioMIX: /* merge */
596 dat = dat | ds_fifo_read ();
597 break;
598
599 case ioLIX: /* load */
600 dat = ds_fifo_read ();
601 break;
602
603 case ioCRS: /* control reset */
604 clrCTL (dev); /* clear control */
605 ds_cmdf = 0; /* not expecting command */
606 ds_cmdp = 0; /* and none pending */
607 ds_reset_cmn (&ds_dev); /* reset ctrl */
608 break;
609
610 case ioCTL: /* control clear/set */
611 if (IR & I_CTL) { /* CLC */
612 clrCTL (dev); /* clear control */
613 ds_cmdf = 1; /* expecting command */
614 ds_cmdp = 0; /* none pending */
615 ds_fifo_reset (); /* clear fifo */
616 }
617 else { /* STC */
618 setCTL (dev); /* set ctl */
619 }
620 break;
621
622 case ioEDT: /* end of transfer */
623 ds_eod = 1; /* flag end transfer */
624 break;
625
626 default:
627 break;
628 }
629
630 if (IR & I_HC) { clrFSR (dev); } /* H/C option */
631 ds_poll (); /* run the controller */
632 return dat;
633 }
634
635 /* Run the controller polling loop, based on ds_state:
636
637 IDLE commands and ATN interrupts
638 WAIT commands only
639 BUSY nothing
640 */
641
642 void ds_poll (void)
643 {
644 int32 dev = ds_dib.devno;
645
646 if ((ds_state != DS_BUSY) && ds_cmdp) ds_docmd (ds_cmd);/* cmd pending? */
647 if ((ds_state == DS_IDLE) && CTL (dev)) ds_doatn (); /* idle? check ATN */
648 return;
649 }
650
651 /* Process a command - ctrl state is either IDLE or WAIT.
652
653 - A drive may be processing a seek or recalibrate
654 - The controller unit is idle
655 - If the command can be processed, ds_state is set to BUSY, and
656 the interface command buffer is cleared
657 - If the command cannot be processed, ds_state is set to WAIT,
658 and the command is retained in the interface command buffer */
659
660 void ds_docmd (uint32 cmd)
661 {
662 uint32 op, f, dtyp, unum;
663
664 op = DSC_GETOP (cmd); /* operation */
665 f = ds_opflags[op]; /* flags */
666 if (op == DSC_COLD) unum = 0; /* boot force unit 0 */
667 else unum = DSC_GETUNIT (cmd); /* get unit */
668 if ((f & CMF_UIDLE) && (unum < DS_NUMDR) && /* idle required */
669 sim_is_active (&ds_unit[unum])) { /* but unit busy? */
670 ds_state = DS_WAIT; /* wait */
671 return;
672 }
673 ds_cmdp = 0; /* flush command */
674 ds_state = DS_BUSY; /* ctrl is busy */
675 if (f & CMF_CLRS) ds_sr1 = 0; /* clear status */
676 if (f & CMF_CLREC) ds_eoc = 0; /* clear end cyl */
677 if (f & CMF_UNDF) { /* illegal op? */
678 ds_sched_ctrl_op (DSC_BADF, 0, CLR_BUSY); /* sched, clr busy */
679 return;
680 }
681 switch (op) {
682
683 /* Drive commands */
684
685 case DSC_COLD: /* cold load read */
686 ds_fmask = DSC_SPEN; /* sparing enabled */
687 ds_cyl = 0; /* cylinder 0 */
688 ds_hs = (DSC_GETCHD (ds_cmd) << DSHS_V_HD) | /* reformat hd/sec */
689 (DSC_GETCSC (ds_cmd) << DSHS_V_SC);
690 case DSC_RECAL: /* recalibrate */
691 case DSC_SEEK: /* seek */
692 case DSC_READ: /* read */
693 case DSC_RFULL: /* read full */
694 case DSC_ROFF: /* read offset */
695 case DSC_RNOVFY: /* read no verify */
696 case DSC_VFY: /* verify */
697 case DSC_WRITE: /* write */
698 case DSC_WFULL: /* write full */
699 case DSC_INIT: /* init */
700 ds_sr1 = unum; /* init status */
701 if (unum >= DS_NUMDR) { /* invalid unit? */
702 ds_sched_ctrl_op (DSC_BADU, unum, CLR_BUSY);/* sched, not busy */
703 return;
704 }
705 if (op == DSC_INIT) ds_sr1 |= /* init? */
706 ((cmd & DSC_SPAR)? DS1_SPAR: 0) | /* copy SPD to stat1 */
707 ((cmd & DSC_PROT)? DS1_PROT: 0) |
708 ((cmd & DSC_DFCT)? DS1_DFCT: 0);
709 ds_unit[unum].FNC = op; /* save op */
710 ds_unit[unum].STA &= ~DS2_ATN; /* clear ATN */
711 sim_cancel (&ds_unit[unum]); /* cancel current */
712 sim_activate (&ds_unit[unum], ds_ctime); /* schedule unit */
713 ds_busy = 1; /* set visible busy */
714 break;
715
716 /* Read status commands */
717
718 case DSC_RSTA: /* read status */
719 dsxb[1] = ds_sr1; /* return SR1 */
720 ds_sr1 = 0; /* clear SR1 */
721 if (unum < DS_NUMDR) { /* return SR2 */
722 dsxb[0] = ds_updds2 (&ds_unit[unum]);
723 ds_unit[unum].STA &= ~DS2_FS; /* clear 1st */
724 }
725 else dsxb[0] = DS2_ERR|DS2_NR;
726 ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */
727 break;
728
729 case DSC_RSA: /* read sector address */
730 dtyp = GET_DTYPE (ds_unit[unum].flags); /* get unit type */
731 dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */
732 ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */
733 break;
734
735 case DSC_RDA: /* read disk address */
736 ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */
737 ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */
738 break;
739
740 case DSC_RSYN: /* read syndrome */
741 dsxb[6] = ds_sr1; /* return SR1 */
742 ds_reqad (&dsxb[5], &dsxb[4]); /* return disk address */
743 dsxb[3] = dsxb[2] = dsxb[1] = dsxb[0] = 0; /* syndrome is 0 */
744 ds_sched_ctrl_op (DSC_RSTA, 7, SET_BUSY); /* sched 7 wds, busy */
745 break;
746
747 /* Other controller commands */
748
749 case DSC_SFM: /* set file mask */
750 case DSC_CLEAR: /* clear */
751 case DSC_AREC: /* address record */
752 case DSC_WAKE: /* wakeup */
753 case DSC_WTIO: /* write TIO */
754 ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */
755 break;
756
757 case DSC_END: /* end */
758 ds_set_idle (); /* idle ctrl */
759 break;
760 }
761
762 return;
763 }
764
765 /* Check for attention */
766
767 void ds_doatn (void)
768 {
769 uint32 i, dev;
770
771 dev = ds_dib.devno; /* device num */
772 for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */
773 ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */
774 if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */
775 ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */
776 setFLG (dev); /* request interrupt */
777 ds_sr1 = DS1_ATN | ds_lastatn; /* set up status 1 */
778 ds_state = DS_WAIT; /* block atn intrs */
779 return;
780 }
781 }
782 return;
783 }
784
785 /* Controller service
786
787 The argument for the function, if any, is stored in uptr->CYL */
788
789 t_stat ds_svc_c (UNIT *uptr)
790 {
791 uint32 op, dev;
792
793 op = uptr->FNC;
794 dev = ds_dib.devno;
795 switch (op) {
796
797 case DSC_AREC: /* address record */
798 ds_wait_for_cpu (uptr, DSC_AREC|DSC_2ND); /* set flag, new state */
799 break;
800 case DSC_AREC | DSC_2ND: /* poll done */
801 if (!DS_FIFO_EMPTY) { /* OTA ds? */
802 ds_cyl = ds_fifo_read (); /* save cylinder */
803 ds_wait_for_cpu (uptr, DSC_AREC|DSC_3RD); /* set flag, new state */
804 }
805 else sim_activate (uptr, ds_ctime); /* no, continue poll */
806 break;
807 case DSC_AREC | DSC_3RD: /* poll done */
808 if (!DS_FIFO_EMPTY) { /* OTA ds? */
809 ds_hs = ds_fifo_read (); /* save head/sector */
810 ds_cmd_done (0, DS1_OK); /* op done, no flag */
811 }
812 else sim_activate (uptr, ds_ctime); /* no, continue poll */
813 break;
814
815 case DSC_RSTA: /* rd stat (all forms) */
816 if (DS_FIFO_EMPTY) { /* fifo empty? */
817 uptr->CYL--;
818 ds_fifo_write (dsxb[uptr->CYL]); /* store next status */
819 ds_wait_for_cpu (uptr, DSC_RSTA |
820 (uptr->CYL? 0: DSC_2ND)); /* set flag, new state */
821 }
822 else sim_activate (uptr, ds_ctime); /* no, continue poll */
823 break;
824 case DSC_RSTA | DSC_2ND: /* poll done */
825 if (DS_FIFO_EMPTY) ds_cmd_done (0, DS1_OK); /* op done? no flag */
826 else sim_activate (uptr, ds_ctime); /* no, continue poll */
827 break;
828
829 case DSC_CLEAR: /* clear */
830 ds_reset_cmn (&ds_dev); /* reset ctrl */
831 clrCTL (dev); /* clear CTL, SRQ */
832 clrSRQ (dev);
833 ds_cmd_done (1, DS1_OK); /* op done, set flag */
834 break;
835
836 case DSC_SFM: /* set file mask */
837 ds_fmask = ds_cmd & DSC_FMASK;
838 ds_cmd_done (1, DS1_OK); /* op done, set flag */
839 break;
840
841 case DSC_WTIO: /* write I/O */
842 ds_cmd_done (0, DS1_OK); /* op done, no flag */
843 break;
844
845 case DSC_WAKE: /* wakeup */
846 ds_cmd_done (1, DS1_AVAIL); /* op done, set flag */
847 break;
848
849 case DSC_BADU: /* invalid unit */
850 if (uptr->CYL > 10) ds_cmd_done (1, DS1_UNAVL); /* [11,16]? bad unit */
851 else ds_cmd_done (1, DS1_S2ERR); /* else unit not ready */
852 break;
853
854 case DSC_BADF: /* invalid operation */
855 ds_cmd_done (1, DS1_ILLOP); /* op done, set flag */
856 break;
857
858 default:
859 return SCPE_IERR;
860 }
861
862 ds_poll (); /* run the controller */
863 return SCPE_OK;
864 }
865
866 /* Timeout service */
867
868 t_stat ds_svc_t (UNIT *uptr)
869 {
870 int32 i;
871
872 for (i = 0; i < (DS_NUMDR + 1); i++) /* cancel all ops */
873 sim_cancel (&ds_unit[i]);
874 ds_set_idle (); /* idle the controller */
875 ds_fmask = 0; /* clear file mask */
876 ds_poll (); /* run the controller */
877 return SCPE_OK;
878 }
879
880 /* Unit service */
881
882 t_stat ds_svc_u (UNIT *uptr)
883 {
884 uint32 op, dev, dtyp;
885 t_stat r;
886
887 op = uptr->FNC;
888 dev = ds_dib.devno;
889 dtyp = GET_DTYPE (uptr->flags);
890 switch (op) { /* case on function */
891
892 /* Seek and recalibrate */
893
894 case DSC_RECAL: /* recalibrate */
895 if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */
896 ds_start_seek (uptr, 0, DSC_RECAL|DSC_2ND); /* set up seek */
897 ds_set_idle (); /* ctrl is idle */
898 }
899 else ds_cmd_done (1, DS1_S2ERR); /* not ready error */
900 break;
901 case DSC_RECAL | DSC_2ND: /* recal complete */
902 uptr->STA = uptr->STA | DS2_ATN; /* set attention */
903 break;
904
905 case DSC_SEEK: /* seek */
906 ds_wait_for_cpu (uptr, DSC_SEEK|DSC_2ND); /* set flag, new state */
907 break;
908 case DSC_SEEK | DSC_2ND: /* waiting for word 1 */
909 if (!DS_FIFO_EMPTY) { /* OTA ds? */
910 ds_cyl = ds_fifo_read (); /* save cylinder */
911 ds_wait_for_cpu (uptr, DSC_SEEK|DSC_3RD); /* set flag, new state */
912 }
913 else sim_activate (uptr, ds_ctime); /* no, continue poll */
914 break;
915 case DSC_SEEK | DSC_3RD: /* waiting for word 2 */
916 if (!DS_FIFO_EMPTY) { /* OTA ds? */
917 ds_hs = ds_fifo_read (); /* save head/sector */
918 if ((uptr->flags & UNIT_UNLOAD) == 0) { /* drive up? */
919 ds_start_seek (uptr, ds_cyl, DSC_SEEK|DSC_4TH); /* set up seek */
920 ds_set_idle (); /* ctrl is idle */
921 }
922 else ds_cmd_done (1, DS1_S2ERR); /* else not ready error */
923 }
924 else sim_activate (uptr, ds_ctime); /* continue poll */
925 break;
926 case DSC_SEEK | DSC_4TH: /* seek complete */
927 uptr->STA = uptr->STA | DS2_ATN; /* set attention */
928 break;
929
930 /* Read variants */
931
932 case DSC_ROFF: /* read with offset */
933 ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */
934 break;
935 case DSC_ROFF | DSC_2ND: /* poll done */
936 if (!DS_FIFO_EMPTY) { /* OTA ds? new state */
937 ds_fifo_read (); /* drain fifo */
938 uptr->FNC = DSC_READ;
939 setFLG (dev); /* handshake */
940 }
941 sim_activate (uptr, ds_ctime); /* schedule unit */
942 break;
943
944 case DSC_COLD: /* cold load read */
945 if ((uptr->flags & UNIT_UNLOAD) == 0) /* drive up? */
946 ds_start_seek (uptr, 0, DSC_READ); /* set up seek */
947 else ds_cmd_done (1, DS1_S2ERR); /* no, not ready error */
948 break;
949
950 case DSC_READ: /* read */
951 if (r = ds_start_rd (uptr, 0, 1)) return r; /* new sector; error? */
952 break;
953 case DSC_READ | DSC_2ND: /* word transfer */
954 ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */
955 break;
956 case DSC_READ | DSC_3RD: /* end of sector */
957 ds_end_rw (uptr, DSC_READ); /* see if more to do */
958 break;
959
960 case DSC_RNOVFY: /* read, no verify */
961 if (r = ds_start_rd (uptr, 0, 0)) return r; /* new sector; error? */
962 break;
963 case DSC_RNOVFY | DSC_2ND: /* word transfer */
964 ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */
965 break;
966 case DSC_RNOVFY | DSC_3RD: /* end of sector */
967 ds_end_rw (uptr, DSC_RNOVFY); /* see if more to do */
968 break;
969
970 case DSC_RFULL: /* read full */
971 dsxb[DS_FSYNC] = 0100376; /* fill in header */
972 dsxb[DS_FCYL] = uptr->CYL;
973 dsxb[DS_FHS] = ds_hs; /* before h/s update */
974 if (r = ds_start_rd (uptr, DS_FDATA, 0)) /* new sector; error? */
975 return r;
976 break;
977 case DSC_RFULL | DSC_2ND: /* word transfer */
978 ds_cont_rd (uptr, DS_NUMWDF); /* xfr wd, check end */
979 break;
980 case DSC_RFULL | DSC_3RD: /* end of sector */
981 ds_end_rw (uptr, DSC_RFULL); /* see if more to do */
982 break;
983
984 case DSC_VFY: /* verify */
985 ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */
986 break;
987 case DSC_VFY | DSC_2ND: /* poll done */
988 if (!DS_FIFO_EMPTY) { /* OTA ds? */
989 ds_vctr = ds_fifo_read (); /* save count */
990 uptr->FNC = DSC_VFY | DSC_3RD; /* next state */
991 sim_activate (uptr, ds_rtime); /* delay for transfer */
992 }
993 else sim_activate (uptr, ds_ctime); /* no, continue poll */
994 break;
995 case DSC_VFY | DSC_3RD: /* start sector */
996 if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) break;
997 /* new sector; error? */
998 ds_next_sec (uptr); /* increment hd, sc */
999 break;
1000 case DSC_VFY | DSC_4TH: /* end sector */
1001 ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */
1002 if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */
1003 else ds_cmd_done (1, DS1_OK); /* no, set done */
1004 break;
1005
1006 /* Write variants */
1007
1008 case DSC_WRITE: /* write */
1009 ds_start_wr (uptr, 1); /* new sector */
1010 break;
1011 case DSC_WRITE | DSC_2ND:
1012 if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */
1013 return r; /* error? */
1014 break;
1015 case DSC_WRITE | DSC_3RD: /* end sector */
1016 ds_end_rw (uptr, DSC_WRITE); /* see if more to do */
1017 break;
1018
1019 case DSC_INIT: /* init */
1020 ds_start_wr (uptr, 0); /* new sector */
1021 break;
1022 case DSC_INIT | DSC_2ND:
1023 if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */
1024 return r; /* error? */
1025 break;
1026 case DSC_INIT | DSC_3RD: /* end sector */
1027 ds_end_rw (uptr, DSC_INIT); /* see if more to do */
1028 break;
1029
1030 case DSC_WFULL: /* write full */
1031 ds_start_wr (uptr, 0); /* new sector */
1032 break;
1033 case DSC_WFULL | DSC_2ND:
1034 if (r = ds_cont_wr (uptr, DS_FDATA, DS_NUMWDF)) /* write word */
1035 return r; /* error */
1036 break;
1037 case DSC_WFULL | DSC_3RD:
1038 ds_end_rw (uptr, DSC_WFULL); /* see if more to do */
1039 break;
1040
1041 default:
1042 break;
1043 }
1044
1045 ds_poll ();
1046 return SCPE_OK;
1047 }
1048
1049 /* Schedule timed wait for CPU response
1050
1051 - Set flag to get CPU attention
1052 - Set specified unit to 'newstate' and schedule
1053 - Schedule timeout */
1054
1055 void ds_wait_for_cpu (UNIT *uptr, uint32 newst)
1056 {
1057 uint32 dev = ds_dib.devno;
1058
1059 setFLG (dev); /* set flag */
1060 uptr->FNC = newst; /* new state */
1061 sim_activate (uptr, ds_ctime); /* activate unit */
1062 sim_cancel (&ds_timer); /* activate timeout */
1063 sim_activate (&ds_timer, ds_tmo);
1064 return;
1065 }
1066
1067 /* Set idle state
1068
1069 - Controller is set to idle state
1070 - Visible busy is cleared
1071 - Timeout is cancelled */
1072
1073 void ds_set_idle (void)
1074 {
1075 ds_busy = 0; /* busy clear */
1076 ds_state = DS_IDLE; /* ctrl idle */
1077 sim_cancel (&ds_timer); /* no timeout */
1078 return;
1079 }
1080
1081 /* Set wait state
1082
1083 - Set flag if required
1084 - Set controller to wait state
1085 - Clear visible busy
1086 - Schedule timeout */
1087
1088 void ds_cmd_done (t_bool sf, uint32 sr1)
1089 {
1090 uint32 dev = ds_dib.devno;
1091
1092 if (sf) { setFLG (dev); } /* set host flag */
1093 ds_busy = 0; /* clear visible busy */
1094 ds_sr1 = ds_sr1 | sr1; /* final status */
1095 ds_state = DS_WAIT; /* ctrl waiting */
1096 sim_cancel (&ds_timer); /* activate timeout */
1097 sim_activate (&ds_timer, ds_tmo);
1098 return;
1099 }
1100
1101 /* Return drive status (status word 2) */
1102
1103 uint32 ds_updds2 (UNIT *uptr)
1104 {
1105 uint32 sta;
1106 uint32 dtyp = GET_DTYPE (uptr->flags);
1107
1108 sta = drv_tab[dtyp].id | /* form status */
1109 uptr->STA | /* static bits */
1110 ((uptr->flags & UNIT_WPR)? DS2_RO: 0) | /* dynamic bits */
1111 ((uptr->flags & UNIT_FMT)? DS2_FRM: 0) |
1112 ((uptr->flags & UNIT_UNLOAD)? DS2_NR | DS2_BS: 0) |
1113 (sim_is_active (uptr)? DS2_BS: 0);
1114 if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */
1115 return sta;
1116 }
1117
1118 /* Schedule controller operation */
1119
1120 void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy)
1121 {
1122 ds_ctrl.FNC = op; /* save op */
1123 ds_ctrl.CYL = arg; /* save argument */
1124 ds_busy = busy; /* set visible busy */
1125 sim_activate (&ds_ctrl, ds_ctime); /* schedule */
1126 sim_cancel (&ds_timer); /* activate timeout */
1127 sim_activate (&ds_timer, ds_tmo);
1128 return;
1129 }
1130
1131 /* Request address - if pending eoc, report cylinder + 1 */
1132
1133 void ds_reqad (uint16 *cyl, uint16 *hs)
1134 {
1135 *cyl = ds_cyl + (ds_eoc? 1: 0);
1136 *hs = ds_hs;
1137 return;
1138 }
1139
1140 /* Start seek - schedule whether in bounds or out of bounds */
1141
1142 void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst)
1143 {
1144 int32 t;
1145 uint32 hd, sc;
1146 uint32 dtyp = GET_DTYPE (uptr->flags);
1147
1148 uptr->FNC = newst; /* set new state */
1149 if (cyl >= drv_tab[dtyp].cyl) { /* out of bounds? */
1150 t = 0; /* don't change cyl */
1151 uptr->STA = uptr->STA | DS2_SC; /* set seek check */
1152 }
1153 else {
1154 t = abs (uptr->CYL - cyl); /* delta cylinders */
1155 uptr->CYL = cyl; /* put on cylinder */
1156 hd = DSHS_GETHD (ds_hs); /* invalid head or sec? */
1157 sc = DSHS_GETSC (ds_hs);
1158 if ((hd >= drv_tab[dtyp].hd) ||
1159 (sc >= drv_tab[dtyp].sc))
1160 uptr->STA = uptr->STA | DS2_SC; /* set seek check */
1161 else uptr->STA = uptr->STA & ~DS2_SC; /* clear seek check */
1162 }
1163 sim_activate (uptr, ds_stime * (t + 1)); /* schedule */
1164 return;
1165 }
1166
1167 /* Start next sector for read or write
1168
1169 - If error, set command done, return TRUE, nothing is scheduled
1170 - If implicit seek, return TRUE, implicit seek is scheduled, but
1171 state is not changed - we will return here when seek is done
1172 - Otherwise, advance state, set position in file, schedule next state */
1173
1174 t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy)
1175 {
1176 uint32 da, hd, sc;
1177 uint32 dtyp = GET_DTYPE (uptr->flags);
1178
1179 ds_eod = 0; /* init eod */
1180 ds_ptr = 0; /* init buffer ptr */
1181 if (uptr->flags & UNIT_UNLOAD) { /* drive down? */
1182 ds_cmd_done (1, DS1_S2ERR);
1183 return TRUE;
1184 }
1185 if (ds_eoc) { /* at end of cylinder? */
1186 ds_next_cyl (uptr); /* auto seek to next */
1187 return TRUE; /* or error */
1188 }
1189 if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */
1190 if (ds_cyl >= drv_tab[dtyp].cyl) /* seeking to bad? */
1191 ds_cmd_done (1, DS1_CYLCE); /* lose */
1192 else ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek right cyl */
1193 return TRUE;
1194 }
1195 hd = DSHS_GETHD (ds_hs);
1196 sc = DSHS_GETSC (ds_hs);
1197 if ((uint32) uptr->CYL >= drv_tab[dtyp].cyl) { /* valid cylinder? */
1198 uptr->STA = uptr->STA | DS2_SC; /* set seek check */
1199 ds_cmd_done (1, DS1_S2ERR); /* error */
1200 return TRUE;
1201 }
1202 if ((hd >= drv_tab[dtyp].hd) || /* valid head, sector? */
1203 (sc >= drv_tab[dtyp].sc)) {
1204 ds_cmd_done (1, DS1_HSCE); /* no, error */
1205 return TRUE;
1206 }
1207 da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */
1208 sim_fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET); /* set file pos */
1209 uptr->FNC += DSC_NEXT; /* next state */
1210 sim_activate (uptr, tm); /* activate unit */
1211 return FALSE;
1212 }
1213
1214 /* Start next sector for read
1215
1216 - Do common start for read and write
1217 - If error, return, command has been terminated, nothing scheduled
1218 - If implicit seek, return, seek scheduled
1219 - If no error or seek, state has been advanced and unit scheduled
1220 - Read sector
1221 - If read error, terminate command and return, nothing scheduled
1222 - If no error, advance head/sector, next state scheduled */
1223
1224 t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy)
1225 {
1226 uint32 t;
1227
1228 if (ds_start_rw (uptr, ds_rtime, vfy)) return SCPE_OK; /* new sec; err or seek? */
1229 t = sim_fread (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref);
1230 for (t = t + off ; t < DS_NUMWDF; t++) dsxb[t] = 0; /* fill sector */
1231 if (ferror (uptr->fileref)) /* error? */
1232 return ds_set_uncorr (uptr); /* say uncorrectable */
1233 ds_next_sec (uptr); /* increment hd, sc */
1234 return SCPE_OK;
1235 }
1236
1237 /* Start next sector for write
1238
1239 - Do common start for read and write
1240 - If error, return, command has been terminated, nothing scheduled
1241 - If implicit seek, return, seek scheduled
1242 - If no error or seek, state has been advanced and unit scheduled
1243 - Clear buffer
1244 - Set service request */
1245
1246 void ds_start_wr (UNIT *uptr, t_bool vfy)
1247 {
1248 uint32 i;
1249 uint32 dev = ds_dib.devno;
1250
1251 if ((uptr->flags & UNIT_WPR) || /* write protected? */
1252 (!vfy && ((uptr->flags & UNIT_FMT) == 0))) { /* format, not enbl? */
1253 ds_cmd_done (1, DS1_S2ERR); /* error */
1254 return;
1255 }
1256 if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sec; err or seek? */
1257 for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */
1258 setSRQ (dev); /* request word */
1259 return;
1260 }
1261
1262 /* Advance to next sector (but not next cylinder) */
1263
1264 void ds_next_sec (UNIT *uptr)
1265 {
1266 uint32 dtyp = GET_DTYPE (uptr->flags);
1267
1268 ds_hs = ds_hs + 1; /* increment sector */
1269 if (DSHS_GETSC (ds_hs) < drv_tab[dtyp].sc) return; /* end of track? */
1270 ds_hs = ds_hs & ~DSHS_SC; /* yes, wrap sector */
1271 if (ds_fmask & DSC_CYLM) { /* cylinder mode? */
1272 ds_hs = ds_hs + (1 << DSHS_V_HD); /* increment head */
1273 if (DSHS_GETHD (ds_hs) < drv_tab[dtyp].hd) return; /* end of cyl? */
1274 ds_hs = ds_hs & ~DSHS_HD; /* 0 head */
1275 }
1276 ds_eoc = 1; /* flag end cylinder */
1277 return;
1278 }
1279
1280 /* Advance to next cylinder
1281
1282 - If autoseek enabled, seek to cylinder +/- 1
1283 - Otherwise, done with end of cylinder error */
1284
1285 void ds_next_cyl (UNIT *uptr)
1286 {
1287 if (ds_fmask & DSC_AUTO) { /* auto seek allowed? */
1288 if (ds_fmask & DSC_DECR) ds_cyl = (ds_cyl - 1) & DMASK;
1289 else ds_cyl = (ds_cyl + 1) & DMASK;
1290 ds_eoc = 0; /* clear end cylinder */
1291 ds_start_seek (uptr, ds_cyl, uptr->FNC); /* seek, same state */
1292 }
1293 else ds_cmd_done (1, DS1_EOCYL); /* no, end of cyl err */
1294 return;
1295 }
1296
1297 /* Transfer word for read
1298
1299 - If end of data, terminate command, nothing scheduled
1300 - Otherwise, transfer word, advance state if last word, schedule */
1301
1302 void ds_cont_rd (UNIT *uptr, uint32 bsize)
1303 {
1304 uint32 dev = ds_dib.devno;
1305
1306 if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */
1307 else if (SRQ (dev)) { /* overrun? */
1308 ds_cmd_done (1, DS1_OVRUN); /* set done */
1309 return;
1310 }
1311 else { ds_fifo_write (dsxb[ds_ptr++]); /* next word */
1312 setSRQ (dev); /* request service */
1313 if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */
1314 sim_activate (uptr, ds_dtime); /* schedule */
1315 }
1316 return;
1317 }
1318
1319 /* Transfer word for write
1320
1321 - Copy word from fifo to buffer
1322 - If end of data, write buffer, terminate command, nothing scheduled
1323 - If end of sector, write buffer, next state, schedule
1324 - Otherwises, set service request, schedule */
1325
1326 t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize)
1327 {
1328 uint32 i, dat;
1329 uint32 dev = ds_dib.devno;
1330
1331 if (SRQ (dev)) { /* overrun? */
1332 ds_cmd_done (1, DS1_OVRUN); /* set done */
1333 return SCPE_OK;
1334 }
1335 dsxb[ds_ptr++] = dat = ds_fifo_read (); /* next word */
1336 if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? */
1337 for (i = ds_ptr; i < bsize; i++) dsxb[i] = dat; /* fill sector */
1338 sim_fwrite (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref);
1339 if (ferror (uptr->fileref)) /* error on write? */
1340 return ds_set_uncorr (uptr); /* uncorrectable */
1341 ds_next_sec (uptr); /* increment hd, sc */
1342 if (ds_eod) { /* end data? */
1343 ds_cmd_done (1, DS1_OK); /* set done */
1344 return SCPE_OK;
1345 }
1346 else uptr->FNC += DSC_NEXT; /* no, next state */
1347 }
1348 else { setSRQ (dev); } /* request next word */
1349 sim_activate (uptr, ds_dtime); /* schedule */
1350 return SCPE_OK;
1351 }
1352
1353 /* End sector for read or write
1354
1355 - If end of data, terminate command, nothing scheduled
1356 - If end of cylinder, schedule next cylinder
1357 - Else schedule start of next sector */
1358
1359 void ds_end_rw (UNIT *uptr, uint32 newst)
1360 {
1361 uptr->FNC = newst; /* new state */
1362 if (ds_eod) ds_cmd_done (1, DS1_OK); /* done? */
1363 else if (ds_eoc) ds_next_cyl (uptr); /* end cyl? seek */
1364 else sim_activate (uptr, ds_rtime); /* normal transfer */
1365 return;
1366 }
1367
1368 /* Report uncorrectable data error */
1369
1370 t_stat ds_set_uncorr (UNIT *uptr)
1371 {
1372 sim_cancel (uptr); /* cancel any operation */
1373 ds_cmd_done (1, DS1_UNCOR); /* done with error */
1374 perror ("DS I/O error"); /* visible error */
1375 clearerr (uptr->fileref);
1376 ds_poll (); /* force poll */
1377 return SCPE_IOERR;
1378 }
1379
1380 /* Fifo read */
1381
1382 uint32 ds_fifo_read (void)
1383 {
1384 uint32 dat;
1385
1386 if (ds_fifo_cnt == 0) return ds_fifo[ds_fifo_rp];
1387 dat = ds_fifo[ds_fifo_rp++];
1388 if (ds_fifo_rp >= DS_FIFO_SIZE) ds_fifo_rp = 0;
1389 ds_fifo_cnt--;
1390 return dat;
1391 }
1392
1393 void ds_fifo_write (uint32 dat)
1394 {
1395 ds_fifo[ds_fifo_ip++] = dat;
1396 if (ds_fifo_ip >= DS_FIFO_SIZE) ds_fifo_ip = 0;
1397 if (ds_fifo_cnt < DS_FIFO_SIZE) ds_fifo_cnt++;
1398 return;
1399 }
1400
1401 void ds_fifo_reset (void)
1402 {
1403 uint32 i;
1404
1405 ds_fifo_ip = ds_fifo_rp = ds_fifo_cnt = 0;
1406 for (i = 0; i < DS_FIFO_SIZE; i++) ds_fifo[i] = 0;
1407 return;
1408 }
1409
1410 /* Reset routine */
1411
1412 t_stat ds_reset_cmn (DEVICE *dptr)
1413 {
1414 int32 i;
1415
1416 ds_cmd = 0; /* clear command */
1417 ds_cmdf = ds_cmdp = 0; /* clear commands flops */
1418 ds_fifo_reset (); /* clear fifo */
1419 ds_eoc = ds_eod = 0;
1420 ds_busy = 0;
1421 ds_state = DS_IDLE; /* ctrl idle */
1422 ds_lastatn = 0;
1423 ds_fmask = 0;
1424 ds_ptr = 0;
1425 ds_cyl = ds_hs = 0;
1426 ds_vctr = 0;
1427 for (i = 0; i < DS_NUMDR; i++) { /* loop thru drives */
1428 sim_cancel (&ds_unit[i]); /* cancel activity */
1429 ds_unit[i].FNC = 0; /* clear function */
1430 ds_unit[i].CYL = 0;
1431 ds_unit[i].STA = 0;
1432 }
1433 sim_cancel (&ds_ctrl);
1434 sim_cancel (&ds_timer);
1435 return SCPE_OK;
1436 }
1437
1438 t_stat ds_reset (DEVICE *dptr)
1439 {
1440 ds_dib.cmd = 0; /* clear cmd */
1441 ds_dib.ctl = 0; /* clear ctl */
1442 ds_dib.fbf = 1; /* set fbf */
1443 ds_dib.flg = 1; /* set flg */
1444 ds_dib.srq = 0; /* clear srq */
1445 return ds_reset_cmn (dptr); /* do common reset */
1446 }
1447
1448 /* Device attach */
1449
1450 t_stat ds_attach (UNIT *uptr, char *cptr)
1451 {
1452 uint32 i, p;
1453 t_stat r;
1454
1455 uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
1456 r = attach_unit (uptr, cptr); /* attach unit */
1457 if (r != SCPE_OK) return r; /* error? */
1458 ds_load_unload (uptr, 0, NULL, NULL); /* if OK, load heads */
1459 ds_sched_atn (uptr); /* schedule attention */
1460 if (((uptr->flags & UNIT_AUTO) == 0) || /* static size? */
1461 ((p = sim_fsize (uptr->fileref)) == 0)) return SCPE_OK; /* new file? */
1462 for (i = 0; drv_tab[i].sc != 0; i++) { /* find best fit */
1463 if (p <= (drv_tab[i].size * sizeof (uint16))) {
1464 uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
1465 uptr->capac = drv_tab[i].size;
1466 return SCPE_OK;
1467 }
1468 }
1469 return SCPE_OK;
1470 }
1471
1472 /* Device detach */
1473
1474 t_stat ds_detach (UNIT *uptr)
1475 {
1476 ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads if attached */
1477 return detach_unit (uptr);
1478 }
1479
1480 /* Load and unload heads */
1481
1482 t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)
1483 {
1484 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to [un]load */
1485 if (value == UNIT_UNLOAD) { /* unload heads? */
1486 uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */
1487 uptr->STA = DS2_ATN; /* update drive status */
1488 ds_sched_atn (uptr); /* schedule attention */
1489 }
1490 else { /* load heads */
1491 uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */
1492 uptr->STA = DS2_ATN | DS2_FS; /* update drive status */
1493 }
1494 return SCPE_OK;
1495 }
1496
1497 /* Schedule attention interrupt if CTL set, not restore, and controller idle */
1498
1499 void ds_sched_atn (UNIT *uptr)
1500 {
1501 int32 i;
1502
1503 if (!ds_dib.ctl || (sim_switches & SIM_SW_REST)) return;
1504 for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */
1505 if (sim_is_active (ds_dev.units + i)) return;
1506 }
1507 uptr->FNC = DSC_ATN; /* pseudo operation */
1508 sim_activate (uptr, 1); /* do immediately */
1509 return;
1510 }
1511
1512 /* Set size command validation routine */
1513
1514 t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
1515 {
1516 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
1517 uptr->capac = drv_tab[GET_DTYPE (val)].size;
1518 return SCPE_OK;
1519 }
1520
1521 /* 13037 bootstrap routine (HP 12992B ROM) */
1522
1523 const uint16 ds_rom[IBL_LNT] = {
1524 0017727, /* STRT JSB STAT ; get status */
1525 0002021, /* SSA,RSS ; is drive ready? */
1526 0027742, /* JMP DMA ; yes, set up DMA */
1527 0013714, /* AND B20 ; no, check status bits */
1528 0002002, /* SZA ; faulty or hard down? */
1529 0102030, /* HLT 30B ; HALT 30B */
1530 0027700, /* JMP STRT ; try again */
1531 0102011, /* ADR1 OCT 102011 */
1532 0102055, /* ADR2 OCT 102055 */
1533 0164000, /* CNT DEC -6144 */
1534 0000007, /* D7 OCT 7 */
1535 0001400, /* STCM OCT 1400 */
1536 0000020, /* B20 OCT 20 */
1537 0017400, /* STMS OCT 17400 */
1538 0000000, /* 9 NOP's */
1539 0000000,
1540 0000000,
1541 0000000,
1542 0000000,
1543 0000000,
1544 0000000,
1545 0000000,
1546 0000000,
1547 0000000, /* STAT NOP ; status check routine */
1548 0107710, /* CLC DC,C ; set command mode */
1549 0063713, /* LDA STCM ; get status command */
1550 0102610, /* OTA DC ; output status command */
1551 0102310, /* SFS DC ; wait for stat#1 word */
1552 0027733, /* JMP *-1 */
1553 0107510, /* LIB DC,C ; B-reg - status#1 word */
1554 0102310, /* SFS DC ; wait for stat#2 word */
1555 0027736, /* JMP *-1 */
1556 0103510, /* LIA DC,C ; A-reg - status#2 word */
1557 0127727, /* JMP STAT,I ; return */
1558 0067776, /* DMA LDB DMAC ; get DMA control word */
1559 0106606, /* OTB 6 ; output DMA ctrl word */
1560 0067707, /* LDB ADR1 ; get memory address */
1561 0106702, /* CLC 2 ; set memory addr mode */
1562 0106602, /* OTB 2 ; output mem addr to DMA */
1563 0102702, /* STC 2 ; set word count mode */
1564 0067711, /* LDB CNT ; get word count */
1565 0106602, /* OTB 2 ; output word cnt to DMA */
1566 0106710, /* CLC CLC DC ; set command follows */
1567 0102501, /* LIA 1 ; load switches */
1568 0106501, /* LIB 1 ; register settings */
1569 0013712, /* AND D7 ; isolate head number */
1570 0005750, /* BLF,CLE,SLB ; bit 12 = 0? */
1571 0027762, /* JMP *+3 ; no, manual boot */
1572 0002002, /* SZA ; yes, RPL, head# = 0? */
1573 0001000, /* ALS ; no, head# = 1 --> 2 */
1574 0001720, /* ALF,ALS ; form cold load */
1575 0001000, /* ALS ; command word */
1576 0103706, /* STC 6,C ; activate DMA */
1577 0103610, /* OTA DC,C ; output cold load cmd */
1578 0102310, /* SFS DC ; is cold load done? */
1579 0027766, /* JMP *-1 ; no, wait */
1580 0017727, /* JSB STAT ; yes, get status */
1581 0060001, /* LDA 1 ; get status word #1 */
1582 0013715, /* AND STMS ; isolate status bits */
1583 0002002, /* SZA ; is transfer ok? */
1584 0027700, /* JMP STRT ; no, try again */
1585 0117710, /* JSB ADR2,I ; yes, start program */
1586 0000010, /* DMAC ABS DC ; DMA command word */
1587 0170100, /* ABS -STRT */
1588 };
1589
1590 t_stat ds_boot (int32 unitno, DEVICE *dptr)
1591 {
1592 int32 dev;
1593
1594 if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
1595 dev = ds_dib.devno; /* get data chan dev */
1596 if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */
1597 SR = (SR & (IBL_OPT | IBL_DS_HEAD)) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV);
1598 return SCPE_OK;
1599 }