Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp11_hk.c - RK611/RK06/RK07 disk controller\r |
2 | \r | |
3 | Copyright (c) 1993-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 PUHKOSE 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 | hk RK611/RK06/RK07 disk\r | |
27 | \r | |
28 | 29-Apr-07 RMS NOP and DCLR (at least) do not check drive type\r | |
29 | MR2 and MR3 only updated on NOP\r | |
30 | 17-Nov-05 RMS Removed unused variable\r | |
31 | 13-Nov-05 RMS Fixed overlapped seek interaction with NOP, DCLR, PACK\r | |
32 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r | |
33 | 07-Jul-05 RMS Removed extraneous externs\r | |
34 | 18-Mar-05 RMS Added attached test to detach routine\r | |
35 | 03-Oct-04 RMS Revised Unibus interface\r | |
36 | RMS Fixed state of output ready for M+\r | |
37 | 26-Mar-04 RMS Fixed warnings with -std=c99\r | |
38 | 25-Jan-04 RMS Revised for device debug support\r | |
39 | 04-Jan-04 RMS Changed sim_fsize calling sequence\r | |
40 | 29-Dec-03 RMS Added 18b Qbus support\r | |
41 | 25-Apr-03 RMS Revised for extended file support\r | |
42 | \r | |
43 | This is a somewhat abstracted implementation of the RK611, more closely\r | |
44 | modelled on third party clones than DEC's own implementation. In particular,\r | |
45 | the drive-to-controller serial communications system is simulated only at\r | |
46 | a level equal to the Emulex SC21.\r | |
47 | \r | |
48 | The RK611 functions only in 18b Unibus systems with I/O maps. The Emulex\r | |
49 | SC02/C was a Qbus work-alike with a unique extension to 22b addressing. It\r | |
50 | was only supported in Ultrix-11 and other third party software.\r | |
51 | \r | |
52 | This module includes ideas from a previous implementation by Fred Van Kempen.\r | |
53 | */\r | |
54 | \r | |
55 | #if defined (VM_PDP10) /* PDP10 version */\r | |
56 | #error "RK611 is not supported on the PDP-10!"\r | |
57 | \r | |
58 | #elif defined (VM_VAX) /* VAX version */\r | |
59 | #include "vax_defs.h"\r | |
60 | \r | |
61 | #else /* PDP-11 version */\r | |
62 | #include "pdp11_defs.h"\r | |
63 | extern int32 cpu_opt;\r | |
64 | #endif\r | |
65 | \r | |
66 | extern uint16 *M;\r | |
67 | \r | |
68 | #define HK_NUMDR 8 /* #drives */\r | |
69 | #define HK_NUMCY6 411 /* cyl/drive */\r | |
70 | #define HK_NUMCY7 815 /* cyl/drive */\r | |
71 | #define HK_NUMSF 3 /* tracks/cyl */\r | |
72 | #define HK_NUMSC 22 /* sectors/track */\r | |
73 | #define HK_NUMWD 256 /* words/sector */\r | |
74 | #define RK06_SIZE (HK_NUMCY6*HK_NUMSF*HK_NUMSC*HK_NUMWD)\r | |
75 | #define RK07_SIZE (HK_NUMCY7*HK_NUMSF*HK_NUMSC*HK_NUMWD)\r | |
76 | #define HK_SIZE(x) (((x)->flags & UNIT_DTYPE)? RK07_SIZE: RK06_SIZE)\r | |
77 | #define HK_CYL(x) (((x)->flags & UNIT_DTYPE)? HK_NUMCY7: HK_NUMCY6)\r | |
78 | #define HK_MAXFR (1 << 16)\r | |
79 | \r | |
80 | /* Flags in the unit flags word */\r | |
81 | \r | |
82 | #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */\r | |
83 | #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */\r | |
84 | #define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */\r | |
85 | #define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */\r | |
86 | #define UNIT_WLK (1 << UNIT_V_WLK)\r | |
87 | #define UNIT_DTYPE (1 << UNIT_V_DTYPE)\r | |
88 | #define UNIT_RK06 (0 << UNIT_V_DTYPE)\r | |
89 | #define UNIT_RK07 (1 << UNIT_V_DTYPE)\r | |
90 | #define UNIT_AUTO (1 << UNIT_V_AUTO)\r | |
91 | #define UNIT_DUMMY (1 << UNIT_V_DUMMY)\r | |
92 | #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */\r | |
93 | \r | |
94 | /* Parameters in the unit descriptor */\r | |
95 | \r | |
96 | #define CYL u3 /* current cylinder */\r | |
97 | #define FNC u4 /* function */\r | |
98 | \r | |
99 | /* HKCS1 - 177440 - control/status 1 */\r | |
100 | \r | |
101 | #define CS1_GO CSR_GO /* go */\r | |
102 | #define CS1_V_FNC 1 /* function pos */\r | |
103 | #define CS1_M_FNC 017 /* function mask */\r | |
104 | #define CS1_FNC (CS1_M_FNC << CS1_V_FNC)\r | |
105 | #define FNC_NOP 000 /* no operation */\r | |
106 | #define FNC_PACK 001 /* pack acknowledge */\r | |
107 | #define FNC_DCLR 002 /* drive clear */\r | |
108 | #define FNC_UNLOAD 003 /* unload */\r | |
109 | #define FNC_START 004 /* start */\r | |
110 | #define FNC_RECAL 005 /* recalibrate */\r | |
111 | #define FNC_OFFSET 006 /* offset */\r | |
112 | #define FNC_SEEK 007 /* seek */\r | |
113 | #define FNC_XFER 010\r | |
114 | #define FNC_READ 010 /* read */\r | |
115 | #define FNC_WRITE 011 /* write */\r | |
116 | #define FNC_WRITEH 013 /* write w/ headers */\r | |
117 | #define FNC_READH 012 /* read w/ headers */\r | |
118 | #define FNC_WCHK 014 /* write check */\r | |
119 | #define FNC_2ND 020 /* 2nd state flag */\r | |
120 | #define CS1_SPA 0000040 /* spare */\r | |
121 | #define CS1_IE CSR_IE /* int enable */\r | |
122 | #define CS1_DONE CSR_DONE /* ready */\r | |
123 | #define CS1_V_UAE 8 /* Unibus addr ext */\r | |
124 | #define CS1_M_UAE 03\r | |
125 | #define CS1_UAE (CS1_M_UAE << CS1_V_UAE)\r | |
126 | #define CS1_DT 0002000 /* drive type */\r | |
127 | #define CS1_CTO 0004000 /* ctrl timeout NI */\r | |
128 | #define CS1_FMT 0010000 /* 16b/18b NI */\r | |
129 | #define CS1_PAR 0020000 /* par err NI */\r | |
130 | #define CS1_DI 0040000 /* drive intr */\r | |
131 | #define CS1_ERR 0100000 /* error */\r | |
132 | #define CS1_CCLR 0100000 /* ctrl clear */\r | |
133 | #define CS1_RW (CS1_DT|CS1_UAE|CS1_IE|CS1_SPA|CS1_FNC)\r | |
134 | #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)\r | |
135 | #define GET_UAE(x) (((x) >> CS1_V_UAE) & CS1_M_UAE)\r | |
136 | #define PUT_UAE(x,n) (((x) & ~ CS1_UAE) | (((n) << CS1_V_UAE) & CS1_UAE))\r | |
137 | \r | |
138 | /* HKWC - 177442 - word count */\r | |
139 | \r | |
140 | /* HKBA - 177444 - base address */\r | |
141 | \r | |
142 | #define BA_MBZ 0000001 /* must be zero */\r | |
143 | \r | |
144 | /* HKDA - 177446 - sector/track */\r | |
145 | \r | |
146 | #define DA_V_SC 0 /* sector pos */\r | |
147 | #define DA_M_SC 037 /* sector mask */\r | |
148 | #define DA_V_SF 8 /* track pos */\r | |
149 | #define DA_M_SF 007 /* track mask */\r | |
150 | #define DA_MBZ 0174340\r | |
151 | #define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC)\r | |
152 | #define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF)\r | |
153 | \r | |
154 | /* HKCS2 - 177450 - control/status 2 */\r | |
155 | \r | |
156 | #define CS2_V_UNIT 0 /* unit pos */\r | |
157 | #define CS2_M_UNIT 07 /* unit mask */\r | |
158 | #define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT)\r | |
159 | #define CS2_RLS 0000010 /* release NI */\r | |
160 | #define CS2_UAI 0000020 /* addr inhibit */\r | |
161 | #define CS2_CLR 0000040 /* controller clear */\r | |
162 | #define CS2_IR 0000100 /* input ready */\r | |
163 | #define CS2_OR 0000200 /* output ready */\r | |
164 | #define CS2_UFE 0000400 /* unit field err NI */\r | |
165 | #define CS2_MDS 0001000 /* multidrive sel NI */\r | |
166 | #define CS2_PGE 0002000 /* program err */\r | |
167 | #define CS2_NEM 0004000 /* nx mem err */\r | |
168 | #define CS2_NED 0010000 /* nx drive err */\r | |
169 | #define CS2_PE 0020000 /* parity err NI */\r | |
170 | #define CS2_WCE 0040000 /* write check err */\r | |
171 | #define CS2_DLT 0100000 /* data late NI */\r | |
172 | #define CS2_MBZ (CS2_CLR)\r | |
173 | #define CS2_RW 0000037\r | |
174 | #define CS2_ERR (CS2_UFE | CS2_MDS | CS2_PGE | CS2_NEM | \\r | |
175 | CS2_NED | CS2_PE | CS2_WCE | CS2_DLT )\r | |
176 | #define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT)\r | |
177 | \r | |
178 | /* HKDS - 177452 - drive status ^ = calculated dynamically */\r | |
179 | \r | |
180 | #define DS_DRA 0000001 /* ^drive avail */\r | |
181 | #define DS_OF 0000004 /* ^offset mode */\r | |
182 | #define DS_ACLO 0000010 /* ^AC LO NI */\r | |
183 | #define DS_SPLS 0000020 /* ^speed loss NI */\r | |
184 | #define DS_DOT 0000040 /* ^off track NI */\r | |
185 | #define DS_VV 0000100 /* volume valid */\r | |
186 | #define DS_RDY 0000200 /* ^drive ready */\r | |
187 | #define DS_DT 0000400 /* ^drive type */\r | |
188 | #define DS_WRL 0004000 /* ^write locked */\r | |
189 | #define DS_PIP 0020000 /* pos in progress */\r | |
190 | #define DS_ATA 0040000 /* attention active */\r | |
191 | #define DS_VLD 0100000 /* ^status valid */\r | |
192 | #define DS_MBZ 0013002\r | |
193 | \r | |
194 | /* HKER - 177454 - error status */\r | |
195 | \r | |
196 | #define ER_ILF 0000001 /* illegal func */\r | |
197 | #define ER_SKI 0000002 /* seek incomp */\r | |
198 | #define ER_NXF 0000004 /* non-exec func */\r | |
199 | #define ER_PAR 0000010 /* parity err */\r | |
200 | #define ER_FER 0000020 /* format err NI */\r | |
201 | #define ER_DTY 0000040 /* drive type err */\r | |
202 | #define ER_ECH 0000100 /* ECC hard err NI */\r | |
203 | #define ER_BSE 0000200 /* bad sector err NI */\r | |
204 | #define ER_HCR 0000400 /* hdr CRC err NI */\r | |
205 | #define ER_AOE 0001000 /* addr ovflo err */\r | |
206 | #define ER_IAE 0002000 /* invalid addr err */\r | |
207 | #define ER_WLE 0004000 /* write lock err */\r | |
208 | #define ER_DTE 0010000 /* drive time err NI */\r | |
209 | #define ER_OPI 0020000 /* op incomplete */\r | |
210 | #define ER_UNS 0040000 /* drive unsafe */\r | |
211 | #define ER_DCK 0100000 /* data check NI */\r | |
212 | \r | |
213 | /* HKAS - 177456 - attention summary/offset */\r | |
214 | \r | |
215 | #define AS_U0 0000400 /* unit 0 flag */\r | |
216 | #define AS_OF 0000277 /* offset mask */\r | |
217 | \r | |
218 | /* HKDC - 177460 - desired cylinder */\r | |
219 | \r | |
220 | #define DC_V_CY 0 /* cylinder pos */\r | |
221 | #define DC_M_CY 0001777 /* cylinder mask */\r | |
222 | #define DC_MBZ 0176000\r | |
223 | #define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY)\r | |
224 | #define GET_DA(c,fs) ((((GET_CY (c) * HK_NUMSF) + \\r | |
225 | GET_SF (fs)) * HK_NUMSC) + GET_SC (fs))\r | |
226 | \r | |
227 | /* Spare - 177462 - read/write */\r | |
228 | \r | |
229 | #define XM_KMASK 0177700 /* Qbus XM key mask */\r | |
230 | #define XM_KEY 0022000 /* Qbus XM "key" */\r | |
231 | #define XM_MMASK 0000077 /* Qbus XM mask */\r | |
232 | #define SC02C (!UNIBUS && ((hkspr & XM_KMASK) == XM_KEY))\r | |
233 | \r | |
234 | /* HKDB - 177464 - read/write */\r | |
235 | \r | |
236 | /* HKMR - 177466 - maintenance register 1 */\r | |
237 | \r | |
238 | #define MR_V_MS 0 /* message select */\r | |
239 | #define MR_M_MS 03\r | |
240 | #define MR_MS (MR_M_MS << MR_V_MS)\r | |
241 | #define GET_MS(x) (((x) >> MR_V_MS) & MR_M_MS)\r | |
242 | #define MR_PAR 0000020 /* force even parity */\r | |
243 | #define MR_DMD 0000040 /* diagnostic mode */\r | |
244 | #define MR_RW 0001777\r | |
245 | \r | |
246 | /* HKEC1 - 177470 - ECC status 1 - always reads as 0 */\r | |
247 | /* HKEC2 - 177472 - ECC status 2 - always reads as 0 */\r | |
248 | \r | |
249 | /* HKMR2 - 177474 - maintenance register 2 */\r | |
250 | \r | |
251 | #define AX_V_UNIT 0 /* unit #, all msgs */\r | |
252 | #define AX_PAR 0100000 /* parity, all msgs */\r | |
253 | \r | |
254 | #define A0_DRA 0000040 /* drive avail */\r | |
255 | #define A0_VV 0000100 /* vol valid */\r | |
256 | #define A0_RDY 0000200 /* drive ready */\r | |
257 | #define A0_DT 0000400 /* drive type */\r | |
258 | #define A0_FMT 0001000 /* format NI */ \r | |
259 | #define A0_OF 0002000 /* offset mode */\r | |
260 | #define A0_WRL 0004000 /* write lock */\r | |
261 | #define A0_SPO 0010000 /* spindle on */\r | |
262 | #define A0_PIP 0020000 /* pos in prog */\r | |
263 | #define A0_ATA 0040000 /* attention */\r | |
264 | \r | |
265 | #define A1_SRV 0000020 /* servo */\r | |
266 | #define A1_HHM 0000040 /* heads home */\r | |
267 | #define A1_BHM 0000100 /* brushes home */\r | |
268 | #define A1_DOR 0000200 /* door latched */\r | |
269 | #define A1_CAR 0000400 /* cartridge present */\r | |
270 | #define A1_SPD 0001000 /* speed ok */\r | |
271 | #define A1_FWD 0002000 /* seek fwd */\r | |
272 | #define A1_REV 0004000 /* seek rev */\r | |
273 | #define A1_LDH 0010000 /* loading heads NI */\r | |
274 | #define A1_RTZ 0020000 /* return to zero */\r | |
275 | #define A1_UNL 0040000 /* unloading heads */\r | |
276 | \r | |
277 | #define A2_V_DIF 4 /* cyl diff */\r | |
278 | #define A2_M_DIF 0777\r | |
279 | \r | |
280 | #define A3_V_SNO 3 /* serial # */\r | |
281 | \r | |
282 | /* HKMR3 - 177476 - maintenance register 3 */\r | |
283 | \r | |
284 | #define B0_IAE 0000040 /* invalid addr */\r | |
285 | #define B0_ACLO 0000100 /* AC LO NI */\r | |
286 | #define B0_FLT 0000200 /* fault */\r | |
287 | #define B0_NXF 0000400 /* non exec fnc */\r | |
288 | #define B0_CDP 0001000 /* msg parity err */\r | |
289 | #define B0_SKI 0002000 /* seek incomp */\r | |
290 | #define B0_WLE 0004000 /* write lock err */\r | |
291 | #define B0_SLO 0010000 /* speed low NI */\r | |
292 | #define B0_OFT 0020000 /* off track NI */\r | |
293 | #define B0_UNS 0040000 /* rw unsafe NI */\r | |
294 | \r | |
295 | #define B1_SCE 0000020 /* sector err NI */\r | |
296 | #define B1_NWC 0000040 /* no write curr NI */\r | |
297 | #define B1_NWT 0000100 /* no write trans NI */\r | |
298 | #define B1_HFL 0000200 /* head fault NI */\r | |
299 | #define B1_MHS 0000400 /* multiselect NI */\r | |
300 | #define B1_IDX 0001000 /* index err NI */\r | |
301 | #define B1_TRI 0002000 /* tribit err NI */\r | |
302 | #define B1_SVE 0004000 /* servo err NI */\r | |
303 | #define B1_SKI 0010000 /* seek no mot */\r | |
304 | #define B1_LIM 0020000 /* seek limit NI */\r | |
305 | #define B1_SVU 0040000 /* servo unsafe NI */\r | |
306 | \r | |
307 | #define B2_V_CYL 4 /* cylinder */\r | |
308 | \r | |
309 | #define B3_V_SEC 4 /* sector */\r | |
310 | #define B3_V_DHA 9 /* decoded head */\r | |
311 | \r | |
312 | /* Read header */\r | |
313 | \r | |
314 | #define RDH1_V_CYL 0 /* cylinder */\r | |
315 | #define RDH2_V_SEC 0 /* sector */\r | |
316 | #define RDH2_V_DHA 5 /* decoded head */\r | |
317 | #define RDH2_GOOD 0140000 /* good sector flags */\r | |
318 | \r | |
319 | /* Debug detail levels */\r | |
320 | \r | |
321 | #define HKDEB_OPS 001 /* transactions */\r | |
322 | #define HKDEB_RRD 002 /* reg reads */\r | |
323 | #define HKDEB_RWR 004 /* reg writes */\r | |
324 | \r | |
325 | extern int32 int_req[IPL_HLVL];\r | |
326 | extern FILE *sim_deb;\r | |
327 | \r | |
328 | uint16 *hkxb = NULL; /* xfer buffer */\r | |
329 | int32 hkcs1 = 0; /* control/status 1 */\r | |
330 | int32 hkwc = 0; /* word count */\r | |
331 | int32 hkba = 0; /* bus address */\r | |
332 | int32 hkda = 0; /* track/sector */\r | |
333 | int32 hkcs2 = 0; /* control/status 2 */\r | |
334 | int32 hkds[HK_NUMDR] = { 0 }; /* drive status */\r | |
335 | int32 hker[HK_NUMDR] = { 0 }; /* error status */\r | |
336 | int32 hkof = 0; /* offset */\r | |
337 | int32 hkmr = 0; /* maint registers */\r | |
338 | int32 hkmr2 = 0;\r | |
339 | int32 hkmr3 = 0;\r | |
340 | int32 hkdc = 0; /* cylinder */\r | |
341 | int32 hkspr = 0; /* spare */\r | |
342 | int32 hk_cwait = 5; /* command time */\r | |
343 | int32 hk_swait = 10; /* seek time */\r | |
344 | int32 hk_rwait = 10; /* rotate time */\r | |
345 | int32 hk_min2wait = 300; /* min time to 2nd int */\r | |
346 | int16 hkdb[3] = { 0 }; /* data buffer silo */\r | |
347 | int16 hk_off[HK_NUMDR] = { 0 }; /* saved offset */\r | |
348 | int16 hk_dif[HK_NUMDR] = { 0 }; /* cylinder diff */\r | |
349 | static uint8 reg_in_drive[16] = {\r | |
350 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r | |
351 | \r | |
352 | DEVICE hk_dev;\r | |
353 | t_stat hk_rd (int32 *data, int32 PA, int32 access);\r | |
354 | t_stat hk_wr (int32 data, int32 PA, int32 access);\r | |
355 | t_stat hk_svc (UNIT *uptr);\r | |
356 | t_stat hk_reset (DEVICE *dptr);\r | |
357 | t_stat hk_boot (int32 unitno, DEVICE *dptr);\r | |
358 | t_stat hk_attach (UNIT *uptr, char *cptr);\r | |
359 | t_stat hk_detach (UNIT *uptr);\r | |
360 | int32 hk_rdmr2 (int32 msg);\r | |
361 | int32 hk_rdmr3 (int32 msg);\r | |
362 | void update_hkcs (int32 flags, int32 drv);\r | |
363 | void update_hkds (int32 drv);\r | |
364 | void hk_cmderr (int32 err, int32 drv);\r | |
365 | void hk_go (int32 drv);\r | |
366 | t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
367 | t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
368 | \r | |
369 | extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);\r | |
370 | \r | |
371 | /* HK data structures\r | |
372 | \r | |
373 | hk_dev HK device descriptor\r | |
374 | hk_unit HK unit list\r | |
375 | hk_reg HK register list\r | |
376 | hk_mod HK modifier list\r | |
377 | */\r | |
378 | \r | |
379 | DIB hk_dib = {\r | |
380 | IOBA_HK, IOLN_HK, &hk_rd, &hk_wr,\r | |
381 | 1, IVCL (HK), VEC_HK, { NULL }\r | |
382 | };\r | |
383 | \r | |
384 | UNIT hk_unit[] = {\r | |
385 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
386 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
387 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
388 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
389 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
390 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
391 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
392 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
393 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
394 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
395 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
396 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
397 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
398 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) },\r | |
399 | { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r | |
400 | UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }\r | |
401 | };\r | |
402 | \r | |
403 | REG hk_reg[] = {\r | |
404 | { GRDATA (HKCS1, hkcs1, DEV_RDX, 16, 0) },\r | |
405 | { GRDATA (HKWC, hkwc, DEV_RDX, 16, 0) },\r | |
406 | { GRDATA (HKBA, hkba, DEV_RDX, 16, 0) },\r | |
407 | { GRDATA (HKDA, hkda, DEV_RDX, 16, 0) },\r | |
408 | { GRDATA (HKCS2, hkcs2, DEV_RDX, 16, 0) },\r | |
409 | { BRDATA (HKDS, hkds, DEV_RDX, 16, HK_NUMDR) },\r | |
410 | { BRDATA (HKER, hker, DEV_RDX, 16, HK_NUMDR) },\r | |
411 | { BRDATA (HKDB, hkdb, DEV_RDX, 16, 3) },\r | |
412 | { GRDATA (HKDC, hkdc, DEV_RDX, 16, 0) },\r | |
413 | { GRDATA (HKOF, hkof, DEV_RDX, 8, 0) },\r | |
414 | { GRDATA (HKMR, hkmr, DEV_RDX, 16, 0) },\r | |
415 | { GRDATA (HKMR2, hkmr2, DEV_RDX, 16, 0), REG_RO },\r | |
416 | { GRDATA (HKMR3, hkmr3, DEV_RDX, 16, 0), REG_RO },\r | |
417 | { GRDATA (HKSPR, hkspr, DEV_RDX, 16, 0) },\r | |
418 | { FLDATA (INT, IREQ (HK), INT_V_HK) },\r | |
419 | { FLDATA (ERR, hkcs1, CSR_V_ERR) },\r | |
420 | { FLDATA (DONE, hkcs1, CSR_V_DONE) },\r | |
421 | { FLDATA (IE, hkcs1, CSR_V_IE) },\r | |
422 | { DRDATA (CTIME, hk_cwait, 24), REG_NZ + PV_LEFT },\r | |
423 | { DRDATA (STIME, hk_swait, 24), REG_NZ + PV_LEFT },\r | |
424 | { DRDATA (RTIME, hk_rwait, 24), REG_NZ + PV_LEFT },\r | |
425 | { DRDATA (MIN2TIME, hk_min2wait, 24), REG_NZ + PV_LEFT + REG_HRO },\r | |
426 | { URDATA (FNC, hk_unit[0].FNC, DEV_RDX, 5, 0,\r | |
427 | HK_NUMDR, REG_HRO) },\r | |
428 | { URDATA (CYL, hk_unit[0].CYL, DEV_RDX, 10, 0,\r | |
429 | HK_NUMDR, REG_HRO) },\r | |
430 | { BRDATA (OFFSET, hk_off, DEV_RDX, 16, HK_NUMDR), REG_HRO },\r | |
431 | { BRDATA (CYLDIF, hk_dif, DEV_RDX, 16, HK_NUMDR), REG_HRO },\r | |
432 | { URDATA (CAPAC, hk_unit[0].capac, 10, T_ADDR_W, 0,\r | |
433 | HK_NUMDR, PV_LEFT | REG_HRO) },\r | |
434 | { GRDATA (DEVADDR, hk_dib.ba, DEV_RDX, 32, 0), REG_HRO },\r | |
435 | { GRDATA (DEVVEC, hk_dib.vec, DEV_RDX, 16, 0), REG_HRO },\r | |
436 | { NULL }\r | |
437 | };\r | |
438 | \r | |
439 | MTAB hk_mod[] = {\r | |
440 | { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
441 | { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r | |
442 | { UNIT_DUMMY, 0, NULL, "BADBLOCK", &hk_set_bad },\r | |
443 | { (UNIT_DTYPE+UNIT_ATT), UNIT_RK06 + UNIT_ATT,\r | |
444 | "RK06", NULL, NULL },\r | |
445 | { (UNIT_DTYPE+UNIT_ATT), UNIT_RK07 + UNIT_ATT,\r | |
446 | "RK07", NULL, NULL },\r | |
447 | { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK06,\r | |
448 | "RK06", NULL, NULL },\r | |
449 | { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK07,\r | |
450 | "RK07", NULL, NULL },\r | |
451 | { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },\r | |
452 | { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },\r | |
453 | { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK06,\r | |
454 | NULL, "RK06", &hk_set_size },\r | |
455 | { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK07,\r | |
456 | NULL, "RK07", &hk_set_size }, \r | |
457 | { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS",\r | |
458 | &set_addr, &show_addr, NULL },\r | |
459 | { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r | |
460 | &set_vec, &show_vec, NULL },\r | |
461 | { 0 }\r | |
462 | };\r | |
463 | \r | |
464 | DEBTAB hk_deb[] = {\r | |
465 | { "OPS", HKDEB_OPS },\r | |
466 | { "RRD", HKDEB_RRD },\r | |
467 | { "RWR", HKDEB_RWR },\r | |
468 | { NULL, 0 }\r | |
469 | };\r | |
470 | \r | |
471 | DEVICE hk_dev = {\r | |
472 | "HK", hk_unit, hk_reg, hk_mod,\r | |
473 | HK_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16,\r | |
474 | NULL, NULL, &hk_reset,\r | |
475 | &hk_boot, &hk_attach, &hk_detach,\r | |
476 | &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG, 0,\r | |
477 | hk_deb, NULL, 0\r | |
478 | };\r | |
479 | \r | |
480 | /* I/O dispatch routines, I/O addresses 17777440 - 17777476 */\r | |
481 | \r | |
482 | t_stat hk_rd (int32 *data, int32 PA, int32 access)\r | |
483 | {\r | |
484 | int32 drv, i, j;\r | |
485 | \r | |
486 | drv = GET_UNIT (hkcs2); /* get current unit */\r | |
487 | j = (PA >> 1) & 017; /* get reg offset */\r | |
488 | if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */\r | |
489 | hkcs2 = hkcs2 | CS2_NED; /* set error flag */\r | |
490 | update_hkcs (0, drv);\r | |
491 | *data = 0;\r | |
492 | return SCPE_OK;\r | |
493 | }\r | |
494 | \r | |
495 | update_hkcs (0, drv); /* update status */\r | |
496 | switch (j) { /* decode PA<4:1> */\r | |
497 | \r | |
498 | case 000: /* HKCS1 */\r | |
499 | *data = hkcs1;\r | |
500 | break;\r | |
501 | \r | |
502 | case 001: /* HKWC */\r | |
503 | *data = hkwc;\r | |
504 | break;\r | |
505 | \r | |
506 | case 002: /* HKBA */\r | |
507 | *data = hkba = hkba & ~BA_MBZ;\r | |
508 | break;\r | |
509 | \r | |
510 | case 003: /* HKDA */\r | |
511 | *data = hkda = hkda & ~DA_MBZ;\r | |
512 | break;\r | |
513 | \r | |
514 | case 004: /* HKCS2 */\r | |
515 | *data = hkcs2 = (hkcs2 & ~CS2_MBZ) | CS2_IR;\r | |
516 | break;\r | |
517 | \r | |
518 | case 005: /* HKDS */\r | |
519 | *data = hkds[drv];\r | |
520 | break;\r | |
521 | \r | |
522 | case 006: /* HKER */\r | |
523 | *data = hker[drv];\r | |
524 | break;\r | |
525 | \r | |
526 | case 007: /* HKAS */\r | |
527 | *data = hkof;\r | |
528 | for (i = 0; i < HK_NUMDR; i++)\r | |
529 | if (hkds[i] & DS_ATA) *data = *data | (AS_U0 << i);\r | |
530 | break;\r | |
531 | \r | |
532 | case 010: /* HKDC */\r | |
533 | *data = hkdc = hkdc & ~DC_MBZ;\r | |
534 | break;\r | |
535 | \r | |
536 | case 011: /* spare */\r | |
537 | *data = hkspr;\r | |
538 | break;\r | |
539 | \r | |
540 | case 012: /* HKDB */\r | |
541 | *data = hkdb[0]; /* top of silo */\r | |
542 | hkdb[0] = hkdb[1]; /* ripple silo */\r | |
543 | hkdb[1] = hkdb[2];\r | |
544 | hkdb[2] = 0; /* just for READH */\r | |
545 | break;\r | |
546 | \r | |
547 | case 013: /* HKMR */\r | |
548 | *data = hkmr;\r | |
549 | break;\r | |
550 | \r | |
551 | case 014: /* HKEC1 */\r | |
552 | case 015: /* HKEC2 */\r | |
553 | *data = 0; /* no ECC */\r | |
554 | break;\r | |
555 | \r | |
556 | case 016: /* HKMR2 */\r | |
557 | *data = hkmr2;\r | |
558 | break;\r | |
559 | \r | |
560 | case 017: /* HKMR3 */\r | |
561 | *data = hkmr3;\r | |
562 | break;\r | |
563 | }\r | |
564 | \r | |
565 | if (DEBUG_PRI (hk_dev, HKDEB_RRD))\r | |
566 | fprintf (sim_deb, ">>HK%d read: reg%d=%o\n", drv, j, *data);\r | |
567 | return SCPE_OK;\r | |
568 | }\r | |
569 | \r | |
570 | t_stat hk_wr (int32 data, int32 PA, int32 access)\r | |
571 | {\r | |
572 | int32 drv, i, j;\r | |
573 | UNIT *uptr;\r | |
574 | \r | |
575 | drv = GET_UNIT (hkcs2); /* get current unit */\r | |
576 | uptr = hk_dev.units + drv; /* get unit */\r | |
577 | j = (PA >> 1) & 017; /* get reg offset */\r | |
578 | if ((hkcs1 & CS1_GO) && /* busy? */\r | |
579 | !(((j == 0) && (data & CS1_CCLR)) || /* not cclr or sclr? */\r | |
580 | ((j == 4) && (data & CS2_CLR)))) {\r | |
581 | hkcs2 = hkcs2 | CS2_PGE; /* prog error */\r | |
582 | update_hkcs (0, drv);\r | |
583 | return SCPE_OK;\r | |
584 | }\r | |
585 | \r | |
586 | if (DEBUG_PRI (hk_dev, HKDEB_RWR))\r | |
587 | fprintf (sim_deb, ">>HK%d write: reg%d=%o\n", drv, j, data);\r | |
588 | switch (j) { /* decode PA<4:1> */\r | |
589 | \r | |
590 | case 000: /* HKCS1 */\r | |
591 | if (data & CS1_CCLR) { /* controller reset? */\r | |
592 | hkcs1 = CS1_DONE; /* CS1 = done */\r | |
593 | hkcs2 = CS2_IR; /* CS2 = ready */\r | |
594 | hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */\r | |
595 | hkda = hkdc = 0;\r | |
596 | hkba = hkwc = 0;\r | |
597 | hkspr = hkof = 0;\r | |
598 | CLR_INT (HK); /* clr int */\r | |
599 | for (i = 0; i < HK_NUMDR; i++) { /* stop data xfr */\r | |
600 | if (sim_is_active (&hk_unit[i]) &&\r | |
601 | ((uptr->FNC & CS1_M_FNC) >= FNC_XFER))\r | |
602 | sim_cancel (&hk_unit[i]);\r | |
603 | }\r | |
604 | drv = 0;\r | |
605 | break;\r | |
606 | }\r | |
607 | if (data & CS1_IE) { /* setting IE? */\r | |
608 | if (data & CS1_DONE) SET_INT (HK); /* write to DONE+IE? */\r | |
609 | }\r | |
610 | else CLR_INT (HK); /* no, clr intr */\r | |
611 | hkcs1 = (hkcs1 & ~CS1_RW) | (data & CS1_RW); /* merge data */\r | |
612 | if (SC02C) hkspr = (hkspr & ~CS1_M_UAE) | GET_UAE (hkcs1);\r | |
613 | if ((data & CS1_GO) && !(hkcs1 & CS1_ERR)) /* go? */\r | |
614 | hk_go (drv);\r | |
615 | break; \r | |
616 | \r | |
617 | case 001: /* HKWC */\r | |
618 | hkwc = data;\r | |
619 | break;\r | |
620 | \r | |
621 | case 002: /* HKBA */\r | |
622 | hkba = data & ~BA_MBZ;\r | |
623 | break;\r | |
624 | \r | |
625 | case 003: /* HKDA */\r | |
626 | hkda = data & ~DA_MBZ;\r | |
627 | break;\r | |
628 | \r | |
629 | case 004: /* HKCS2 */\r | |
630 | if (data & CS2_CLR) hk_reset (&hk_dev); /* init? */\r | |
631 | else hkcs2 = (hkcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR;\r | |
632 | drv = GET_UNIT (hkcs2);\r | |
633 | break;\r | |
634 | \r | |
635 | case 007: /* HKAS */\r | |
636 | hkof = data & AS_OF;\r | |
637 | break;\r | |
638 | \r | |
639 | case 010: /* HKDC */\r | |
640 | hkdc = data & ~DC_MBZ;\r | |
641 | break;\r | |
642 | \r | |
643 | case 011: /* spare */\r | |
644 | hkspr = data;\r | |
645 | if (SC02C) hkcs1 = PUT_UAE (hkcs1, hkspr & 03); /* SC02C? upd UAE */\r | |
646 | break;\r | |
647 | \r | |
648 | case 012: /* HKDB */\r | |
649 | hkdb[0] = data;\r | |
650 | break;\r | |
651 | \r | |
652 | case 013: /* HKMR */\r | |
653 | hkmr = data & MR_RW;\r | |
654 | break;\r | |
655 | \r | |
656 | default: /* all others RO */\r | |
657 | break;\r | |
658 | } /* end switch */\r | |
659 | \r | |
660 | update_hkcs (0, drv); /* update status */\r | |
661 | return SCPE_OK;\r | |
662 | }\r | |
663 | \r | |
664 | /* Initiate operation - go set, not previously set */\r | |
665 | \r | |
666 | void hk_go (int32 drv)\r | |
667 | {\r | |
668 | int32 fnc, t;\r | |
669 | UNIT *uptr;\r | |
670 | \r | |
671 | static uint8 fnc_cdt[16] = {\r | |
672 | 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\r | |
673 | };\r | |
674 | \r | |
675 | static uint8 fnc_nxf[16] = {\r | |
676 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0\r | |
677 | };\r | |
678 | static uint8 fnc_att[16] = {\r | |
679 | 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0\r | |
680 | };\r | |
681 | static uint8 fnc_rdy[16] = {\r | |
682 | 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0\r | |
683 | };\r | |
684 | static uint8 fnc_cyl[16] = {\r | |
685 | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0\r | |
686 | };\r | |
687 | \r | |
688 | fnc = GET_FNC (hkcs1);\r | |
689 | if (DEBUG_PRI (hk_dev, HKDEB_OPS)) fprintf (sim_deb,\r | |
690 | ">>HK%d strt: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n",\r | |
691 | drv, fnc, hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc);\r | |
692 | uptr = hk_dev.units + drv; /* get unit */\r | |
693 | if (fnc != FNC_NOP) hkmr = hkmr & ~MR_MS; /* !nop, clr msg sel */\r | |
694 | if (uptr->flags & UNIT_DIS) { /* nx unit? */\r | |
695 | hkcs2 = hkcs2 | CS2_NED; /* set error flag */\r | |
696 | update_hkcs (CS1_DONE, drv); /* done */\r | |
697 | return;\r | |
698 | }\r | |
699 | if (fnc_cdt[fnc] &&\r | |
700 | (((hkcs1 & CS1_DT) != 0) != /* need dtype match? */\r | |
701 | ((uptr->flags & UNIT_DTYPE) != 0))) {\r | |
702 | hk_cmderr (ER_DTY, drv); /* type error */\r | |
703 | return;\r | |
704 | }\r | |
705 | if (fnc_nxf[fnc] && ((hkds[drv] & DS_VV) == 0)) { /* need vol valid? */\r | |
706 | hk_cmderr (ER_NXF, drv); /* non exec func */\r | |
707 | return;\r | |
708 | }\r | |
709 | if (fnc_att[fnc] && !(uptr->flags & UNIT_ATT)) { /* need attached? */\r | |
710 | hk_cmderr (ER_UNS, drv); /* unsafe */\r | |
711 | return;\r | |
712 | }\r | |
713 | if (fnc_rdy[fnc] && sim_is_active (uptr)) return; /* need inactive? */\r | |
714 | if (fnc_cyl[fnc] && /* need valid cyl */\r | |
715 | ((GET_CY (hkdc) >= HK_CYL (uptr)) || /* bad cylinder */\r | |
716 | (GET_SF (hkda) >= HK_NUMSF) || /* bad surface */\r | |
717 | (GET_SC (hkda) >= HK_NUMSC))) { /* or bad sector? */\r | |
718 | hk_cmderr (ER_IAE, drv); /* illegal addr */\r | |
719 | return;\r | |
720 | }\r | |
721 | \r | |
722 | hkcs1 = (hkcs1 | CS1_GO) & ~CS1_DONE; /* set go, clear done */\r | |
723 | switch (fnc) { /* case on function */\r | |
724 | \r | |
725 | /* Instantaneous functions (unit may be busy, can't schedule thread) */\r | |
726 | \r | |
727 | case FNC_NOP: /* no operation */\r | |
728 | hkmr2 = hk_rdmr2 (GET_MS (hkmr)); /* get serial msgs */\r | |
729 | hkmr3 = hk_rdmr3 (GET_MS (hkmr));\r | |
730 | update_hkcs (CS1_DONE, drv); /* done */\r | |
731 | break;\r | |
732 | \r | |
733 | case FNC_DCLR: /* drive clear */\r | |
734 | hkds[drv] &= ~DS_ATA; /* clr ATA */ \r | |
735 | hker[drv] = 0; /* clear errors */\r | |
736 | update_hkcs (CS1_DONE, drv); /* done */\r | |
737 | break;\r | |
738 | \r | |
739 | case FNC_PACK: /* pack acknowledge */\r | |
740 | hkds[drv] = hkds[drv] | DS_VV; /* set volume valid */\r | |
741 | update_hkcs (CS1_DONE, drv); /* done */\r | |
742 | break;\r | |
743 | \r | |
744 | /* "Fast functions" finish in less than 15 usec */\r | |
745 | \r | |
746 | case FNC_START: /* start spindle */\r | |
747 | case FNC_UNLOAD: /* unload */\r | |
748 | uptr->FNC = fnc; /* save function */\r | |
749 | sim_activate (uptr, hk_cwait); /* schedule */\r | |
750 | return;\r | |
751 | \r | |
752 | /* Positioning functions provide two interrupts - an immediate interrupt\r | |
753 | on ctrl done and a second one (if ctrl ready) when the seek is complete */\r | |
754 | \r | |
755 | case FNC_OFFSET: /* offset mode */\r | |
756 | case FNC_RECAL: /* recalibrate */\r | |
757 | case FNC_SEEK: /* seek */\r | |
758 | hkds[drv] = hkds[drv] | DS_PIP; /* set positioning */\r | |
759 | uptr->FNC = fnc; /* save function */\r | |
760 | sim_activate (uptr, hk_cwait); /* schedule */\r | |
761 | return;\r | |
762 | \r | |
763 | /* Data transfer functions lock the controller for the duration */\r | |
764 | \r | |
765 | case FNC_WRITEH: /* write headers */\r | |
766 | case FNC_WRITE: /* write */\r | |
767 | hk_off[drv] = 0; /* clr offset */\r | |
768 | case FNC_WCHK: /* write check */\r | |
769 | case FNC_READ: /* read */\r | |
770 | case FNC_READH: /* read headers */\r | |
771 | hk_dif[drv] = hkdc - uptr->CYL; /* cyl diff */\r | |
772 | t = abs (hk_dif[drv]); /* |cyl diff| */\r | |
773 | sim_activate (uptr, hk_rwait + (hk_swait * t)); /* Schedule */\r | |
774 | uptr->FNC = fnc; /* save function */\r | |
775 | uptr->CYL = hkdc; /* update cyl */\r | |
776 | return;\r | |
777 | \r | |
778 | default:\r | |
779 | hk_cmderr (ER_ILF, drv); /* not supported */\r | |
780 | break;\r | |
781 | }\r | |
782 | return;\r | |
783 | }\r | |
784 | \r | |
785 | /* Service unit timeout\r | |
786 | \r | |
787 | Complete movement or data transfer command\r | |
788 | Unit must exist - can't remove an active unit\r | |
789 | Unit must be attached - detach cancels in progress operations\r | |
790 | */\r | |
791 | \r | |
792 | t_stat hk_svc (UNIT *uptr)\r | |
793 | {\r | |
794 | int32 i, t, dc, fnc, err;\r | |
795 | int32 wc, awc, da;\r | |
796 | uint32 drv, ba;\r | |
797 | uint16 comp;\r | |
798 | \r | |
799 | drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r | |
800 | fnc = uptr->FNC & CS1_M_FNC; /* get function */\r | |
801 | switch (fnc) { /* case on function */\r | |
802 | \r | |
803 | /* Fast commands - start spindle only provides one interrupt\r | |
804 | because ATTACH implicitly spins up the drive */\r | |
805 | \r | |
806 | case FNC_UNLOAD: /* unload */\r | |
807 | hk_detach (uptr); /* detach unit */\r | |
808 | case FNC_START: /* start spindle */\r | |
809 | update_hkcs (CS1_DONE, drv); /* done */\r | |
810 | break;\r | |
811 | \r | |
812 | /* Positioning commands provide two interrupts, an immediate controller done\r | |
813 | and a delayed drive interrupt */\r | |
814 | \r | |
815 | case FNC_OFFSET: /* offset */\r | |
816 | if (uptr->FNC & FNC_2ND) { /* 2nd int? */\r | |
817 | hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */\r | |
818 | update_hkcs (CS1_DI, drv); /* drive intr */\r | |
819 | }\r | |
820 | else {\r | |
821 | uptr->FNC = uptr->FNC | FNC_2ND; /* second state */\r | |
822 | hk_off[drv] = hkof & AS_OF; /* save offset */\r | |
823 | sim_activate (uptr, hk_min2wait); /* wait for compl */\r | |
824 | update_hkcs (CS1_DONE, drv); /* done */\r | |
825 | } \r | |
826 | break;\r | |
827 | \r | |
828 | case FNC_RECAL: /* recalibrate */\r | |
829 | case FNC_SEEK: /* seek */\r | |
830 | if (uptr->FNC & FNC_2ND) { /* 2nd int? */\r | |
831 | hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */\r | |
832 | update_hkcs (CS1_DI, drv); /* drive intr */\r | |
833 | }\r | |
834 | else {\r | |
835 | uptr->FNC = uptr->FNC | FNC_2ND; /* second state */\r | |
836 | hk_off[drv] = 0; /* clr offset */\r | |
837 | dc = (fnc == FNC_SEEK)? hkdc: 0; /* get cyl */\r | |
838 | hk_dif[drv] = dc - uptr->CYL; /* cyl diff */\r | |
839 | t = abs (hk_dif[drv]) * hk_swait; /* |cyl diff| */\r | |
840 | if (t < hk_min2wait) t = hk_min2wait; /* min time */\r | |
841 | uptr->CYL = dc; /* save cyl */ \r | |
842 | sim_activate (uptr, t); /* schedule */\r | |
843 | update_hkcs (CS1_DONE, drv); /* done */\r | |
844 | }\r | |
845 | break;\r | |
846 | \r | |
847 | /* Data transfer commands only generate one interrupt */\r | |
848 | \r | |
849 | case FNC_READH:\r | |
850 | hkdb[0] = uptr->CYL << RDH1_V_CYL; /* first word */\r | |
851 | hkdb[1] = (GET_SC (hkda) << RDH2_V_SEC) | /* second word */\r | |
852 | (1 << (GET_SF (hkda) + RDH2_V_DHA)) | RDH2_GOOD;\r | |
853 | hkdb[2] = hkdb[0] ^ hkdb[1]; /* checksum */\r | |
854 | update_hkcs (CS1_DONE, drv); /* done */\r | |
855 | break;\r | |
856 | \r | |
857 | case FNC_WRITE: /* write */\r | |
858 | if (uptr->flags & UNIT_WPRT) { /* write locked? */\r | |
859 | hk_cmderr (ER_WLE, drv); /* command error */\r | |
860 | return SCPE_OK;\r | |
861 | }\r | |
862 | case FNC_WCHK: /* write check */\r | |
863 | case FNC_READ: /* read */\r | |
864 | if (SC02C) ba = ((hkspr & XM_MMASK) << 16) | hkba; /* 22b addr? */\r | |
865 | else ba = (GET_UAE (hkcs1) << 16) | hkba; /* no, 18b addr */\r | |
866 | da = GET_DA (hkdc, hkda) * HK_NUMWD; /* get disk addr */\r | |
867 | wc = 0200000 - hkwc; /* get true wc */\r | |
868 | \r | |
869 | if ((da + wc) > HK_SIZE (uptr)) { /* disk overrun? */\r | |
870 | hker[drv] = hker[drv] | ER_AOE; /* set err */\r | |
871 | hkds[drv] = hkds[drv] | DS_ATA; /* set attn */\r | |
872 | wc = HK_SIZE (uptr) - da; /* trim xfer */\r | |
873 | if (da >= HK_SIZE (uptr)) { /* none left? */\r | |
874 | update_hkcs (CS1_DONE, drv); /* then done */\r | |
875 | break;\r | |
876 | }\r | |
877 | }\r | |
878 | \r | |
879 | err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);\r | |
880 | if (uptr->FNC == FNC_WRITE) { /* write? */\r | |
881 | if (hkcs2 & CS2_UAI) { /* no addr inc? */\r | |
882 | if (t = Map_ReadW (ba, 2, &comp)) { /* get 1st wd */\r | |
883 | wc = 0; /* NXM, no xfr */\r | |
884 | hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */\r | |
885 | }\r | |
886 | for (i = 0; i < wc; i++) hkxb[i] = comp;\r | |
887 | }\r | |
888 | else { /* normal */\r | |
889 | if (t = Map_ReadW (ba, wc << 1, hkxb)) { /* get buf */\r | |
890 | wc = wc - (t >> 1); /* NXM, adj wc */\r | |
891 | hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */\r | |
892 | }\r | |
893 | ba = ba + (wc << 1); /* adv ba */\r | |
894 | }\r | |
895 | awc = (wc + (HK_NUMWD - 1)) & ~(HK_NUMWD - 1);\r | |
896 | for (i = wc; i < awc; i++) hkxb[i] = 0; /* fill buf */\r | |
897 | if (wc && !err) { /* write buf */\r | |
898 | fxwrite (hkxb, sizeof (uint16), wc, uptr->fileref);\r | |
899 | err = ferror (uptr->fileref);\r | |
900 | }\r | |
901 | } /* end if wr */\r | |
902 | else if (uptr->FNC == FNC_READ) { /* read? */\r | |
903 | i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref);\r | |
904 | err = ferror (uptr->fileref);\r | |
905 | for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */\r | |
906 | if (hkcs2 & CS2_UAI) { /* no addr inc? */\r | |
907 | if (t = Map_WriteW (ba, 2, &hkxb[wc - 1])) {\r | |
908 | wc = 0; /* NXM, no xfr */\r | |
909 | hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */\r | |
910 | }\r | |
911 | }\r | |
912 | else { /* normal */\r | |
913 | if (t = Map_WriteW (ba, wc << 1, hkxb)) { /* put buf */\r | |
914 | wc = wc - (t >> 1); /* NXM, adj wc */\r | |
915 | hkcs2 = hkcs2 | CS2_NEM; /* set nxm err */\r | |
916 | }\r | |
917 | ba = ba + (wc << 1); /* adv ba */\r | |
918 | }\r | |
919 | } /* end if read */\r | |
920 | else { /* wchk */ \r | |
921 | i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref);\r | |
922 | err = ferror (uptr->fileref);\r | |
923 | for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */\r | |
924 | awc = wc;\r | |
925 | for (wc = 0; wc < awc; wc++) { /* loop thru buf */\r | |
926 | if (Map_ReadW (ba, 2, &comp)) { /* read word */\r | |
927 | hkcs2 = hkcs2 | CS2_NEM; /* set error */\r | |
928 | break;\r | |
929 | }\r | |
930 | if (comp != hkxb[wc]) { /* compare wd */\r | |
931 | hkcs2 = hkcs2 | CS2_WCE; /* set error */\r | |
932 | break;\r | |
933 | }\r | |
934 | if ((hkcs2 & CS2_UAI) == 0) ba = ba + 2;\r | |
935 | }\r | |
936 | } /* end else wchk */\r | |
937 | \r | |
938 | hkwc = (hkwc + wc) & 0177777; /* final word count */\r | |
939 | hkba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */\r | |
940 | hkcs1 = PUT_UAE (hkcs1, ba >> 16); /* upper 2b */\r | |
941 | if (SC02C) /* SC02C? upper 6b */\r | |
942 | hkspr = (hkspr & ~XM_MMASK) | ((ba >> 16) & XM_MMASK);\r | |
943 | da = da + wc + (HK_NUMWD - 1);\r | |
944 | da = da / HK_NUMWD;\r | |
945 | hkda = da % HK_NUMSC;\r | |
946 | da = da / HK_NUMSC;\r | |
947 | hkda = hkda | ((da % HK_NUMSF) << DA_V_SF);\r | |
948 | hkdc = da / HK_NUMSF;\r | |
949 | \r | |
950 | if (err != 0) { /* error? */\r | |
951 | hk_cmderr (ER_PAR, drv); /* set drive error */\r | |
952 | perror ("HK I/O error");\r | |
953 | clearerr (uptr->fileref);\r | |
954 | return SCPE_IOERR;\r | |
955 | }\r | |
956 | \r | |
957 | case FNC_WRITEH: /* write headers stub */\r | |
958 | update_hkcs (CS1_DONE, drv); /* set done */\r | |
959 | break;\r | |
960 | } /* end case func */\r | |
961 | \r | |
962 | return SCPE_OK;\r | |
963 | }\r | |
964 | \r | |
965 | /* Controller status update\r | |
966 | \r | |
967 | Check for done transition\r | |
968 | Update drive status\r | |
969 | Update HKCS1\r | |
970 | Update interrupt request\r | |
971 | */\r | |
972 | \r | |
973 | void update_hkcs (int32 flag, int32 drv)\r | |
974 | {\r | |
975 | int32 i;\r | |
976 | \r | |
977 | update_hkds (drv); /* upd drv status */\r | |
978 | if (flag & CS1_DONE) hkcs1 = hkcs1 & ~CS1_GO; /* clear go */\r | |
979 | if (hkcs1 & CS1_IE) { /* intr enable? */\r | |
980 | if (((flag & CS1_DONE) && ((hkcs1 & CS1_DONE) == 0)) ||\r | |
981 | ((flag & CS1_DI) && (hkcs1 & CS1_DONE))) /* done 0->1 or DI? */\r | |
982 | SET_INT (HK);\r | |
983 | }\r | |
984 | else CLR_INT (HK);\r | |
985 | hkcs1 = (hkcs1 & (CS1_DT|CS1_UAE|CS1_DONE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO)) | flag;\r | |
986 | for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */\r | |
987 | if (hkds[i] & DS_ATA) hkcs1 = hkcs1 | CS1_DI;\r | |
988 | }\r | |
989 | if (hker[drv] | (hkcs1 & (CS1_PAR | CS1_CTO)) | /* if err, set ERR */\r | |
990 | (hkcs2 & CS2_ERR)) hkcs1 = hkcs1 | CS1_ERR;\r | |
991 | if ((flag & CS1_DONE) && /* set done && debug? */\r | |
992 | (DEBUG_PRI (hk_dev, HKDEB_OPS)))\r | |
993 | fprintf (sim_deb,\r | |
994 | ">>HK%d done: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n",\r | |
995 | drv, GET_FNC (hkcs1), hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc);\r | |
996 | return;\r | |
997 | }\r | |
998 | \r | |
999 | /* Drive status update */\r | |
1000 | \r | |
1001 | void update_hkds (int32 drv)\r | |
1002 | {\r | |
1003 | if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */\r | |
1004 | hkds[drv] = hker[drv] = 0; /* all clear */\r | |
1005 | return;\r | |
1006 | }\r | |
1007 | hkds[drv] = (hkds[drv] & (DS_VV | DS_PIP | DS_ATA)) | DS_VLD | DS_DRA;\r | |
1008 | if (hk_unit[drv].flags & UNIT_ATT) { /* attached? */\r | |
1009 | if (!sim_is_active (&hk_unit[drv])) /* not busy? */\r | |
1010 | hkds[drv] = hkds[drv] | DS_RDY; /* set RDY */\r | |
1011 | if (hker[drv]) hkds[drv] = hkds[drv] | DS_ATA; /* err? set ATA */\r | |
1012 | if (hk_off[drv]) hkds[drv] = hkds[drv] | DS_OF; /* offset? set OF */\r | |
1013 | if (hk_unit[drv].flags & UNIT_WPRT) /* write locked? */\r | |
1014 | hkds[drv] = hkds[drv] | DS_WRL; /* set WRL */\r | |
1015 | }\r | |
1016 | else {\r | |
1017 | hkds[drv] = hkds[drv] & ~(DS_PIP | DS_VV); /* no, clr PIP,VV */\r | |
1018 | hker[drv] = 0; /* no errors */\r | |
1019 | }\r | |
1020 | if (hk_unit[drv].flags & UNIT_RK07) hkds[drv] = hkds[drv] | DS_DT;\r | |
1021 | return;\r | |
1022 | }\r | |
1023 | \r | |
1024 | /* Set error and abort command */\r | |
1025 | \r | |
1026 | void hk_cmderr (int32 err, int32 drv)\r | |
1027 | {\r | |
1028 | hker[drv] = hker[drv] | err; /* set error */\r | |
1029 | hkds[drv] = hkds[drv] | DS_ATA; /* set attn */\r | |
1030 | update_hkcs (CS1_DONE, drv); /* set done */\r | |
1031 | return;\r | |
1032 | }\r | |
1033 | \r | |
1034 | /* Diagnostic registers\r | |
1035 | \r | |
1036 | It's unclear whether the drivers actually use these values, but the\r | |
1037 | Emulex controller bothers to implement them, so we will too */\r | |
1038 | \r | |
1039 | int32 hk_mrpar (int32 v)\r | |
1040 | {\r | |
1041 | int32 bit, wrk;\r | |
1042 | \r | |
1043 | wrk = v & 077777; /* par on 15b */\r | |
1044 | v = wrk | ((hkmr & MR_PAR)? 0: AX_PAR); /* even/odd */\r | |
1045 | while (wrk) { /* while 1's */\r | |
1046 | bit = wrk & (-wrk); /* lowest 1 */\r | |
1047 | wrk = wrk & ~bit; /* clear */\r | |
1048 | v = v ^ AX_PAR; /* xor parity */\r | |
1049 | }\r | |
1050 | return v;\r | |
1051 | }\r | |
1052 | \r | |
1053 | int32 hk_rdmr2 (int32 msg)\r | |
1054 | {\r | |
1055 | int32 drv = GET_UNIT (hkcs2);\r | |
1056 | int32 v = drv << AX_V_UNIT;\r | |
1057 | UNIT *uptr = hk_dev.units + drv;\r | |
1058 | int32 fnc = uptr->FNC & CS1_M_FNC;\r | |
1059 | \r | |
1060 | switch (msg) {\r | |
1061 | \r | |
1062 | case 0: /* message A0 */\r | |
1063 | v = v | ((hkds[drv] & DS_ATA)? A0_ATA: 0) |\r | |
1064 | ((hkds[drv] & DS_PIP)? A0_PIP: 0) |\r | |
1065 | ((uptr->flags & UNIT_WPRT)? A0_WRL: 0) |\r | |
1066 | ((hk_off[drv])? A0_OF: 0) |\r | |
1067 | ((uptr->flags & UNIT_RK07)? A0_DT: 0) |\r | |
1068 | ((hkds[drv] & DS_VV)? A0_VV: 0) | A0_DRA;\r | |
1069 | if (uptr->flags & UNIT_ATT) v = v | A0_SPO |\r | |
1070 | (!sim_is_active (uptr)? A0_RDY: 0);\r | |
1071 | break;\r | |
1072 | \r | |
1073 | case 1: /* message A1 */\r | |
1074 | if (uptr->flags & UNIT_ATT) {\r | |
1075 | if (sim_is_active (uptr)) {\r | |
1076 | if (fnc == FNC_UNLOAD) v = v | A1_UNL;\r | |
1077 | else if (fnc == FNC_RECAL) v = v | A1_RTZ;\r | |
1078 | else if (fnc == FNC_SEEK) {\r | |
1079 | if (hk_dif[drv] < 0) v = v | A1_REV;\r | |
1080 | if (hk_dif[drv] > 0) v = v | A1_FWD;\r | |
1081 | }\r | |
1082 | }\r | |
1083 | v = v | (A1_SPD|A1_CAR|A1_DOR|A1_HHM|A1_SRV);\r | |
1084 | }\r | |
1085 | else v = v | A1_HHM;\r | |
1086 | break;\r | |
1087 | \r | |
1088 | case 2: /* message A2 */\r | |
1089 | if (hkds[drv] & DS_OF)\r | |
1090 | v = v | ((hk_off[drv] & A2_M_DIF) << A2_V_DIF);\r | |
1091 | else v = v | ((hk_dif[drv] & A2_M_DIF) << A2_V_DIF);\r | |
1092 | break;\r | |
1093 | \r | |
1094 | case 3: /* message A3 */\r | |
1095 | v = v | ((012340 + v) << A3_V_SNO);\r | |
1096 | break;\r | |
1097 | }\r | |
1098 | \r | |
1099 | return hk_mrpar (v);\r | |
1100 | }\r | |
1101 | \r | |
1102 | int32 hk_rdmr3 (int32 msg)\r | |
1103 | {\r | |
1104 | int32 drv = GET_UNIT (hkcs2);\r | |
1105 | int32 v = msg & 03;\r | |
1106 | \r | |
1107 | switch (msg) {\r | |
1108 | \r | |
1109 | case 0: /* message B0 */\r | |
1110 | v = v | ((hker[drv] & ER_WLE)? (B0_WLE | B0_FLT): 0) |\r | |
1111 | ((hker[drv] & ER_SKI)? (B0_SKI | B0_FLT): 0) |\r | |
1112 | ((hker[drv] & ER_NXF)? (B0_NXF | B0_FLT): 0) |\r | |
1113 | ((hker[drv] & ER_IAE)? (B0_IAE | B0_FLT): 0);\r | |
1114 | break;\r | |
1115 | \r | |
1116 | case 1: /* message B1 */\r | |
1117 | v = v | ((hker[drv] & ER_SKI)? B1_SKI: 0) |\r | |
1118 | ((hker[drv] & ER_UNS)? B1_SVE: 0);\r | |
1119 | break;\r | |
1120 | \r | |
1121 | case 2: /* message B2 */\r | |
1122 | v = v | (hk_unit[drv].CYL << B2_V_CYL);\r | |
1123 | break;\r | |
1124 | \r | |
1125 | case 3: /* message B3 */\r | |
1126 | v = v | (GET_SC (hkda) << B3_V_SEC) |\r | |
1127 | (1 << (GET_SF (hkda) + B3_V_DHA));\r | |
1128 | break;\r | |
1129 | }\r | |
1130 | \r | |
1131 | return hk_mrpar (v);\r | |
1132 | }\r | |
1133 | \r | |
1134 | /* Device reset */\r | |
1135 | \r | |
1136 | t_stat hk_reset (DEVICE *dptr)\r | |
1137 | {\r | |
1138 | int32 i;\r | |
1139 | UNIT *uptr;\r | |
1140 | \r | |
1141 | hkcs1 = CS1_DONE; /* set done */\r | |
1142 | hkcs2 = CS2_IR; /* clear state */\r | |
1143 | hkmr = hkmr2 = hkmr3 = 0;\r | |
1144 | hkda = hkdc = 0;\r | |
1145 | hkba = hkwc = 0;\r | |
1146 | hkof = hkspr = 0;\r | |
1147 | CLR_INT (HK); /* clear intr req */\r | |
1148 | for (i = 0; i < HK_NUMDR; i++) { /* stop operations */\r | |
1149 | uptr = hk_dev.units + i;\r | |
1150 | sim_cancel (uptr);\r | |
1151 | if (uptr->flags & UNIT_ATT) hkds[i] = hkds[i] & DS_VV;\r | |
1152 | else hkds[i] = 0;\r | |
1153 | uptr->CYL = uptr->FNC = 0; /* clear state */\r | |
1154 | hk_dif[i] = 0;\r | |
1155 | hk_off[i] = 0;\r | |
1156 | hker[i] = 0;\r | |
1157 | } /* clear errors */\r | |
1158 | if (hkxb == NULL) hkxb = (uint16 *) calloc (HK_MAXFR, sizeof (uint16));\r | |
1159 | if (hkxb == NULL) return SCPE_MEM;\r | |
1160 | return SCPE_OK;\r | |
1161 | }\r | |
1162 | \r | |
1163 | /* Device attach */\r | |
1164 | \r | |
1165 | t_stat hk_attach (UNIT *uptr, char *cptr)\r | |
1166 | {\r | |
1167 | uint32 drv, p;\r | |
1168 | t_stat r;\r | |
1169 | \r | |
1170 | uptr->capac = HK_SIZE (uptr);\r | |
1171 | r = attach_unit (uptr, cptr); /* attach unit */\r | |
1172 | if (r != SCPE_OK) return r; /* error? */\r | |
1173 | drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r | |
1174 | hkds[drv] = DS_ATA | DS_RDY | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r | |
1175 | hker[drv] = 0; /* upd drv status */\r | |
1176 | hk_off[drv] = 0;\r | |
1177 | hk_dif[drv] = 0;\r | |
1178 | uptr->CYL = 0;\r | |
1179 | update_hkcs (CS1_DI, drv); /* upd ctlr status */\r | |
1180 | \r | |
1181 | p = sim_fsize (uptr->fileref); /* get file size */\r | |
1182 | if (p == 0) { /* new disk image? */\r | |
1183 | if (uptr->flags & UNIT_RO) return SCPE_OK;\r | |
1184 | return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD);\r | |
1185 | }\r | |
1186 | if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */\r | |
1187 | if (p > (RK06_SIZE * sizeof (uint16))) {\r | |
1188 | uptr->flags = uptr->flags | UNIT_RK07;\r | |
1189 | uptr->capac = RK07_SIZE;\r | |
1190 | }\r | |
1191 | else {\r | |
1192 | uptr->flags = uptr->flags & ~UNIT_RK07;\r | |
1193 | uptr->capac = RK06_SIZE;\r | |
1194 | }\r | |
1195 | return SCPE_OK;\r | |
1196 | }\r | |
1197 | \r | |
1198 | /* Device detach */\r | |
1199 | \r | |
1200 | t_stat hk_detach (UNIT *uptr)\r | |
1201 | {\r | |
1202 | uint32 drv;\r | |
1203 | \r | |
1204 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r | |
1205 | drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r | |
1206 | hkds[drv] = (hkds[drv] & ~(DS_RDY | DS_WRL | DS_VV | DS_OF)) | DS_ATA;\r | |
1207 | if (sim_is_active (uptr)) { /* unit active? */\r | |
1208 | sim_cancel (uptr); /* cancel operation */\r | |
1209 | hker[drv] = hker[drv] | ER_OPI; /* set drive error */\r | |
1210 | if ((uptr->FNC & FNC_2ND) == 0) /* expecting done? */\r | |
1211 | update_hkcs (CS1_DONE, drv); /* set done */\r | |
1212 | }\r | |
1213 | update_hkcs (CS1_DI, drv); /* request intr */\r | |
1214 | return detach_unit (uptr);\r | |
1215 | }\r | |
1216 | \r | |
1217 | /* Set size command validation routine */\r | |
1218 | \r | |
1219 | t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1220 | {\r | |
1221 | if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r | |
1222 | uptr->capac = val? RK07_SIZE: RK06_SIZE;\r | |
1223 | return SCPE_OK;\r | |
1224 | }\r | |
1225 | \r | |
1226 | /* Set bad block routine */\r | |
1227 | \r | |
1228 | t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1229 | {\r | |
1230 | return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD);\r | |
1231 | }\r | |
1232 | \r | |
1233 | #if defined (VM_PDP11)\r | |
1234 | \r | |
1235 | /* Device bootstrap - does not clear CSR when done */\r | |
1236 | \r | |
1237 | #define BOOT_START 02000 /* start */\r | |
1238 | #define BOOT_ENTRY (BOOT_START + 002) /* entry */\r | |
1239 | #define BOOT_UNIT (BOOT_START + 010) /* unit number */\r | |
1240 | #define BOOT_CSR (BOOT_START + 014) /* CSR */\r | |
1241 | #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))\r | |
1242 | \r | |
1243 | static const uint16 boot_rom[] = {\r | |
1244 | 0042115, /* "MD" */\r | |
1245 | 0012706, BOOT_START, /* mov #boot_start, sp */\r | |
1246 | 0012700, 0000000, /* mov #unit, r0 */\r | |
1247 | 0012701, 0177440, /* mov #HKCS1, r1 */\r | |
1248 | 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */\r | |
1249 | 0010061, 0000010, /* mov r0, 10(r1) ; set unit */\r | |
1250 | 0016102, 0000012, /* mov 12(r1), r2 ; drv typ */\r | |
1251 | 0100375, /* bpl .-4 ; valid? */\r | |
1252 | 0042702, 0177377, /* bic #177377, r2 ; clr rest */\r | |
1253 | 0006302, /* asl r2 ; move */\r | |
1254 | 0006302, /* asl r2 */\r | |
1255 | 0012703, 0000003, /* mov #pack+go, r3 */\r | |
1256 | 0050203, /* bis r2, r3 ; merge type */\r | |
1257 | 0010311, /* mov r3, (r1); ; pack ack */\r | |
1258 | 0105711, /* tstb (r1) ; wait */\r | |
1259 | 0100376, /* bpl .-2 */\r | |
1260 | 0012761, 0177000, 0000002, /* mov #-512.,2(r1) ; set wc */\r | |
1261 | 0005061, 0000004, /* clr 4(r1) ; clr ba */\r | |
1262 | 0005061, 0000006, /* clr 6(r1) ; clr da */\r | |
1263 | 0005061, 0000020, /* clr 20(r1) ; clr cyl */\r | |
1264 | 0012703, 0000021, /* mov #read+go, r3 */\r | |
1265 | 0050203, /* bis r2, r3 ; merge type */\r | |
1266 | 0010311, /* mov r3, (r1); ; read */\r | |
1267 | 0105711, /* tstb (r1) ; wait */\r | |
1268 | 0100376, /* bpl .-2 */\r | |
1269 | 0005002, /* clr R2 */\r | |
1270 | 0005003, /* clr R3 */\r | |
1271 | 0012704, BOOT_START+020, /* mov #start+020, r4 */\r | |
1272 | 0005005, /* clr R5 */\r | |
1273 | 0005007 /* clr PC */\r | |
1274 | };\r | |
1275 | \r | |
1276 | t_stat hk_boot (int32 unitno, DEVICE *dptr)\r | |
1277 | {\r | |
1278 | int32 i;\r | |
1279 | extern int32 saved_PC;\r | |
1280 | \r | |
1281 | for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r | |
1282 | M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT;\r | |
1283 | M[BOOT_CSR >> 1] = hk_dib.ba & DMASK;\r | |
1284 | saved_PC = BOOT_ENTRY;\r | |
1285 | return SCPE_OK;\r | |
1286 | }\r | |
1287 | \r | |
1288 | #else\r | |
1289 | \r | |
1290 | t_stat hk_boot (int32 unitno, DEVICE *dptr)\r | |
1291 | {\r | |
1292 | return SCPE_NOFNC;\r | |
1293 | }\r | |
1294 | \r | |
1295 | #endif\r |