First Commit of my working state
[simh.git] / PDP11 / pdp11_hk.c
CommitLineData
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
63extern int32 cpu_opt;\r
64#endif\r
65\r
66extern 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
325extern int32 int_req[IPL_HLVL];\r
326extern FILE *sim_deb;\r
327\r
328uint16 *hkxb = NULL; /* xfer buffer */\r
329int32 hkcs1 = 0; /* control/status 1 */\r
330int32 hkwc = 0; /* word count */\r
331int32 hkba = 0; /* bus address */\r
332int32 hkda = 0; /* track/sector */\r
333int32 hkcs2 = 0; /* control/status 2 */\r
334int32 hkds[HK_NUMDR] = { 0 }; /* drive status */\r
335int32 hker[HK_NUMDR] = { 0 }; /* error status */\r
336int32 hkof = 0; /* offset */\r
337int32 hkmr = 0; /* maint registers */\r
338int32 hkmr2 = 0;\r
339int32 hkmr3 = 0;\r
340int32 hkdc = 0; /* cylinder */\r
341int32 hkspr = 0; /* spare */\r
342int32 hk_cwait = 5; /* command time */\r
343int32 hk_swait = 10; /* seek time */\r
344int32 hk_rwait = 10; /* rotate time */\r
345int32 hk_min2wait = 300; /* min time to 2nd int */\r
346int16 hkdb[3] = { 0 }; /* data buffer silo */\r
347int16 hk_off[HK_NUMDR] = { 0 }; /* saved offset */\r
348int16 hk_dif[HK_NUMDR] = { 0 }; /* cylinder diff */\r
349static 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
352DEVICE hk_dev;\r
353t_stat hk_rd (int32 *data, int32 PA, int32 access);\r
354t_stat hk_wr (int32 data, int32 PA, int32 access);\r
355t_stat hk_svc (UNIT *uptr);\r
356t_stat hk_reset (DEVICE *dptr);\r
357t_stat hk_boot (int32 unitno, DEVICE *dptr);\r
358t_stat hk_attach (UNIT *uptr, char *cptr);\r
359t_stat hk_detach (UNIT *uptr);\r
360int32 hk_rdmr2 (int32 msg);\r
361int32 hk_rdmr3 (int32 msg);\r
362void update_hkcs (int32 flags, int32 drv);\r
363void update_hkds (int32 drv);\r
364void hk_cmderr (int32 err, int32 drv);\r
365void hk_go (int32 drv);\r
366t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
367t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);\r
368\r
369extern 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
379DIB 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
384UNIT 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
403REG 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
439MTAB 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
464DEBTAB 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
471DEVICE 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
482t_stat hk_rd (int32 *data, int32 PA, int32 access)\r
483{\r
484int32 drv, i, j;\r
485\r
486drv = GET_UNIT (hkcs2); /* get current unit */\r
487j = (PA >> 1) & 017; /* get reg offset */\r
488if (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
495update_hkcs (0, drv); /* update status */\r
496switch (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
565if (DEBUG_PRI (hk_dev, HKDEB_RRD))\r
566 fprintf (sim_deb, ">>HK%d read: reg%d=%o\n", drv, j, *data);\r
567return SCPE_OK;\r
568}\r
569\r
570t_stat hk_wr (int32 data, int32 PA, int32 access)\r
571{\r
572int32 drv, i, j;\r
573UNIT *uptr;\r
574\r
575drv = GET_UNIT (hkcs2); /* get current unit */\r
576uptr = hk_dev.units + drv; /* get unit */\r
577j = (PA >> 1) & 017; /* get reg offset */\r
578if ((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
586if (DEBUG_PRI (hk_dev, HKDEB_RWR))\r
587 fprintf (sim_deb, ">>HK%d write: reg%d=%o\n", drv, j, data);\r
588switch (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
660update_hkcs (0, drv); /* update status */\r
661return SCPE_OK;\r
662}\r
663\r
664/* Initiate operation - go set, not previously set */\r
665\r
666void hk_go (int32 drv)\r
667{\r
668int32 fnc, t;\r
669UNIT *uptr;\r
670\r
671static 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
675static 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
678static 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
681static 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
684static 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
688fnc = GET_FNC (hkcs1);\r
689if (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
692uptr = hk_dev.units + drv; /* get unit */\r
693if (fnc != FNC_NOP) hkmr = hkmr & ~MR_MS; /* !nop, clr msg sel */\r
694if (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
699if (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
705if (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
709if (fnc_att[fnc] && !(uptr->flags & UNIT_ATT)) { /* need attached? */\r
710 hk_cmderr (ER_UNS, drv); /* unsafe */\r
711 return;\r
712 }\r
713if (fnc_rdy[fnc] && sim_is_active (uptr)) return; /* need inactive? */\r
714if (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
722hkcs1 = (hkcs1 | CS1_GO) & ~CS1_DONE; /* set go, clear done */\r
723switch (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
782return;\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
792t_stat hk_svc (UNIT *uptr)\r
793{\r
794int32 i, t, dc, fnc, err;\r
795int32 wc, awc, da;\r
796uint32 drv, ba;\r
797uint16 comp;\r
798\r
799drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r
800fnc = uptr->FNC & CS1_M_FNC; /* get function */\r
801switch (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
962return 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
973void update_hkcs (int32 flag, int32 drv)\r
974{\r
975int32 i;\r
976\r
977update_hkds (drv); /* upd drv status */\r
978if (flag & CS1_DONE) hkcs1 = hkcs1 & ~CS1_GO; /* clear go */\r
979if (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
984else CLR_INT (HK);\r
985hkcs1 = (hkcs1 & (CS1_DT|CS1_UAE|CS1_DONE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO)) | flag;\r
986for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */\r
987 if (hkds[i] & DS_ATA) hkcs1 = hkcs1 | CS1_DI;\r
988 }\r
989if (hker[drv] | (hkcs1 & (CS1_PAR | CS1_CTO)) | /* if err, set ERR */\r
990 (hkcs2 & CS2_ERR)) hkcs1 = hkcs1 | CS1_ERR;\r
991if ((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
996return;\r
997}\r
998\r
999/* Drive status update */\r
1000\r
1001void update_hkds (int32 drv)\r
1002{\r
1003if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */\r
1004 hkds[drv] = hker[drv] = 0; /* all clear */\r
1005 return;\r
1006 }\r
1007hkds[drv] = (hkds[drv] & (DS_VV | DS_PIP | DS_ATA)) | DS_VLD | DS_DRA;\r
1008if (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
1016else {\r
1017 hkds[drv] = hkds[drv] & ~(DS_PIP | DS_VV); /* no, clr PIP,VV */\r
1018 hker[drv] = 0; /* no errors */\r
1019 }\r
1020if (hk_unit[drv].flags & UNIT_RK07) hkds[drv] = hkds[drv] | DS_DT;\r
1021return;\r
1022}\r
1023\r
1024/* Set error and abort command */\r
1025\r
1026void hk_cmderr (int32 err, int32 drv)\r
1027{\r
1028hker[drv] = hker[drv] | err; /* set error */\r
1029hkds[drv] = hkds[drv] | DS_ATA; /* set attn */\r
1030update_hkcs (CS1_DONE, drv); /* set done */\r
1031return;\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
1039int32 hk_mrpar (int32 v)\r
1040{\r
1041int32 bit, wrk;\r
1042\r
1043wrk = v & 077777; /* par on 15b */\r
1044v = wrk | ((hkmr & MR_PAR)? 0: AX_PAR); /* even/odd */\r
1045while (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
1050return v;\r
1051}\r
1052\r
1053int32 hk_rdmr2 (int32 msg)\r
1054{\r
1055int32 drv = GET_UNIT (hkcs2);\r
1056int32 v = drv << AX_V_UNIT;\r
1057UNIT *uptr = hk_dev.units + drv;\r
1058int32 fnc = uptr->FNC & CS1_M_FNC;\r
1059\r
1060switch (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
1099return hk_mrpar (v);\r
1100}\r
1101\r
1102int32 hk_rdmr3 (int32 msg)\r
1103{\r
1104int32 drv = GET_UNIT (hkcs2);\r
1105int32 v = msg & 03;\r
1106\r
1107switch (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
1131return hk_mrpar (v);\r
1132}\r
1133\r
1134/* Device reset */\r
1135\r
1136t_stat hk_reset (DEVICE *dptr)\r
1137{\r
1138int32 i;\r
1139UNIT *uptr;\r
1140\r
1141hkcs1 = CS1_DONE; /* set done */\r
1142hkcs2 = CS2_IR; /* clear state */\r
1143hkmr = hkmr2 = hkmr3 = 0;\r
1144hkda = hkdc = 0;\r
1145hkba = hkwc = 0;\r
1146hkof = hkspr = 0;\r
1147CLR_INT (HK); /* clear intr req */\r
1148for (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
1158if (hkxb == NULL) hkxb = (uint16 *) calloc (HK_MAXFR, sizeof (uint16));\r
1159if (hkxb == NULL) return SCPE_MEM;\r
1160return SCPE_OK;\r
1161}\r
1162\r
1163/* Device attach */\r
1164\r
1165t_stat hk_attach (UNIT *uptr, char *cptr)\r
1166{\r
1167uint32 drv, p;\r
1168t_stat r;\r
1169\r
1170uptr->capac = HK_SIZE (uptr);\r
1171r = attach_unit (uptr, cptr); /* attach unit */\r
1172if (r != SCPE_OK) return r; /* error? */\r
1173drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r
1174hkds[drv] = DS_ATA | DS_RDY | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r
1175hker[drv] = 0; /* upd drv status */\r
1176hk_off[drv] = 0;\r
1177hk_dif[drv] = 0;\r
1178uptr->CYL = 0;\r
1179update_hkcs (CS1_DI, drv); /* upd ctlr status */\r
1180\r
1181p = sim_fsize (uptr->fileref); /* get file size */\r
1182if (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
1186if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */\r
1187if (p > (RK06_SIZE * sizeof (uint16))) {\r
1188 uptr->flags = uptr->flags | UNIT_RK07;\r
1189 uptr->capac = RK07_SIZE;\r
1190 }\r
1191else {\r
1192 uptr->flags = uptr->flags & ~UNIT_RK07;\r
1193 uptr->capac = RK06_SIZE;\r
1194 }\r
1195return SCPE_OK;\r
1196}\r
1197\r
1198/* Device detach */\r
1199\r
1200t_stat hk_detach (UNIT *uptr)\r
1201{\r
1202uint32 drv;\r
1203\r
1204if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r
1205drv = (uint32) (uptr - hk_dev.units); /* get drv number */\r
1206hkds[drv] = (hkds[drv] & ~(DS_RDY | DS_WRL | DS_VV | DS_OF)) | DS_ATA;\r
1207if (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
1213update_hkcs (CS1_DI, drv); /* request intr */\r
1214return detach_unit (uptr);\r
1215}\r
1216\r
1217/* Set size command validation routine */\r
1218\r
1219t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1220{\r
1221if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
1222uptr->capac = val? RK07_SIZE: RK06_SIZE;\r
1223return SCPE_OK;\r
1224}\r
1225\r
1226/* Set bad block routine */\r
1227\r
1228t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1229{\r
1230return 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
1243static 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
1276t_stat hk_boot (int32 unitno, DEVICE *dptr)\r
1277{\r
1278int32 i;\r
1279extern int32 saved_PC;\r
1280\r
1281for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r
1282M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT;\r
1283M[BOOT_CSR >> 1] = hk_dib.ba & DMASK;\r
1284saved_PC = BOOT_ENTRY;\r
1285return SCPE_OK;\r
1286}\r
1287\r
1288#else\r
1289\r
1290t_stat hk_boot (int32 unitno, DEVICE *dptr)\r
1291{\r
1292return SCPE_NOFNC;\r
1293}\r
1294\r
1295#endif\r