Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* hp2100_dq.c: HP 2100 12565A disk simulator\r |
2 | \r | |
3 | Copyright (c) 1993-2006, Bill McDermith\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 the author 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 the author.\r | |
25 | \r | |
26 | dq 12565A 2883 disk system\r | |
27 | \r | |
28 | 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)\r | |
29 | 01-Mar-05 JDB Added SET UNLOAD/LOAD\r | |
30 | 07-Oct-04 JDB Fixed enable/disable from either device\r | |
31 | Shortened xtime from 5 to 3 (drive avg 156KW/second)\r | |
32 | Fixed not ready/any error status\r | |
33 | Fixed RAR model\r | |
34 | 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan)\r | |
35 | 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r | |
36 | Fixed SR setting in IBL\r | |
37 | Revised IBL loader\r | |
38 | Implemented DMA SRQ (follows FLG)\r | |
39 | 25-Apr-03 RMS Fixed bug in status check\r | |
40 | 10-Nov-02 RMS Added boot command, rebuilt like 12559/13210\r | |
41 | 09-Jan-02 WOM Copied dp driver and mods for 2883\r | |
42 | \r | |
43 | Differences between 12559/13210 and 12565 controllers\r | |
44 | - 12565 stops transfers on address miscompares; 12559/13210 only stops writes\r | |
45 | - 12565 does not set error on positioner busy\r | |
46 | - 12565 does not set positioner busy if already on cylinder\r | |
47 | - 12565 does not need eoc logic, it will hit an invalid head number\r | |
48 | \r | |
49 | The controller's "Record Address Register" (RAR) contains the CHS address of\r | |
50 | the last Position or Load Address command executed. The RAR is shared among\r | |
51 | all drives on the controller. In addition, each drive has an internal\r | |
52 | position register that contains the last cylinder and head position\r | |
53 | transferred to the drive during Position command execution (sector operations\r | |
54 | always start with the RAR sector position).\r | |
55 | \r | |
56 | In a real drive, the address field of the sector under the head is read and\r | |
57 | compared to the RAR. When they match, the target sector is under the head\r | |
58 | and is ready for reading or writing. If a match doesn't occur, an Address\r | |
59 | Error is indicated. In the simulator, the address field is obtained from the\r | |
60 | drive's current position register during a read, i.e., the "on-disc" address\r | |
61 | field is assumed to match the current position.\r | |
62 | \r | |
63 | Reference:\r | |
64 | - 12565A Disc Interface Kit Operating and Service Manual (12565-90003, Aug-1973)\r | |
65 | \r | |
66 | The following implemented behaviors have been inferred from secondary sources\r | |
67 | (diagnostics, operating system drivers, etc.), due to absent or contradictory\r | |
68 | authoritative information; future correction may be needed:\r | |
69 | \r | |
70 | 1. Read Address command starts at the sector number in the RAR.\r | |
71 | */\r | |
72 | \r | |
73 | #include "hp2100_defs.h"\r | |
74 | \r | |
75 | #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */\r | |
76 | #define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */\r | |
77 | #define UNIT_WLK (1 << UNIT_V_WLK)\r | |
78 | #define UNIT_UNLOAD (1 << UNIT_V_UNLOAD)\r | |
79 | #define FNC u3 /* saved function */\r | |
80 | #define DRV u4 /* drive number (DC) */\r | |
81 | #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */\r | |
82 | \r | |
83 | #define DQ_N_NUMWD 7\r | |
84 | #define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */\r | |
85 | #define DQ_NUMSC 23 /* sectors/track */\r | |
86 | #define DQ_NUMSF 20 /* tracks/cylinder */\r | |
87 | #define DQ_NUMCY 203 /* cylinders/disk */\r | |
88 | #define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD)\r | |
89 | #define DQ_NUMDRV 2 /* # drives */\r | |
90 | \r | |
91 | /* Command word */\r | |
92 | \r | |
93 | #define CW_V_FNC 12 /* function */\r | |
94 | #define CW_M_FNC 017\r | |
95 | #define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC)\r | |
96 | /* 000 /* unused */\r | |
97 | #define FNC_STA 001 /* status check */\r | |
98 | #define FNC_RCL 002 /* recalibrate */\r | |
99 | #define FNC_SEEK 003 /* seek */\r | |
100 | #define FNC_RD 004 /* read */\r | |
101 | #define FNC_WD 005 /* write */\r | |
102 | #define FNC_RA 006 /* read address */\r | |
103 | #define FNC_WA 007 /* write address */\r | |
104 | #define FNC_CHK 010 /* check */\r | |
105 | #define FNC_LA 013 /* load address */\r | |
106 | #define FNC_AS 014 /* address skip */\r | |
107 | \r | |
108 | #define FNC_SEEK1 020 /* fake - seek1 */\r | |
109 | #define FNC_SEEK2 021 /* fake - seek2 */\r | |
110 | #define FNC_SEEK3 022 /* fake - seek3 */\r | |
111 | #define FNC_CHK1 023 /* fake - check1 */\r | |
112 | #define FNC_LA1 024 /* fake - ldaddr1 */\r | |
113 | \r | |
114 | #define CW_V_DRV 0 /* drive */\r | |
115 | #define CW_M_DRV 01\r | |
116 | #define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)\r | |
117 | \r | |
118 | /* Disk address words */\r | |
119 | \r | |
120 | #define DA_V_CYL 0 /* cylinder */\r | |
121 | #define DA_M_CYL 0377\r | |
122 | #define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)\r | |
123 | #define DA_V_HD 8 /* head */\r | |
124 | #define DA_M_HD 037\r | |
125 | #define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)\r | |
126 | #define DA_V_SC 0 /* sector */\r | |
127 | #define DA_M_SC 037\r | |
128 | #define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)\r | |
129 | #define DA_CKMASK 0777 /* check mask */\r | |
130 | \r | |
131 | /* Status in dqc_sta[drv] - (d) = dynamic */\r | |
132 | \r | |
133 | #define STA_DID 0000200 /* drive ID (d) */\r | |
134 | #define STA_NRDY 0000100 /* not ready (d) */\r | |
135 | #define STA_EOC 0000040 /* end of cylinder */\r | |
136 | #define STA_AER 0000020 /* addr error */\r | |
137 | #define STA_FLG 0000010 /* flagged */\r | |
138 | #define STA_BSY 0000004 /* seeking */\r | |
139 | #define STA_DTE 0000002 /* data error */\r | |
140 | #define STA_ERR 0000001 /* any error */\r | |
141 | #define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE)\r | |
142 | \r | |
143 | extern uint32 PC, SR;\r | |
144 | extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r | |
145 | \r | |
146 | int32 dqc_busy = 0; /* cch xfer */\r | |
147 | int32 dqc_cnt = 0; /* check count */\r | |
148 | int32 dqc_stime = 100; /* seek time */\r | |
149 | int32 dqc_ctime = 100; /* command time */\r | |
150 | int32 dqc_xtime = 3; /* xfer time */\r | |
151 | int32 dqc_dtime = 2; /* dch time */\r | |
152 | int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */\r | |
153 | int32 dqc_obuf = 0; /* cch buffers */\r | |
154 | int32 dqd_xfer = 0; /* xfer in prog */\r | |
155 | int32 dqd_wval = 0; /* write data valid */\r | |
156 | int32 dq_ptr = 0; /* buffer ptr */\r | |
157 | uint8 dqc_rarc = 0; /* RAR cylinder */\r | |
158 | uint8 dqc_rarh = 0; /* RAR head */\r | |
159 | uint8 dqc_rars = 0; /* RAR sector */\r | |
160 | uint8 dqc_ucyl[DQ_NUMDRV] = { 0 }; /* unit cylinder */\r | |
161 | uint8 dqc_uhed[DQ_NUMDRV] = { 0 }; /* unit head */\r | |
162 | uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */\r | |
163 | uint16 dqxb[DQ_NUMWD]; /* sector buffer */\r | |
164 | \r | |
165 | DEVICE dqd_dev, dqc_dev;\r | |
166 | int32 dqdio (int32 inst, int32 IR, int32 dat);\r | |
167 | int32 dqcio (int32 inst, int32 IR, int32 dat);\r | |
168 | t_stat dqc_svc (UNIT *uptr);\r | |
169 | t_stat dqd_svc (UNIT *uptr);\r | |
170 | t_stat dqc_reset (DEVICE *dptr);\r | |
171 | t_stat dqc_attach (UNIT *uptr, char *cptr);\r | |
172 | t_stat dqc_detach (UNIT* uptr);\r | |
173 | t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc);\r | |
174 | t_stat dqc_boot (int32 unitno, DEVICE *dptr);\r | |
175 | void dq_god (int32 fnc, int32 drv, int32 time);\r | |
176 | void dq_goc (int32 fnc, int32 drv, int32 time);\r | |
177 | \r | |
178 | /* DQD data structures\r | |
179 | \r | |
180 | dqd_dev DQD device descriptor\r | |
181 | dqd_unit DQD unit list\r | |
182 | dqd_reg DQD register list\r | |
183 | */\r | |
184 | \r | |
185 | DIB dq_dib[] = {\r | |
186 | { DQD, 0, 0, 0, 0, 0, &dqdio },\r | |
187 | { DQC, 0, 0, 0, 0, 0, &dqcio }\r | |
188 | };\r | |
189 | \r | |
190 | #define dqd_dib dq_dib[0]\r | |
191 | #define dqc_dib dq_dib[1]\r | |
192 | \r | |
193 | UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) };\r | |
194 | \r | |
195 | REG dqd_reg[] = {\r | |
196 | { ORDATA (IBUF, dqd_ibuf, 16) },\r | |
197 | { ORDATA (OBUF, dqd_obuf, 16) },\r | |
198 | { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) },\r | |
199 | { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) },\r | |
200 | { FLDATA (CMD, dqd_dib.cmd, 0) },\r | |
201 | { FLDATA (CTL, dqd_dib.ctl, 0) },\r | |
202 | { FLDATA (FLG, dqd_dib.flg, 0) },\r | |
203 | { FLDATA (FBF, dqd_dib.fbf, 0) },\r | |
204 | { FLDATA (SRQ, dqd_dib.srq, 0) },\r | |
205 | { FLDATA (XFER, dqd_xfer, 0) },\r | |
206 | { FLDATA (WVAL, dqd_wval, 0) },\r | |
207 | { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO },\r | |
208 | { NULL }\r | |
209 | };\r | |
210 | \r | |
211 | MTAB dqd_mod[] = {\r | |
212 | { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r | |
213 | &hp_setdev, &hp_showdev, &dqd_dev },\r | |
214 | { 0 }\r | |
215 | };\r | |
216 | \r | |
217 | DEVICE dqd_dev = {\r | |
218 | "DQD", &dqd_unit, dqd_reg, dqd_mod,\r | |
219 | 1, 10, DQ_N_NUMWD, 1, 8, 16,\r | |
220 | NULL, NULL, &dqc_reset,\r | |
221 | NULL, NULL, NULL,\r | |
222 | &dqd_dib, DEV_DISABLE\r | |
223 | };\r | |
224 | \r | |
225 | /* DQC data structures\r | |
226 | \r | |
227 | dqc_dev DQC device descriptor\r | |
228 | dqc_unit DQC unit list\r | |
229 | dqc_reg DQC register list\r | |
230 | dqc_mod DQC modifier list\r | |
231 | */\r | |
232 | \r | |
233 | UNIT dqc_unit[] = {\r | |
234 | { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r | |
235 | UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) },\r | |
236 | { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE |\r | |
237 | UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) }\r | |
238 | };\r | |
239 | \r | |
240 | REG dqc_reg[] = {\r | |
241 | { ORDATA (OBUF, dqc_obuf, 16) },\r | |
242 | { ORDATA (BUSY, dqc_busy, 2), REG_RO },\r | |
243 | { ORDATA (CNT, dqc_cnt, 9) },\r | |
244 | { FLDATA (CMD, dqc_dib.cmd, 0) },\r | |
245 | { FLDATA (CTL, dqc_dib.ctl, 0) },\r | |
246 | { FLDATA (FLG, dqc_dib.flg, 0) },\r | |
247 | { FLDATA (FBF, dqc_dib.fbf, 0) },\r | |
248 | { FLDATA (SRQ, dqc_dib.srq, 0) },\r | |
249 | { DRDATA (RARC, dqc_rarc, 8), PV_RZRO },\r | |
250 | { DRDATA (RARH, dqc_rarh, 5), PV_RZRO },\r | |
251 | { DRDATA (RARS, dqc_rars, 5), PV_RZRO },\r | |
252 | { BRDATA (CYL, dqc_ucyl, 10, 8, DQ_NUMDRV), PV_RZRO },\r | |
253 | { BRDATA (HED, dqc_uhed, 10, 5, DQ_NUMDRV), PV_RZRO },\r | |
254 | { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) },\r | |
255 | { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT },\r | |
256 | { DRDATA (DTIME, dqc_dtime, 24), PV_LEFT },\r | |
257 | { DRDATA (STIME, dqc_stime, 24), PV_LEFT },\r | |
258 | { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT },\r | |
259 | { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0,\r | |
260 | DQ_NUMDRV, REG_HRO) },\r | |
261 | { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO },\r | |
262 | { NULL }\r | |
263 | };\r | |
264 | \r | |
265 | MTAB dqc_mod[] = {\r | |
266 | { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dqc_load_unload },\r | |
267 | { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dqc_load_unload },\r | |
268 | { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
269 | { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r | |
270 | { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",\r | |
271 | &hp_setdev, &hp_showdev, &dqd_dev },\r | |
272 | { 0 }\r | |
273 | };\r | |
274 | \r | |
275 | DEVICE dqc_dev = {\r | |
276 | "DQC", dqc_unit, dqc_reg, dqc_mod,\r | |
277 | DQ_NUMDRV, 8, 24, 1, 8, 16,\r | |
278 | NULL, NULL, &dqc_reset,\r | |
279 | &dqc_boot, &dqc_attach, &dqc_detach,\r | |
280 | &dqc_dib, DEV_DISABLE\r | |
281 | };\r | |
282 | \r | |
283 | /* IO instructions */\r | |
284 | \r | |
285 | int32 dqdio (int32 inst, int32 IR, int32 dat)\r | |
286 | {\r | |
287 | int32 devd;\r | |
288 | \r | |
289 | devd = IR & I_DEVMASK; /* get device no */\r | |
290 | switch (inst) { /* case on opcode */\r | |
291 | \r | |
292 | case ioFLG: /* flag clear/set */\r | |
293 | if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */\r | |
294 | break;\r | |
295 | \r | |
296 | case ioSFC: /* skip flag clear */\r | |
297 | if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;\r | |
298 | break;\r | |
299 | \r | |
300 | case ioSFS: /* skip flag set */\r | |
301 | if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;\r | |
302 | break;\r | |
303 | \r | |
304 | case ioOTX: /* output */\r | |
305 | dqd_obuf = dat;\r | |
306 | if (!dqc_busy || dqd_xfer) dqd_wval = 1; /* if !overrun, valid */\r | |
307 | break;\r | |
308 | \r | |
309 | case ioMIX: /* merge */\r | |
310 | dat = dat | dqd_ibuf;\r | |
311 | break;\r | |
312 | \r | |
313 | case ioLIX: /* load */\r | |
314 | dat = dqd_ibuf;\r | |
315 | break;\r | |
316 | \r | |
317 | case ioCRS: /* control reset (action unverif) */\r | |
318 | case ioCTL: /* control clear/set */\r | |
319 | if (IR & I_CTL) { /* CLC */\r | |
320 | clrCTL (devd); /* clr ctl, cmd */\r | |
321 | clrCMD (devd);\r | |
322 | dqd_xfer = 0; /* clr xfer */\r | |
323 | }\r | |
324 | else { /* STC */\r | |
325 | setCTL (devd); /* set ctl, cmd */\r | |
326 | setCMD (devd);\r | |
327 | if (dqc_busy && !dqd_xfer) /* overrun? */\r | |
328 | dqc_sta[dqc_busy - 1] |= STA_DTE;\r | |
329 | }\r | |
330 | break;\r | |
331 | \r | |
332 | default:\r | |
333 | break;\r | |
334 | }\r | |
335 | \r | |
336 | if (IR & I_HC) { clrFSR (devd); } /* H/C option */\r | |
337 | return dat;\r | |
338 | }\r | |
339 | \r | |
340 | int32 dqcio (int32 inst, int32 IR, int32 dat)\r | |
341 | {\r | |
342 | int32 devc, fnc, drv;\r | |
343 | \r | |
344 | devc = IR & I_DEVMASK; /* get device no */\r | |
345 | switch (inst) { /* case on opcode */\r | |
346 | \r | |
347 | case ioFLG: /* flag clear/set */\r | |
348 | if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */\r | |
349 | break;\r | |
350 | \r | |
351 | case ioSFC: /* skip flag clear */\r | |
352 | if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;\r | |
353 | break;\r | |
354 | \r | |
355 | case ioSFS: /* skip flag set */\r | |
356 | if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;\r | |
357 | break;\r | |
358 | \r | |
359 | case ioOTX: /* output */\r | |
360 | dqc_obuf = dat;\r | |
361 | break;\r | |
362 | \r | |
363 | case ioLIX: /* load */\r | |
364 | dat = 0;\r | |
365 | case ioMIX: /* merge */\r | |
366 | break; /* no data */\r | |
367 | \r | |
368 | case ioCRS: /* control reset (action unverif) */\r | |
369 | case ioCTL: /* control clear/set */\r | |
370 | if (IR & I_CTL) { /* CLC? */\r | |
371 | clrCMD (devc); /* clr cmd, ctl */\r | |
372 | clrCTL (devc); /* cancel non-seek */\r | |
373 | if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]);\r | |
374 | sim_cancel (&dqd_unit); /* cancel dch */\r | |
375 | dqd_xfer = 0; /* clr dch xfer */\r | |
376 | dqc_busy = 0; /* clr busy */\r | |
377 | }\r | |
378 | else { /* STC */\r | |
379 | setCTL (devc); /* set ctl */\r | |
380 | if (!CMD (devc)) { /* cmd clr? */\r | |
381 | setCMD (devc); /* set cmd, ctl */\r | |
382 | drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */\r | |
383 | fnc = CW_GETFNC (dqc_obuf); /* from cmd word */\r | |
384 | switch (fnc) { /* case on fnc */\r | |
385 | case FNC_SEEK: case FNC_RCL: /* seek, recal */\r | |
386 | case FNC_CHK: /* check */\r | |
387 | dqc_sta[drv] = 0; /* clear status */\r | |
388 | case FNC_STA: case FNC_LA: /* rd sta, load addr */\r | |
389 | dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */\r | |
390 | break;\r | |
391 | case FNC_RD: case FNC_WD: /* read, write */\r | |
392 | case FNC_RA: case FNC_WA: /* rd addr, wr addr */\r | |
393 | case FNC_AS: /* address skip */\r | |
394 | dq_goc (fnc, drv, dqc_ctime); /* sched drive */\r | |
395 | break;\r | |
396 | } /* end case */\r | |
397 | } /* end if !CMD */\r | |
398 | } /* end else */\r | |
399 | break;\r | |
400 | \r | |
401 | default:\r | |
402 | break;\r | |
403 | }\r | |
404 | \r | |
405 | if (IR & I_HC) { clrFSR (devc); } /* H/C option */\r | |
406 | return dat;\r | |
407 | }\r | |
408 | \r | |
409 | /* Start data channel operation */\r | |
410 | \r | |
411 | void dq_god (int32 fnc, int32 drv, int32 time)\r | |
412 | {\r | |
413 | dqd_unit.DRV = drv; /* save unit */\r | |
414 | dqd_unit.FNC = fnc; /* save function */\r | |
415 | sim_activate (&dqd_unit, time);\r | |
416 | return;\r | |
417 | }\r | |
418 | \r | |
419 | /* Start controller operation */\r | |
420 | \r | |
421 | void dq_goc (int32 fnc, int32 drv, int32 time)\r | |
422 | {\r | |
423 | int32 t;\r | |
424 | \r | |
425 | if (t = sim_is_active (&dqc_unit[drv])) { /* still seeking? */\r | |
426 | sim_cancel (&dqc_unit[drv]); /* cancel */\r | |
427 | time = time + t; /* include seek time */\r | |
428 | }\r | |
429 | dqc_sta[drv] = 0; /* clear status */\r | |
430 | dq_ptr = 0; /* init buf ptr */\r | |
431 | dqc_busy = drv + 1; /* set busy */\r | |
432 | dqd_xfer = 1; /* xfer in prog */\r | |
433 | dqc_unit[drv].FNC = fnc; /* save function */\r | |
434 | sim_activate (&dqc_unit[drv], time); /* activate unit */\r | |
435 | return;\r | |
436 | }\r | |
437 | \r | |
438 | /* Data channel unit service\r | |
439 | \r | |
440 | This routine handles the data channel transfers. It also handles\r | |
441 | data transfers that are blocked by seek in progress.\r | |
442 | \r | |
443 | uptr->DRV = target drive\r | |
444 | uptr->FNC = target function\r | |
445 | \r | |
446 | Seek substates\r | |
447 | seek - transfer cylinder\r | |
448 | seek1 - transfer head/surface, sched drive\r | |
449 | Recalibrate substates\r | |
450 | rcl - clear cyl/head/surface, sched drive\r | |
451 | Load address\r | |
452 | la - transfer cylinder\r | |
453 | la1 - transfer head/surface, finish operation\r | |
454 | Status check - transfer status, finish operation\r | |
455 | Check data\r | |
456 | chk - transfer sector count, sched drive\r | |
457 | */\r | |
458 | \r | |
459 | t_stat dqd_svc (UNIT *uptr)\r | |
460 | {\r | |
461 | int32 drv, devc, devd, st;\r | |
462 | \r | |
463 | drv = uptr->DRV; /* get drive no */\r | |
464 | devc = dqc_dib.devno; /* get cch devno */\r | |
465 | devd = dqd_dib.devno; /* get dch devno */\r | |
466 | switch (uptr->FNC) { /* case function */\r | |
467 | \r | |
468 | case FNC_LA: /* arec, need cyl */\r | |
469 | case FNC_SEEK: /* seek, need cyl */\r | |
470 | if (CMD (devd)) { /* dch active? */\r | |
471 | dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */\r | |
472 | dqd_wval = 0; /* clr data valid */\r | |
473 | setFSR (devd); /* set dch flg */\r | |
474 | clrCMD (devd); /* clr dch cmd */\r | |
475 | if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1;\r | |
476 | else uptr->FNC = FNC_SEEK1; /* advance state */\r | |
477 | }\r | |
478 | sim_activate (uptr, dqc_xtime); /* no, wait more */\r | |
479 | break;\r | |
480 | \r | |
481 | case FNC_LA1: /* arec, need hd/sec */\r | |
482 | case FNC_SEEK1: /* seek, need hd/sec */\r | |
483 | if (CMD (devd)) { /* dch active? */\r | |
484 | dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */\r | |
485 | dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */\r | |
486 | dqd_wval = 0; /* clr data valid */\r | |
487 | setFSR (devd); /* set dch flg */\r | |
488 | clrCMD (devd); /* clr dch cmd */\r | |
489 | if (uptr->FNC == FNC_LA1) {\r | |
490 | setFSR (devc); /* set cch flg */\r | |
491 | clrCMD (devc); /* clr cch cmd */\r | |
492 | break; /* done if Load Address */\r | |
493 | }\r | |
494 | if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */\r | |
495 | st = abs (dqc_rarc - dqc_ucyl[drv]) * dqc_stime;\r | |
496 | if (st == 0) st = dqc_xtime; /* if on cyl, min time */\r | |
497 | else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */\r | |
498 | dqc_ucyl[drv] = dqc_rarc; /* transfer RAR */\r | |
499 | dqc_uhed[drv] = dqc_rarh;\r | |
500 | sim_activate (&dqc_unit[drv], st); /* schedule op */\r | |
501 | dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */\r | |
502 | }\r | |
503 | else sim_activate (uptr, dqc_xtime); /* no, wait more */\r | |
504 | break;\r | |
505 | \r | |
506 | case FNC_RCL: /* recalibrate */\r | |
507 | dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */\r | |
508 | if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */\r | |
509 | st = dqc_ucyl[drv] * dqc_stime; /* calc diff */\r | |
510 | if (st == 0) st = dqc_xtime; /* if on cyl, min time */\r | |
511 | else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */\r | |
512 | sim_activate (&dqc_unit[drv], st); /* schedule drive */\r | |
513 | dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */\r | |
514 | dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */\r | |
515 | break;\r | |
516 | \r | |
517 | case FNC_STA: /* read status */\r | |
518 | if (CMD (devd)) { /* dch active? */\r | |
519 | if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */\r | |
520 | dqd_ibuf = dqc_sta[drv] & ~STA_DID;\r | |
521 | else dqd_ibuf = STA_NRDY;\r | |
522 | if (dqd_ibuf & STA_ANYERR) /* errors? set flg */\r | |
523 | dqd_ibuf = dqd_ibuf | STA_ERR;\r | |
524 | if (drv) dqd_ibuf = dqd_ibuf | STA_DID;\r | |
525 | setFSR (devd); /* set dch flg */\r | |
526 | clrCMD (devd); /* clr dch cmd */\r | |
527 | clrCMD (devc); /* clr cch cmd */\r | |
528 | dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */\r | |
529 | }\r | |
530 | else sim_activate (uptr, dqc_xtime); /* wait more */\r | |
531 | break;\r | |
532 | \r | |
533 | case FNC_CHK: /* check, need cnt */\r | |
534 | if (CMD (devd)) { /* dch active? */\r | |
535 | dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */\r | |
536 | dqd_wval = 0; /* clr data valid */\r | |
537 | dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */\r | |
538 | }\r | |
539 | else sim_activate (uptr, dqc_xtime); /* wait more */\r | |
540 | break;\r | |
541 | \r | |
542 | default:\r | |
543 | return SCPE_IERR;\r | |
544 | }\r | |
545 | \r | |
546 | return SCPE_OK;\r | |
547 | }\r | |
548 | \r | |
549 | /* Drive unit service\r | |
550 | \r | |
551 | This routine handles the data transfers.\r | |
552 | \r | |
553 | Seek substates\r | |
554 | seek2 - done\r | |
555 | Recalibrate substate\r | |
556 | rcl1 - done\r | |
557 | Check data substates\r | |
558 | chk1 - finish operation\r | |
559 | Read\r | |
560 | Read address\r | |
561 | Address skip (read without header check)\r | |
562 | Write\r | |
563 | Write address\r | |
564 | */\r | |
565 | \r | |
566 | #define GETDA(x,y,z) \\r | |
567 | (((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD\r | |
568 | \r | |
569 | t_stat dqc_svc (UNIT *uptr)\r | |
570 | {\r | |
571 | int32 da, drv, devc, devd, err;\r | |
572 | \r | |
573 | err = 0; /* assume no err */\r | |
574 | drv = uptr - dqc_dev.units; /* get drive no */\r | |
575 | devc = dqc_dib.devno; /* get cch devno */\r | |
576 | devd = dqd_dib.devno; /* get dch devno */\r | |
577 | if (uptr->flags & UNIT_UNLOAD) { /* drive down? */\r | |
578 | setFSR (devc); /* set cch flg */\r | |
579 | clrCMD (devc); /* clr cch cmd */\r | |
580 | dqc_sta[drv] = 0; /* clr status */\r | |
581 | dqc_busy = 0; /* ctlr is free */\r | |
582 | dqd_xfer = dqd_wval = 0;\r | |
583 | return SCPE_OK;\r | |
584 | }\r | |
585 | switch (uptr->FNC) { /* case function */\r | |
586 | \r | |
587 | case FNC_SEEK2: /* seek done */\r | |
588 | if (dqc_ucyl[drv] >= DQ_NUMCY) { /* out of range? */\r | |
589 | dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; /* seek check */\r | |
590 | dqc_ucyl[drv] = 0; /* seek to cyl 0 */\r | |
591 | }\r | |
592 | else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */\r | |
593 | case FNC_SEEK3:\r | |
594 | if (dqc_busy || FLG (devc)) { /* ctrl busy? */\r | |
595 | uptr->FNC = FNC_SEEK3; /* next state */\r | |
596 | sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */\r | |
597 | }\r | |
598 | else {\r | |
599 | setFSR (devc); /* set cch flg */\r | |
600 | clrCMD (devc); /* clr cch cmd */\r | |
601 | }\r | |
602 | return SCPE_OK;\r | |
603 | \r | |
604 | case FNC_RA: /* read addr */\r | |
605 | if (!CMD (devd)) break; /* dch clr? done */\r | |
606 | if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */\r | |
607 | else if (dq_ptr == 1) { /* second word? */\r | |
608 | dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */\r | |
609 | (dqc_rars << DA_V_SC); /* and RAR sector */\r | |
610 | dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */\r | |
611 | }\r | |
612 | else break;\r | |
613 | dq_ptr = dq_ptr + 1;\r | |
614 | setFSR (devd); /* set dch flg */\r | |
615 | clrCMD (devd); /* clr dch cmd */\r | |
616 | sim_activate (uptr, dqc_xtime); /* sched next word */\r | |
617 | return SCPE_OK;\r | |
618 | \r | |
619 | case FNC_AS: /* address skip */\r | |
620 | case FNC_RD: /* read */\r | |
621 | case FNC_CHK1: /* check */\r | |
622 | if (dq_ptr == 0) { /* new sector? */\r | |
623 | if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;\r | |
624 | if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */\r | |
625 | (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */\r | |
626 | (dqc_rars >= DQ_NUMSC)) { /* bad sector? */\r | |
627 | dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */\r | |
628 | break;\r | |
629 | }\r | |
630 | if (dqc_rarh >= DQ_NUMSF) { /* bad head? */\r | |
631 | dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */\r | |
632 | break;\r | |
633 | }\r | |
634 | da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */\r | |
635 | dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */\r | |
636 | if (dqc_rars == 0) /* wrap? incr head */\r | |
637 | dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1;\r | |
638 | if (err = fseek (uptr->fileref, da * sizeof (int16),\r | |
639 | SEEK_SET)) break;\r | |
640 | fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);\r | |
641 | if (err = ferror (uptr->fileref)) break;\r | |
642 | }\r | |
643 | dqd_ibuf = dqxb[dq_ptr++]; /* get word */\r | |
644 | if (dq_ptr >= DQ_NUMWD) { /* end of sector? */\r | |
645 | if (uptr->FNC == FNC_CHK1) { /* check? */\r | |
646 | dqc_cnt = (dqc_cnt - 1) & DA_CKMASK; /* decr count */\r | |
647 | if (dqc_cnt == 0) break; /* if zero, done */\r | |
648 | }\r | |
649 | dq_ptr = 0; /* wrap buf ptr */\r | |
650 | }\r | |
651 | if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */\r | |
652 | setFSR (devd); /* set flag */\r | |
653 | }\r | |
654 | clrCMD (devd); /* clr dch cmd */\r | |
655 | sim_activate (uptr, dqc_xtime); /* sched next word */\r | |
656 | return SCPE_OK;\r | |
657 | \r | |
658 | case FNC_WA: /* write address */\r | |
659 | case FNC_WD: /* write */\r | |
660 | if (dq_ptr == 0) { /* sector start? */\r | |
661 | if (!CMD (devd) && !dqd_wval) break; /* xfer done? */\r | |
662 | if (uptr->flags & UNIT_WPRT) { /* write protect? */\r | |
663 | dqc_sta[drv] = dqc_sta[drv] | STA_FLG;\r | |
664 | break; /* done */\r | |
665 | }\r | |
666 | if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */\r | |
667 | (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */\r | |
668 | (dqc_rars >= DQ_NUMSC)) { /* bad sector? */\r | |
669 | dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */\r | |
670 | break;\r | |
671 | }\r | |
672 | if (dqc_rarh >= DQ_NUMSF) { /* bad head? */\r | |
673 | dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */\r | |
674 | break;\r | |
675 | }\r | |
676 | }\r | |
677 | dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */\r | |
678 | dqd_wval = 0; /* clr data valid */\r | |
679 | if (dq_ptr >= DQ_NUMWD) { /* buffer full? */\r | |
680 | da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */\r | |
681 | dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */\r | |
682 | if (dqc_rars == 0) /* wrap? incr head */\r | |
683 | dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1;\r | |
684 | if (err = fseek (uptr->fileref, da * sizeof (int16),\r | |
685 | SEEK_SET)) return TRUE;\r | |
686 | fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);\r | |
687 | if (err = ferror (uptr->fileref)) break;\r | |
688 | dq_ptr = 0;\r | |
689 | }\r | |
690 | if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */\r | |
691 | setFSR (devd); /* set flag */\r | |
692 | }\r | |
693 | clrCMD (devd); /* clr dch cmd */\r | |
694 | sim_activate (uptr, dqc_xtime); /* sched next word */\r | |
695 | return SCPE_OK;\r | |
696 | \r | |
697 | default:\r | |
698 | return SCPE_IERR;\r | |
699 | } /* end case fnc */\r | |
700 | \r | |
701 | setFSR (devc); /* set cch flg */\r | |
702 | clrCMD (devc); /* clr cch cmd */\r | |
703 | dqc_busy = 0; /* ctlr is free */\r | |
704 | dqd_xfer = dqd_wval = 0;\r | |
705 | if (err != 0) { /* error? */\r | |
706 | perror ("DQ I/O error");\r | |
707 | clearerr (uptr->fileref);\r | |
708 | return SCPE_IOERR;\r | |
709 | }\r | |
710 | return SCPE_OK;\r | |
711 | }\r | |
712 | \r | |
713 | /* Reset routine */\r | |
714 | \r | |
715 | t_stat dqc_reset (DEVICE *dptr)\r | |
716 | {\r | |
717 | int32 drv;\r | |
718 | \r | |
719 | hp_enbdis_pair (dptr, /* make pair cons */\r | |
720 | (dptr == &dqd_dev)? &dqc_dev: &dqd_dev);\r | |
721 | dqd_ibuf = dqd_obuf = 0; /* clear buffers */\r | |
722 | dqc_busy = dqc_obuf = 0;\r | |
723 | dqd_xfer = dqd_wval = 0;\r | |
724 | dq_ptr = 0;\r | |
725 | dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */\r | |
726 | dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */\r | |
727 | dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */\r | |
728 | dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */\r | |
729 | dqc_dib.flg = dqd_dib.flg = 1; /* set flg */\r | |
730 | dqc_dib.srq = dqd_dib.srq = 1; /* srq follows flg */\r | |
731 | sim_cancel (&dqd_unit); /* cancel dch */\r | |
732 | for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */\r | |
733 | sim_cancel (&dqc_unit[drv]); /* cancel activity */\r | |
734 | dqc_unit[drv].FNC = 0; /* clear function */\r | |
735 | dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */\r | |
736 | dqc_sta[drv] = 0; /* clear status */\r | |
737 | }\r | |
738 | return SCPE_OK;\r | |
739 | }\r | |
740 | \r | |
741 | /* Attach routine */\r | |
742 | \r | |
743 | t_stat dqc_attach (UNIT *uptr, char *cptr)\r | |
744 | {\r | |
745 | t_stat r;\r | |
746 | \r | |
747 | r = attach_unit (uptr, cptr); /* attach unit */\r | |
748 | if (r == SCPE_OK) dqc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */\r | |
749 | return r;\r | |
750 | }\r | |
751 | \r | |
752 | /* Detach routine */\r | |
753 | \r | |
754 | t_stat dqc_detach (UNIT* uptr)\r | |
755 | {\r | |
756 | dqc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */\r | |
757 | return detach_unit (uptr); /* detach unit */\r | |
758 | }\r | |
759 | \r | |
760 | /* Load and unload heads */\r | |
761 | \r | |
762 | t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc)\r | |
763 | {\r | |
764 | if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */\r | |
765 | if (value == UNIT_UNLOAD) /* unload heads? */\r | |
766 | uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */\r | |
767 | else uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */\r | |
768 | return SCPE_OK;\r | |
769 | }\r | |
770 | \r | |
771 | /* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */\r | |
772 | \r | |
773 | const uint16 dq_rom[IBL_LNT] = {\r | |
774 | 0102501, /*ST LIA 1 ; get switches */\r | |
775 | 0106501, /* LIB 1 */\r | |
776 | 0013765, /* AND D7 ; isolate hd */\r | |
777 | 0005750, /* BLF,CLE,SLB */\r | |
778 | 0027741, /* JMP RD */\r | |
779 | 0005335, /* RBR,SLB,ERB ; <13>->E, set = 2883 */\r | |
780 | 0027717, /* JMP IS */\r | |
781 | 0102611, /*LP OTA CC ; do 7900 status to */\r | |
782 | 0103711, /* STC CC,C ; clear first seek */\r | |
783 | 0102310, /* SFS DC */\r | |
784 | 0027711, /* JMP *-1 */\r | |
785 | 0002004, /* INA ; get next drive */\r | |
786 | 0053765, /* CPA D7 ; all cleared? */\r | |
787 | 0002001, /* RSS */\r | |
788 | 0027707, /* JMP LP */\r | |
789 | 0067761, /*IS LDB SEEKC ; get seek comnd */\r | |
790 | 0106610, /* OTB DC ; issue cyl addr (0) */\r | |
791 | 0103710, /* STC DC,C ; to dch */\r | |
792 | 0106611, /* OTB CC ; seek cmd */\r | |
793 | 0103711, /* STC CC,C ; to cch */\r | |
794 | 0102310, /* SFS DC ; addr wd ok? */\r | |
795 | 0027724, /* JMP *-1 ; no, wait */\r | |
796 | 0006400, /* CLB */\r | |
797 | 0102501, /* LIA 1 ; get switches */\r | |
798 | 0002051, /* SEZ,SLA,RSS ; subchan = 1 or ISS */\r | |
799 | 0047770, /* ADB BIT9 ; head 2 */\r | |
800 | 0106610, /* OTB DC ; head/sector */\r | |
801 | 0103710, /* STC DC,C ; to dch */\r | |
802 | 0102311, /* SFS CC ; seek done? */\r | |
803 | 0027734, /* JMP *-1 ; no, wait */\r | |
804 | 0063731, /* LDA ISSRD ; get read read */\r | |
805 | 0002341, /* SEZ,CCE,RSS ; iss disc? */\r | |
806 | 0001100, /* ARS ; no, make 7900 read */\r | |
807 | 0067776, /*RD LDB DMACW ; DMA control */\r | |
808 | 0106606, /* OTB 6 */\r | |
809 | 0067762, /* LDB ADDR1 ; memory addr */\r | |
810 | 0077741, /* STB RD ; make non re-executable */\r | |
811 | 0106602, /* OTB 2 */\r | |
812 | 0102702, /* STC 2 ; flip DMA ctrl */\r | |
813 | 0067764, /* LDB COUNT ; word count */\r | |
814 | 0106602, /* OTB 2 */\r | |
815 | 0002041, /* SEZ,RSS */\r | |
816 | 0027766, /* JMP NW */\r | |
817 | 0102611, /* OTA CC ; to cch */\r | |
818 | 0103710, /* STC DC,C ; start dch */\r | |
819 | 0103706, /* STC 6,C ; start DMA */\r | |
820 | 0103711, /* STC CC,C ; start cch */\r | |
821 | 0037773, /* ISZ SK */\r | |
822 | 0027773, /* JMP SK */\r | |
823 | 0030000, /*SEEKC 030000 */\r | |
824 | 0102011, /*ADDR1 102011 */\r | |
825 | 0102055, /*ADDR2 102055 */\r | |
826 | 0164000, /*COUNT -6144. */\r | |
827 | 0000007, /*D7 7 */\r | |
828 | 0106710, /*NW CLC DC ; set 'next wd is cmd' flag */\r | |
829 | 0001720, /* ALF,ALF ; move to head number loc */\r | |
830 | 0001000, /*BIT9 ALS */\r | |
831 | 0103610, /* OTA DC,C ; output cold load cmd */\r | |
832 | 0103706, /* STC 6,C ; start DMA */\r | |
833 | 0102310, /* SFS DC ; done? */\r | |
834 | 0027773, /* JMP *-1 ; no, wait */\r | |
835 | 0117763, /*XT JSB ADDR2,I ; start program */\r | |
836 | 0120010, /*DMACW 120000+DC */\r | |
837 | 0000000 /* -ST */\r | |
838 | };\r | |
839 | \r | |
840 | t_stat dqc_boot (int32 unitno, DEVICE *dptr)\r | |
841 | {\r | |
842 | int32 dev;\r | |
843 | \r | |
844 | if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */\r | |
845 | dev = dqd_dib.devno; /* get data chan dev */\r | |
846 | if (ibl_copy (dq_rom, dev)) return SCPE_IERR; /* copy boot to memory */\r | |
847 | SR = (SR & IBL_OPT) | IBL_DQ | (dev << IBL_V_DEV); /* set SR */\r | |
848 | return SCPE_OK;\r | |
849 | }\r |