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