First Commit of my working state
[simh.git] / HP2100 / hp2100_dp.c
CommitLineData
196ba1fc
PH
1/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator\r
2\r
3 Copyright (c) 1993-2006, 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 dp 12557A 2871 disk subsystem\r
27 13210A 7900 disk subsystem\r
28\r
29 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)\r
30 01-Mar-05 JDB Added SET UNLOAD/LOAD\r
31 07-Oct-04 JDB Fixed enable/disable from either device\r
32 Fixed ANY ERROR status for 12557A interface\r
33 Fixed unattached drive status for 12557A interface\r
34 Status cmd without prior STC DC now completes (12557A)\r
35 OTA/OTB CC on 13210A interface also does CLC CC\r
36 Fixed RAR model\r
37 Fixed seek check on 13210 if sector out of range\r
38 20-Aug-04 JDB Fixes from Dave Bryan\r
39 - Check status on unattached drive set busy and not ready\r
40 - Check status tests wrong unit for write protect status\r
41 - Drive on line sets ATN, will set FLG if polling\r
42 15-Aug-04 RMS Controller resumes polling for ATN interrupts after\r
43 read status (found by Dave Bryan)\r
44 22-Jul-04 RMS Controller sets ATN for all commands except\r
45 read status (found by Dave Bryan)\r
46 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan)\r
47 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r
48 Fixed SR setting in IBL\r
49 Fixed interpretation of SR<0>\r
50 Revised IBL loader\r
51 Implemented DMA SRQ (follows FLG)\r
52 25-Apr-03 RMS Revised for extended file support\r
53 Fixed bug(s) in boot (found by Terry Newton)\r
54 10-Nov-02 RMS Added BOOT command, fixed numerous bugs\r
55 15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith)\r
56 10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith)\r
57 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW\r
58 24-Nov-01 RMS Changed STA to be an array\r
59 07-Sep-01 RMS Moved function prototypes\r
60 29-Nov-00 RMS Made variable names unique\r
61 21-Nov-00 RMS Fixed flag, buffer power up state\r
62\r
63 The simulator uses a number of state variables:\r
64\r
65 dpc_busy set to drive number + 1 when the controller is busy\r
66 of the unit in use\r
67 dpd_xfer set to 1 if the data channel is executing a data transfer\r
68 dpd_wval set to 1 by OTx if either !dpc_busy or dpd_xfer\r
69 dpc_poll set to 1 if attention polling is enabled\r
70\r
71 dpc_busy and dpd_xfer are set together at the start of a read, write, refine,\r
72 or init. When data transfers are complete (CLC DC), dpd_xfer is cleared, but the\r
73 operation is not necessarily over. When the operation is complete, dpc_busy\r
74 is cleared and the command channel flag is set.\r
75\r
76 dpc_busy && !dpd_xfer && STC DC (controller is busy, data channel transfer has\r
77 been terminated by CLC DC, but a word has been placed in the data channel buffer)\r
78 indicates data overrun.\r
79\r
80 dpd_wval is used in write operations to fill out the sector buffer with 0's\r
81 if only a partial sector has been transferred.\r
82\r
83 dpc_poll indicates whether seek completion polling can occur. It is cleared\r
84 by reset and CLC CC and set by issuance of a seek or completion of check status.\r
85\r
86 The controller's "Record Address Register" (RAR) contains the CHS address of\r
87 the last Seek or Address Record command executed. The RAR is shared among\r
88 all drives on the controller. In addition, each drive has an internal\r
89 position register that contains the last cylinder position transferred to the\r
90 drive during Seek command execution (data operations always start with the\r
91 RAR head and sector position).\r
92\r
93 In a real drive, the address field of the sector under the head is read and\r
94 compared to the RAR. When they match, the target sector is under the head\r
95 and is ready for reading or writing. If a match doesn't occur, an Address\r
96 Error is indicated. In the simulator, the address field is obtained from the\r
97 drive's current position register during a read, i.e., the "on-disc" address\r
98 field is assumed to match the current position.\r
99\r
100 References:\r
101 - 7900A Disc Drive Operating and Service Manual (07900-90002, Feb-1975)\r
102 - 13210A Disc Drive Interface Kit Operating and Service Manual\r
103 (13210-90003, Nov-1974)\r
104 - 12557A Cartridge Disc Interface Kit Operating and Service Manual\r
105 (12557-90001, Sep-1970)\r
106\r
107 The following implemented behaviors have been inferred from secondary sources\r
108 (diagnostics, operating system drivers, etc.), due to absent or contradictory\r
109 authoritative information; future correction may be needed:\r
110\r
111 1. Status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR) on the 12557A.\r
112 2. Omitting STC DC before Status Check does not set DC flag but does poll.\r
113*/\r
114\r
115#include "hp2100_defs.h"\r
116\r
117#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */\r
118#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */\r
119#define UNIT_WLK (1 << UNIT_V_WLK)\r
120#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD)\r
121#define FNC u3 /* saved function */\r
122#define DRV u4 /* drive number (DC) */\r
123#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */\r
124\r
125#define DP_N_NUMWD 7\r
126#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */\r
127#define DP_NUMSC2 12 /* sectors/srf 12557 */\r
128#define DP_NUMSC3 24 /* sectors/srf 13210 */\r
129#define DP_NUMSC (dp_ctype? DP_NUMSC3: DP_NUMSC2)\r
130#define DP_NUMSF 4 /* surfaces/cylinder */\r
131#define DP_NUMCY 203 /* cylinders/disk */\r
132#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD)\r
133#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)\r
134#define DP_NUMDRV 4 /* # drives */\r
135\r
136/* Command word */\r
137\r
138#define CW_V_FNC 12 /* function */\r
139#define CW_M_FNC 017\r
140#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC)\r
141#define FNC_STA 000 /* status check */\r
142#define FNC_WD 001 /* write */\r
143#define FNC_RD 002 /* read */\r
144#define FNC_SEEK 003 /* seek */\r
145#define FNC_REF 005 /* refine */\r
146#define FNC_CHK 006 /* check */\r
147#define FNC_INIT 011 /* init */\r
148#define FNC_AR 013 /* address */\r
149#define FNC_SEEK1 020 /* fake - seek1 */\r
150#define FNC_SEEK2 021 /* fake - seek2 */\r
151#define FNC_SEEK3 022 /* fake - seek3 */\r
152#define FNC_CHK1 023 /* fake - check1 */\r
153#define FNC_AR1 024 /* fake - arec1 */\r
154#define CW_V_DRV 0 /* drive */\r
155#define CW_M_DRV 03\r
156#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)\r
157\r
158/* Disk address words */\r
159\r
160#define DA_V_CYL 0 /* cylinder */\r
161#define DA_M_CYL 0377\r
162#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)\r
163#define DA_V_HD 8 /* head */\r
164#define DA_M_HD 03\r
165#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)\r
166#define DA_V_SC 0 /* sector */\r
167#define DA_M_SC2 017\r
168#define DA_M_SC3 037\r
169#define DA_M_SC (dp_ctype? DA_M_SC3: DA_M_SC2)\r
170#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)\r
171#define DA_CKMASK2 037 /* check mask */\r
172#define DA_CKMASK3 077\r
173#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2)\r
174\r
175/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */\r
176\r
177#define STA_ATN 0100000 /* attention (u) */\r
178#define STA_1ST 0040000 /* first status */\r
179#define STA_OVR 0020000 /* overrun */\r
180#define STA_RWU 0010000 /* rw unsafe NI (u) */\r
181#define STA_ACU 0004000 /* access unsafe NI */\r
182#define STA_HUNT 0002000 /* hunting NI (12557) */\r
183#define STA_PROT 0002000 /* protected (13210) */\r
184#define STA_SKI 0001000 /* incomplete NI (u) */\r
185#define STA_SKE 0000400 /* seek error */\r
186/* 0000200 /* unused */\r
187#define STA_NRDY 0000100 /* not ready (d) */\r
188#define STA_EOC 0000040 /* end of cylinder */\r
189#define STA_AER 0000020 /* addr error */\r
190#define STA_FLG 0000010 /* flagged */\r
191#define STA_BSY 0000004 /* seeking */\r
192#define STA_DTE 0000002 /* data error */\r
193#define STA_ERR 0000001 /* any error (d) */\r
194\r
195#define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \\r
196 STA_SKI | STA_SKE | STA_NRDY | \\r
197 STA_EOC | STA_AER | STA_DTE) /* 12557A error set */\r
198#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \\r
199 STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \\r
200 STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */\r
201#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2)\r
202\r
203#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)\r
204#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */\r
205\r
206extern uint32 PC, SR;\r
207extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r
208extern int32 sim_switches;\r
209\r
210int32 dp_ctype = 1; /* ctrl type */\r
211int32 dpc_busy = 0; /* cch unit */\r
212int32 dpc_poll = 0; /* cch poll enable */\r
213int32 dpc_cnt = 0; /* check count */\r
214int32 dpc_eoc = 0; /* end of cyl */\r
215int32 dpc_stime = 100; /* seek time */\r
216int32 dpc_ctime = 100; /* command time */\r
217int32 dpc_xtime = 5; /* xfer time */\r
218int32 dpc_dtime = 2; /* dch time */\r
219int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */\r
220int32 dpc_obuf = 0; /* cch buffers */\r
221int32 dpd_xfer = 0; /* xfer in prog */\r
222int32 dpd_wval = 0; /* write data valid */\r
223int32 dp_ptr = 0; /* buffer ptr */\r
224uint8 dpc_rarc = 0; /* RAR cylinder */\r
225uint8 dpc_rarh = 0; /* RAR head */\r
226uint8 dpc_rars = 0; /* RAR sector */\r
227uint8 dpc_ucyl[DP_NUMDRV] = { 0 }; /* unit cylinder */\r
228uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */\r
229uint16 dpxb[DP_NUMWD]; /* sector buffer */\r
230\r
231DEVICE dpd_dev, dpc_dev;\r
232int32 dpdio (int32 inst, int32 IR, int32 dat);\r
233int32 dpcio (int32 inst, int32 IR, int32 dat);\r
234t_stat dpc_svc (UNIT *uptr);\r
235t_stat dpd_svc (UNIT *uptr);\r
236t_stat dpc_reset (DEVICE *dptr);\r
237t_stat dpc_attach (UNIT *uptr, char *cptr);\r
238t_stat dpc_detach (UNIT* uptr);\r
239t_stat dpc_boot (int32 unitno, DEVICE *dptr);\r
240void dp_god (int32 fnc, int32 drv, int32 time);\r
241void dp_goc (int32 fnc, int32 drv, int32 time);\r
242t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);\r
243t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);\r
244t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);\r
245\r
246/* DPD data structures\r
247\r
248 dpd_dev DPD device descriptor\r
249 dpd_unit DPD unit list\r
250 dpd_reg DPD register list\r
251*/\r
252\r
253DIB dp_dib[] = {\r
254 { DPD, 0, 0, 0, 0, 0, &dpdio },\r
255 { DPC, 0, 0, 0, 0, 0, &dpcio }\r
256 };\r
257\r
258#define dpd_dib dp_dib[0]\r
259#define dpc_dib dp_dib[1]\r
260\r
261UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) };\r
262\r
263REG dpd_reg[] = {\r
264 { ORDATA (IBUF, dpd_ibuf, 16) },\r
265 { ORDATA (OBUF, dpd_obuf, 16) },\r
266 { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },\r
267 { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },\r
268 { FLDATA (CMD, dpd_dib.cmd, 0) },\r
269 { FLDATA (CTL, dpd_dib.ctl, 0) },\r
270 { FLDATA (FLG, dpd_dib.flg, 0) },\r
271 { FLDATA (FBF, dpd_dib.fbf, 0) },\r
272 { FLDATA (SRQ, dpd_dib.srq, 0) },\r
273 { FLDATA (XFER, dpd_xfer, 0) },\r
274 { FLDATA (WVAL, dpd_wval, 0) },\r
275 { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO },\r
276 { NULL }\r
277 };\r
278\r
279MTAB dpd_mod[] = {\r
280 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r
281 &hp_setdev, &hp_showdev, &dpd_dev },\r
282 { 0 }\r
283 };\r
284\r
285DEVICE dpd_dev = {\r
286 "DPD", &dpd_unit, dpd_reg, dpd_mod,\r
287 1, 10, DP_N_NUMWD, 1, 8, 16,\r
288 NULL, NULL, &dpc_reset,\r
289 NULL, NULL, NULL,\r
290 &dpd_dib, DEV_DISABLE\r
291 };\r
292\r
293/* DPC data structures\r
294\r
295 dpc_dev DPC device descriptor\r
296 dpc_unit DPC unit list\r
297 dpc_reg DPC register list\r
298 dpc_mod DPC modifier list\r
299*/\r
300\r
301UNIT dpc_unit[] = {\r
302 { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r
303 UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) },\r
304 { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r
305 UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) },\r
306 { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r
307 UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) },\r
308 { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r
309 UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }\r
310 };\r
311\r
312REG dpc_reg[] = {\r
313 { ORDATA (OBUF, dpc_obuf, 16) },\r
314 { ORDATA (BUSY, dpc_busy, 4), REG_RO },\r
315 { ORDATA (CNT, dpc_cnt, 5) },\r
316 { FLDATA (CMD, dpc_dib.cmd, 0) },\r
317 { FLDATA (CTL, dpc_dib.ctl, 0) },\r
318 { FLDATA (FLG, dpc_dib.flg, 0) },\r
319 { FLDATA (FBF, dpc_dib.fbf, 0) },\r
320 { FLDATA (SRQ, dpc_dib.srq, 0) },\r
321 { FLDATA (EOC, dpc_eoc, 0) },\r
322 { FLDATA (POLL, dpc_poll, 0) },\r
323 { DRDATA (RARC, dpc_rarc, 8), PV_RZRO },\r
324 { DRDATA (RARH, dpc_rarh, 2), PV_RZRO },\r
325 { DRDATA (RARS, dpc_rars, 5), PV_RZRO },\r
326 { BRDATA (CYL, dpc_ucyl, 10, 8, DP_NUMDRV), PV_RZRO },\r
327 { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },\r
328 { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT },\r
329 { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT },\r
330 { DRDATA (STIME, dpc_stime, 24), PV_LEFT },\r
331 { DRDATA (XTIME, dpc_xtime, 24), REG_NZ | PV_LEFT },\r
332 { FLDATA (CTYPE, dp_ctype, 0), REG_HRO },\r
333 { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0,\r
334 DP_NUMDRV, REG_HRO) },\r
335 { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0,\r
336 DP_NUMDRV, PV_LEFT | REG_HRO) },\r
337 { ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO },\r
338 { NULL }\r
339 };\r
340\r
341MTAB dpc_mod[] = {\r
342 { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dpc_load_unload },\r
343 { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dpc_load_unload },\r
344 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
345 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r
346 { MTAB_XTD | MTAB_VDV, 1, NULL, "13210A",\r
347 &dp_settype, NULL, NULL },\r
348 { MTAB_XTD | MTAB_VDV, 0, NULL, "12557A",\r
349 &dp_settype, NULL, NULL },\r
350 { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,\r
351 NULL, &dp_showtype, NULL },\r
352 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r
353 &hp_setdev, &hp_showdev, &dpd_dev },\r
354 { 0 }\r
355 };\r
356\r
357DEVICE dpc_dev = {\r
358 "DPC", dpc_unit, dpc_reg, dpc_mod,\r
359 DP_NUMDRV, 8, 24, 1, 8, 16,\r
360 NULL, NULL, &dpc_reset,\r
361 &dpc_boot, &dpc_attach, &dpc_detach,\r
362 &dpc_dib, DEV_DISABLE\r
363 };\r
364\r
365/* IO instructions */\r
366\r
367int32 dpdio (int32 inst, int32 IR, int32 dat)\r
368{\r
369int32 devd;\r
370\r
371devd = IR & I_DEVMASK; /* get device no */\r
372switch (inst) { /* case on opcode */\r
373\r
374 case ioFLG: /* flag clear/set */\r
375 if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */\r
376 break;\r
377\r
378 case ioSFC: /* skip flag clear */\r
379 if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;\r
380 break;\r
381\r
382 case ioSFS: /* skip flag set */\r
383 if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;\r
384 break;\r
385\r
386 case ioOTX: /* output */\r
387 dpd_obuf = dat;\r
388 if (!dpc_busy || dpd_xfer) dpd_wval = 1; /* if !overrun, valid */\r
389 break;\r
390\r
391 case ioMIX: /* merge */\r
392 dat = dat | dpd_ibuf;\r
393 break;\r
394\r
395 case ioLIX: /* load */\r
396 dat = dpd_ibuf;\r
397 break;\r
398\r
399 case ioCRS: /* control reset (action unverif) */\r
400 case ioCTL: /* control clear/set */\r
401 if (IR & I_CTL) { /* CLC */\r
402 clrCTL (devd); /* clr ctl, cmd */\r
403 clrCMD (devd);\r
404 dpd_xfer = 0; /* clr xfer */\r
405 }\r
406 else { /* STC */\r
407 if (!dp_ctype) setCTL (devd); /* 12557: set ctl */\r
408 setCMD (devd); /* set cmd */\r
409 if (dpc_busy && !dpd_xfer) /* overrun? */\r
410 dpc_sta[dpc_busy - 1] |= STA_OVR;\r
411 }\r
412 break;\r
413\r
414 default:\r
415 break;\r
416 }\r
417\r
418if (IR & I_HC) { clrFSR (devd); } /* H/C option */\r
419return dat;\r
420}\r
421\r
422int32 dpcio (int32 inst, int32 IR, int32 dat)\r
423{\r
424int32 i, devc, fnc, drv;\r
425int32 devd = dpd_dib.devno;\r
426\r
427devc = IR & I_DEVMASK; /* get device no */\r
428switch (inst) { /* case on opcode */\r
429\r
430 case ioFLG: /* flag clear/set */\r
431 if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */\r
432 break;\r
433\r
434 case ioSFC: /* skip flag clear */\r
435 if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;\r
436 break;\r
437\r
438 case ioSFS: /* skip flag set */\r
439 if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;\r
440 break;\r
441\r
442 case ioLIX: /* load */\r
443 dat = 0;\r
444 case ioMIX: /* merge */\r
445 for (i = 0; i < DP_NUMDRV; i++)\r
446 if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i);\r
447 break;\r
448\r
449 case ioOTX: /* output */\r
450 dpc_obuf = dat;\r
451 if (!dp_ctype) break;\r
452 IR = IR | I_CTL; /* 13210 OTx causes CLC */\r
453\r
454 case ioCRS: /* control reset (action unverif) */\r
455 case ioCTL: /* control clear/set */\r
456 if (IR & I_CTL) { /* CLC? */\r
457 clrCTL (devc); /* clr cmd, ctl */\r
458 clrCMD (devc); /* cancel non-seek */\r
459 if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]);\r
460 sim_cancel (&dpd_unit); /* cancel dch */\r
461 dpd_xfer = 0; /* clr dch xfer */\r
462 dpc_busy = 0; /* clr cch busy */\r
463 dpc_poll = 0; /* clr cch poll */\r
464 }\r
465 else { /* STC */\r
466 setCTL (devc); /* set ctl */\r
467 if (!CMD (devc)) { /* is cmd clr? */\r
468 setCMD (devc); /* set cmd */\r
469 drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */\r
470 fnc = CW_GETFNC (dpc_obuf); /* from cmd word */\r
471 switch (fnc) { /* case on fnc */\r
472\r
473 case FNC_SEEK: /* seek */\r
474 dpc_poll = 1; /* enable polling */\r
475 dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */\r
476 break;\r
477\r
478 case FNC_STA: /* rd sta */\r
479 if (dp_ctype) { clrFSR (devd); } /* 13210? clr dch flag */\r
480 case FNC_CHK: /* check */\r
481 case FNC_AR: /* addr rec */\r
482 dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */\r
483 break;\r
484\r
485 case FNC_RD: case FNC_WD: /* read, write */\r
486 case FNC_REF: case FNC_INIT: /* refine, init */\r
487 dp_goc (fnc, drv, dpc_ctime); /* sched drive */\r
488 break;\r
489 } /* end case */\r
490 } /* end if */\r
491 } /* end else */\r
492 break;\r
493\r
494 default:\r
495 break;\r
496 }\r
497\r
498if (IR & I_HC) { clrFSR (devc); } /* H/C option */\r
499return dat;\r
500}\r
501\r
502/* Start data channel operation */\r
503\r
504void dp_god (int32 fnc, int32 drv, int32 time)\r
505{\r
506dpd_unit.DRV = drv; /* save unit */\r
507dpd_unit.FNC = fnc; /* save function */\r
508sim_activate (&dpd_unit, time);\r
509return;\r
510}\r
511\r
512/* Start controller operation */\r
513\r
514void dp_goc (int32 fnc, int32 drv, int32 time)\r
515{\r
516int32 t;\r
517\r
518if (t = sim_is_active (&dpc_unit[drv])) { /* still seeking? */\r
519 sim_cancel (&dpc_unit[drv]); /* stop seek */\r
520 dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */\r
521 time = time + t; /* include seek time */\r
522 }\r
523dp_ptr = 0; /* init buf ptr */\r
524dpc_eoc = 0; /* clear end cyl */\r
525dpc_busy = drv + 1; /* set busy */\r
526dpd_xfer = 1; /* xfer in prog */\r
527dpc_unit[drv].FNC = fnc; /* save function */\r
528dpc_sta[drv] = dpc_sta[drv] & ~STA_ATN; /* clear ATN */\r
529sim_activate (&dpc_unit[drv], time); /* activate unit */\r
530return;\r
531}\r
532\r
533/* Data channel unit service\r
534\r
535 This routine handles the data channel transfers. It also handles\r
536 data transfers that are blocked by seek in progress.\r
537\r
538 uptr->DRV = target drive\r
539 uptr->FNC = target function\r
540\r
541 Seek substates\r
542 seek - transfer cylinder\r
543 seek1 - transfer head/surface\r
544 Address record\r
545 ar - transfer cylinder\r
546 ar1 - transfer head/surface, finish operation\r
547 Status check - transfer status, finish operation\r
548 Check data\r
549 chk - transfer sector count\r
550*/\r
551\r
552t_stat dpd_svc (UNIT *uptr)\r
553{\r
554int32 i, drv, devc, devd, st;\r
555\r
556drv = uptr->DRV; /* get drive no */\r
557devc = dpc_dib.devno; /* get cch devno */\r
558devd = dpd_dib.devno; /* get dch devno */\r
559switch (uptr->FNC) { /* case function */\r
560\r
561 case FNC_AR: /* arec, need cyl */\r
562 case FNC_SEEK: /* seek, need cyl */\r
563 if (CMD (devd)) { /* dch active? */\r
564 dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */\r
565 dpd_wval = 0; /* clr data valid */\r
566 setFSR (devd); /* set dch flg */\r
567 clrCMD (devd); /* clr dch cmd */\r
568 if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1;\r
569 else uptr->FNC = FNC_SEEK1; /* advance state */\r
570 }\r
571 sim_activate (uptr, dpc_xtime); /* no, wait more */\r
572 break;\r
573\r
574 case FNC_AR1: /* arec, need hd/sec */\r
575 case FNC_SEEK1: /* seek, need hd/sec */\r
576 if (CMD (devd)) { /* dch active? */\r
577 dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */\r
578 dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */\r
579 dpd_wval = 0; /* clr data valid */\r
580 setFSR (devd); /* set dch flg */\r
581 clrCMD (devd); /* clr dch cmd */\r
582 if (uptr->FNC == FNC_AR1) {\r
583 setFSR (devc); /* set cch flg */\r
584 clrCMD (devc); /* clr cch cmd */\r
585 dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */\r
586 break; /* done if Address Record */\r
587 }\r
588 if (sim_is_active (&dpc_unit[drv])) { /* if busy, */\r
589 dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */\r
590 break; /* allow prev seek to cmpl */\r
591 }\r
592 if ((dpc_rarc >= DP_NUMCY) || /* invalid cyl? */\r
593 (dp_ctype && (dpc_rars >= DP_NUMSC3))) { /* invalid sector? (13210A) */\r
594 dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */\r
595 sim_activate (&dpc_unit[drv], 1); /* schedule drive no-wait */\r
596 dpc_unit[drv].FNC = FNC_SEEK3; /* do immed compl w/poll */\r
597 break;\r
598 }\r
599 st = abs (dpc_rarc - dpc_ucyl[drv]) * dpc_stime;\r
600 if (st == 0) st = dpc_stime; /* min time */\r
601 dpc_ucyl[drv] = dpc_rarc; /* transfer RAR */\r
602 sim_activate (&dpc_unit[drv], st); /* schedule drive */\r
603 dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) &\r
604 ~(STA_SKE | STA_SKI | STA_HUNT);\r
605 dpc_unit[drv].FNC = FNC_SEEK2; /* set operation */\r
606 }\r
607 else sim_activate (uptr, dpc_xtime); /* no, wait more */\r
608 break;\r
609\r
610 case FNC_STA: /* read status */\r
611 if (CMD (devd) || dp_ctype) { /* dch act or 13210? */\r
612 if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */\r
613 dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */\r
614 if (dp_ctype) dpd_ibuf = /* 13210? */\r
615 (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) |\r
616 (dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0);\r
617 }\r
618 else dpd_ibuf = STA_UNLOADED; /* not ready */\r
619 if (dpd_ibuf & STA_ANYERR) /* errors? set flg */\r
620 dpd_ibuf = dpd_ibuf | STA_ERR;\r
621 setFSR (devd); /* set dch flg */\r
622 clrCMD (devd); /* clr dch cmd */\r
623 clrCMD (devc); /* clr cch cmd */\r
624 }\r
625 dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */\r
626 ~(STA_ATN | STA_1ST | STA_OVR |\r
627 STA_RWU | STA_ACU | STA_EOC |\r
628 STA_AER | STA_FLG | STA_DTE);\r
629 dpc_poll = 1; /* enable polling */\r
630 for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */\r
631 if (dpc_sta[i] & STA_ATN) { /* any ATN set? */\r
632 setFSR (devc); /* set cch flg */\r
633 break;\r
634 }\r
635 }\r
636 break;\r
637\r
638 case FNC_CHK: /* check, need cnt */\r
639 if (CMD (devd)) { /* dch active? */\r
640 dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */\r
641 dpd_wval = 0; /* clr data valid */\r
642 dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */\r
643 }\r
644 else sim_activate (uptr, dpc_xtime); /* wait more */\r
645 break;\r
646\r
647 default:\r
648 return SCPE_IERR;\r
649 }\r
650\r
651return SCPE_OK;\r
652}\r
653\r
654/* Drive unit service\r
655\r
656 This routine handles the data transfers.\r
657\r
658 Seek substates\r
659 seek2 - done\r
660 Refine sector - erase sector, finish operation\r
661 Check data\r
662 chk1 - finish operation\r
663 Read\r
664 Write\r
665*/\r
666\r
667#define GETDA(x,y,z) \\r
668 (((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD\r
669\r
670t_stat dpc_svc (UNIT *uptr)\r
671{\r
672int32 da, drv, devc, devd, err;\r
673\r
674err = 0; /* assume no err */\r
675drv = uptr - dpc_dev.units; /* get drive no */\r
676devc = dpc_dib.devno; /* get cch devno */\r
677devd = dpd_dib.devno; /* get dch devno */\r
678if (uptr->flags & UNIT_UNLOAD) { /* drive down? */\r
679 setFSR (devc); /* set cch flg */\r
680 clrCMD (devc); /* clr cch cmd */\r
681 dpc_sta[drv] = 0; /* clr status */\r
682 dpc_busy = 0; /* ctlr is free */\r
683 dpc_poll = 0; /* polling disabled */\r
684 dpd_xfer = 0;\r
685 dpd_wval = 0;\r
686 return SCPE_OK;\r
687 }\r
688switch (uptr->FNC) { /* case function */\r
689\r
690 case FNC_SEEK2: /* positioning done */\r
691 dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */\r
692 case FNC_SEEK3: /* seek complete */\r
693 if (dpc_poll) { /* polling enabled? */\r
694 setFSR (devc); /* set cch flg */\r
695 clrCMD (devc); /* clear cmd */\r
696 }\r
697 return SCPE_OK;\r
698\r
699 case FNC_REF: /* refine sector */\r
700 break; /* just a NOP */\r
701\r
702 case FNC_RD: /* read */\r
703 case FNC_CHK1: /* check */\r
704 if (dp_ptr == 0) { /* new sector? */\r
705 if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;\r
706 if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */\r
707 dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */\r
708 if (dpc_rars >= DP_NUMSC) { /* bad sector? */\r
709 dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */\r
710 break;\r
711 }\r
712 if (dpc_eoc) { /* end of cyl? */\r
713 dpc_sta[drv] = dpc_sta[drv] | STA_EOC;\r
714 break;\r
715 }\r
716 da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */\r
717 dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */\r
718 if (dpc_rars == 0) { /* wrap? */\r
719 dpc_rarh = dpc_rarh ^ 1; /* incr head */\r
720 dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */\r
721 }\r
722 if (err = fseek (uptr->fileref, da * sizeof (int16),\r
723 SEEK_SET)) break;\r
724 fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);\r
725 if (err = ferror (uptr->fileref)) break;\r
726 }\r
727 dpd_ibuf = dpxb[dp_ptr++]; /* get word */\r
728 if (dp_ptr >= DP_NUMWD) { /* end of sector? */\r
729 if (uptr->FNC == FNC_CHK1) { /* check? */\r
730 dpc_cnt = (dpc_cnt - 1) & DA_CKMASK; /* decr count */\r
731 if (dpc_cnt == 0) break; /* stop at zero */\r
732 }\r
733 dp_ptr = 0; /* wrap buf ptr */\r
734 }\r
735 if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */\r
736 setFSR (devd); /* set flag */\r
737 }\r
738 clrCMD (devd); /* clr dch cmd */\r
739 sim_activate (uptr, dpc_xtime); /* sched next word */\r
740 return SCPE_OK;\r
741\r
742 case FNC_INIT: /* init */\r
743 case FNC_WD: /* write */\r
744 if (dp_ptr == 0) { /* start sector? */\r
745 if (!CMD (devd) && !dpd_wval) break; /* xfer done? */\r
746 if (uptr->flags & UNIT_WPRT) { /* wr prot? */\r
747 dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */\r
748 break; /* done */\r
749 }\r
750 if ((dpc_rarc != dpc_ucyl[drv]) || /* RAR cyl miscompare? */\r
751 (dpc_rars >= DP_NUMSC)) { /* bad sector? */\r
752 dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* address error */\r
753 break;\r
754 }\r
755 if (dpc_eoc) { /* end of cyl? */\r
756 dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */\r
757 break; /* done */\r
758 }\r
759 }\r
760 dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */\r
761 dpd_wval = 0; /* clr data valid */\r
762 if (dp_ptr >= DP_NUMWD) { /* buffer full? */\r
763 da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */\r
764 dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */\r
765 if (dpc_rars == 0) { /* wrap? */\r
766 dpc_rarh = dpc_rarh ^ 1; /* incr head */\r
767 dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */\r
768 }\r
769 if (err = fseek (uptr->fileref, da * sizeof (int16),\r
770 SEEK_SET)) break;\r
771 fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);\r
772 if (err = ferror (uptr->fileref)) break; /* error? */\r
773 dp_ptr = 0; /* next sector */\r
774 }\r
775 if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */\r
776 setFSR (devd); /* set flag */\r
777 }\r
778 clrCMD (devd); /* clr dch cmd */\r
779 sim_activate (uptr, dpc_xtime); /* sched next word */\r
780 return SCPE_OK;\r
781\r
782 default:\r
783 return SCPE_IERR;\r
784 } /* end case fnc */\r
785\r
786dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */\r
787setFSR (devc); /* set cch flg */\r
788clrCMD (devc); /* clr cch cmd */\r
789dpc_busy = 0; /* ctlr is free */\r
790dpd_xfer = dpd_wval = 0;\r
791if (err != 0) { /* error? */\r
792 perror ("DP I/O error");\r
793 clearerr (uptr->fileref);\r
794 return SCPE_IOERR;\r
795 }\r
796return SCPE_OK;\r
797}\r
798\r
799/* Reset routine */\r
800\r
801t_stat dpc_reset (DEVICE *dptr)\r
802{\r
803int32 drv;\r
804\r
805hp_enbdis_pair (dptr, /* make pair cons */\r
806 (dptr == &dpd_dev)? &dpc_dev: &dpd_dev);\r
807dpd_ibuf = dpd_obuf = 0; /* clear buffers */\r
808dpc_busy = dpc_obuf = 0;\r
809dpc_eoc = 0;\r
810dpc_poll = 0;\r
811dpd_xfer = dpd_wval = 0;\r
812dp_ptr = 0;\r
813dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */\r
814dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */\r
815dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */\r
816dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */\r
817dpc_dib.flg = dpd_dib.flg = 1; /* set flg */\r
818dpc_dib.srq = dpd_dib.flg = 1; /* srq follows flg */\r
819sim_cancel (&dpd_unit); /* cancel dch */\r
820for (drv = 0; drv < DP_NUMDRV; drv++) { /* loop thru drives */\r
821 sim_cancel (&dpc_unit[drv]); /* cancel activity */\r
822 dpc_unit[drv].FNC = 0; /* clear function */\r
823 dpc_ucyl[drv] = 0; /* clear drive pos */\r
824 if (dpc_unit[drv].flags & UNIT_ATT)\r
825 dpc_sta[drv] = dpc_sta[drv] & STA_1ST; /* first seek status */\r
826 else dpc_sta[drv] = 0; /* clear status */\r
827 }\r
828return SCPE_OK;\r
829}\r
830\r
831/* Attach routine */\r
832\r
833t_stat dpc_attach (UNIT *uptr, char *cptr)\r
834{\r
835t_stat r;\r
836\r
837r = attach_unit (uptr, cptr); /* attach unit */\r
838if (r == SCPE_OK) dpc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */\r
839return r;\r
840}\r
841\r
842/* Detach routine */\r
843\r
844t_stat dpc_detach (UNIT* uptr)\r
845{\r
846dpc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */\r
847return detach_unit (uptr); /* detach unit */\r
848}\r
849\r
850/* Load and unload heads */\r
851\r
852t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)\r
853{\r
854uint32 drv;\r
855\r
856if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */\r
857\r
858if (value == UNIT_UNLOAD) /* unload heads? */\r
859 uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */\r
860else { /* load heads */\r
861 uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */\r
862 drv = uptr - dpc_dev.units; /* get drive no */\r
863 dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */\r
864 if (dpc_poll) { /* polling enabled? */\r
865 dpc_dib.fbf = 1; /* set fbf */\r
866 dpc_dib.flg = 1; /* set flg */\r
867 dpc_dib.srq = 1; /* srq follows flg */\r
868 }\r
869 }\r
870return SCPE_OK;\r
871}\r
872\r
873/* Set controller type */\r
874\r
875t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)\r
876{\r
877int32 i;\r
878\r
879if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;\r
880for (i = 0; i < DP_NUMDRV; i++) {\r
881 if (dpc_unit[i].flags & UNIT_ATT) return SCPE_ALATT;\r
882 }\r
883for (i = 0; i < DP_NUMDRV; i++)\r
884 dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2);\r
885dp_ctype = val;\r
886return SCPE_OK;\r
887}\r
888\r
889/* Show controller type */\r
890\r
891t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)\r
892{\r
893if (dp_ctype) fprintf (st, "13210A");\r
894else fprintf (st, "12557A");\r
895return SCPE_OK;\r
896}\r
897\r
898/* 7900/7901 bootstrap routine (HP 12992F ROM) */\r
899\r
900const uint16 dp_rom[IBL_LNT] = {\r
901 0106710, /*ST CLC DC ; clr dch */\r
902 0106711, /* CLC CC ; clr cch */\r
903 0017757, /* JSB STAT ; get status */\r
904 0067746, /*SK LDB SKCMD ; seek cmd */\r
905 0106610, /* OTB DC ; cyl # */\r
906 0103710, /* STC DC,C ; to dch */\r
907 0106611, /* OTB CC ; seek cmd */\r
908 0103711, /* STC CC,C ; to cch */\r
909 0102310, /* SFS DC ; addr wd ok? */\r
910 0027710, /* JMP *-1 ; no, wait */\r
911 0006400, /* CLB */\r
912 0102501, /* LIA 1 ; read switches */\r
913 0002011, /* SLA,RSS ; <0> set? */\r
914 0047747, /* ADB BIT9 ; head 2 = removable */\r
915 0106610, /* OTB DC ; head/sector */\r
916 0103710, /* STC DC,C ; to dch */\r
917 0102311, /* SFS CC ; seek done? */\r
918 0027720, /* JMP *-1 ; no, wait */\r
919 0017757, /* JSB STAT ; get status */\r
920 0067776, /* LDB DMACW ; DMA control */\r
921 0106606, /* OTB 6 */\r
922 0067750, /* LDB ADDR1 ; memory addr */\r
923 0106602, /* OTB 2 */\r
924 0102702, /* STC 2 ; flip DMA ctrl */\r
925 0067752, /* LDB CNT ; word count */\r
926 0106602, /* OTB 2 */\r
927 0063745, /* LDB RDCMD ; read cmd */\r
928 0102611, /* OTA CC ; to cch */\r
929 0103710, /* STC DC,C ; start dch */\r
930 0103706, /* STC 6,C ; start DMA */\r
931 0103711, /* STC CC,C ; start cch */\r
932 0102311, /* SFS CC ; done? */\r
933 0027737, /* JMP *-1 ; no, wait */\r
934 0017757, /* JSB STAT ; get status */\r
935 0027775, /* JMP XT ; done */\r
936 0037766, /*FSMSK 037766 ; status mask */\r
937 0004000, /*STMSK 004000 ; unsafe mask */\r
938 0020000, /*RDCMD 020000 ; read cmd */\r
939 0030000, /*SKCMD 030000 ; seek cmd */\r
940 0001000, /*BIT9 001000 ; head 2 select */\r
941 0102011, /*ADDR1 102011 */\r
942 0102055, /*ADDR2 102055 */\r
943 0164000, /*CNT -6144. */\r
944 0, 0, 0, 0, /* unused */\r
945 0000000, /*STAT 0 */\r
946 0002400, /* CLA ; status request */\r
947 0102611, /* OTC CC ; to cch */\r
948 0103711, /* STC CC,C ; start cch */\r
949 0102310, /* SFS DC ; done? */\r
950 0027763, /* JMP *-1 */\r
951 0102510, /* LIA DC ; get status */\r
952 0013743, /* AND FSMSK ; mask 15,14,3,0 */\r
953 0002003, /* SZA,RSS ; drive ready? */\r
954 0127757, /* JMP STAT,I ; yes */\r
955 0013744, /* AND STMSK ; fault? */\r
956 0002002, /* SZA */\r
957 0102030, /* HLT 30 ; yes */\r
958 0027700, /* JMP ST ; no, retry */\r
959 0117751, /*XT JSB ADDR2,I ; start program */\r
960 0120010, /*DMACW 120000+DC */\r
961 0000000 /* -ST */\r
962 };\r
963\r
964t_stat dpc_boot (int32 unitno, DEVICE *dptr)\r
965{\r
966int32 dev;\r
967\r
968if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */\r
969dev = dpd_dib.devno; /* get data chan dev */\r
970if (ibl_copy (dp_rom, dev)) return SCPE_IERR; /* copy boot to memory */\r
971SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */\r
972if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */\r
973return SCPE_OK;\r
974}\r