First Commit of my working state
[simh.git] / PDP10 / pdp10_rp.c
CommitLineData
196ba1fc
PH
1/* pdp10_rp.c - RH11/RP04/05/06/07 RM02/03/05/80 "Massbus" disk controller\r
2\r
3 Copyright (c) 1993-2005, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 rp RH/RP/RM moving head disks\r
27\r
28 12-Nov-05 RMS Fixed DCLR not to clear drive address\r
29 07-Jul-05 RMS Removed extraneous externs\r
30 18-Mar-05 RMS Added attached test to detach routine\r
31 20-Sep-04 RMS Fixed bugs in replicated state, RP vs RM accuracy\r
32 04-Jan-04 RMS Changed sim_fsize calling sequence\r
33 23-Jul-03 RMS Fixed bug in read header stub\r
34 25-Apr-03 RMS Revised for extended file support\r
35 21-Nov-02 RMS Fixed bug in bootstrap (reported by Michael Thompson)\r
36 29-Sep-02 RMS Added variable vector support\r
37 New data structures\r
38 30-Nov-01 RMS Added read only unit, extended SET/SHOW support support\r
39 24-Nov-01 RMS Changed RPER, RPDS, FNC, FLG to arrays\r
40 23-Oct-01 RMS Fixed bug in error interrupts\r
41 New IO page address constants\r
42 05-Oct-01 RMS Rewrote interrupt handling from schematics\r
43 02-Oct-01 RMS Revised CS1 write code\r
44 30-Sep-01 RMS Moved CS1<5:0> into drives\r
45 28-Sep-01 RMS Fixed interrupt handling for SC/ATA\r
46 23-Aug-01 RMS Added read/write header stubs for ITS\r
47 (found by Mirian Crzig Lennox) \r
48 13-Jul-01 RMS Changed fread call to fxread (found by Peter Schorn)\r
49 14-May-01 RMS Added check for unattached drive\r
50\r
51 The "Massbus style" disks consisted of several different large\r
52 capacity drives interfaced through a reasonably common (but not\r
53 100% compatible) family of interfaces into the KS10 Unibus via\r
54 the RH11 disk controller.\r
55\r
56 WARNING: The interupt logic of the RH11/RH70 is unusual and must be\r
57 simulated with great precision. The RH11 has an internal interrupt\r
58 request flop, CSTB INTR, which is controlled as follows:\r
59 - Writing IE and DONE simultaneously sets CSTB INTR\r
60 - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR\r
61 (and also clear IE)\r
62 - A transition of DONE from 0 to 1 sets CSTB from INTR\r
63 The output of INTR is OR'd with the AND of RPCS1<SC,DONE,IE> to\r
64 create the interrupt request signal. Thus,\r
65 - The DONE interrupt is edge sensitive, but the SC interrupt is\r
66 level sensitive.\r
67 - The DONE interrupt, once set, is not disabled if IE is cleared,\r
68 but the SC interrupt is.\r
69*/\r
70\r
71#include "pdp10_defs.h"\r
72#include <math.h>\r
73\r
74#define RP_NUMDR 8 /* #drives */\r
75#define RP_NUMWD 128 /* 36b words/sector */\r
76#define RP_MAXFR 32768 /* max transfer */\r
77#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \\r
78 ((double) drv_tab[d].sect)))\r
79#define MBA_RP_CTRL 0 /* RP drive */\r
80#define MBA_RM_CTRL 1 /* RM drive */\r
81\r
82/* Flags in the unit flags word */\r
83\r
84#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */\r
85#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */\r
86#define UNIT_M_DTYPE 7\r
87#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */\r
88#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */\r
89#define UNIT_WLK (1 << UNIT_V_WLK)\r
90#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)\r
91#define UNIT_AUTO (1 << UNIT_V_AUTO)\r
92#define UNIT_DUMMY (1 << UNIT_V_DUMMY)\r
93#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)\r
94#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */\r
95\r
96/* Parameters in the unit descriptor */\r
97\r
98#define CYL u3 /* current cylinder */\r
99#define FUNC u4 /* function */\r
100\r
101/* RPCS1 - 176700 - control/status 1 */\r
102\r
103#define CS1_GO CSR_GO /* go */\r
104#define CS1_V_FNC 1 /* function pos */\r
105#define CS1_M_FNC 037 /* function mask */\r
106#define CS1_FNC (CS1_M_FNC << CS1_V_FNC)\r
107#define FNC_NOP 000 /* no operation */\r
108#define FNC_UNLOAD 001 /* unload */\r
109#define FNC_SEEK 002 /* seek */\r
110#define FNC_RECAL 003 /* recalibrate */\r
111#define FNC_DCLR 004 /* drive clear */\r
112#define FNC_RELEASE 005 /* port release */\r
113#define FNC_OFFSET 006 /* offset */\r
114#define FNC_RETURN 007 /* return to center */\r
115#define FNC_PRESET 010 /* read-in preset */\r
116#define FNC_PACK 011 /* pack acknowledge */\r
117#define FNC_SEARCH 014 /* search */\r
118#define FNC_XFER 024 /* >=? data xfr */\r
119#define FNC_WCHK 024 /* write check */\r
120#define FNC_WRITE 030 /* write */\r
121#define FNC_WRITEH 031 /* write w/ headers */\r
122#define FNC_READ 034 /* read */\r
123#define FNC_READH 035 /* read w/ headers */\r
124#define CS1_IE CSR_IE /* int enable */\r
125#define CS1_DONE CSR_DONE /* ready */\r
126#define CS1_V_UAE 8 /* Unibus addr ext */\r
127#define CS1_M_UAE 03\r
128#define CS1_UAE (CS1_M_UAE << CS1_V_UAE)\r
129#define CS1_DVA 0004000 /* drive avail NI */\r
130#define CS1_MCPE 0020000 /* Mbus par err NI */\r
131#define CS1_TRE 0040000 /* transfer err */\r
132#define CS1_SC 0100000 /* special cond */\r
133#define CS1_MBZ 0012000\r
134#define CS1_DRV (CS1_FNC | CS1_GO)\r
135#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)\r
136#define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE))\r
137\r
138/* RPWC - 176702 - word count */\r
139\r
140/* RPBA - 176704 - base address */\r
141\r
142#define BA_MBZ 0000001 /* must be zero */\r
143\r
144/* RPDA - 176706 - sector/track */\r
145\r
146#define DA_V_SC 0 /* sector pos */\r
147#define DA_M_SC 077 /* sector mask */\r
148#define DA_V_SF 8 /* track pos */\r
149#define DA_M_SF 077 /* track mask */\r
150#define DA_MBZ 0140300\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/* RPCS2 - 176710 - 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_UAI 0000010 /* addr inhibit */\r
160#define CS2_PAT 0000020 /* parity test NI */\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_MDPE 0000400 /* Mbus par err NI */\r
165#define CS2_MXF 0001000 /* missed xfer 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 (CS2_UNIT | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)\r
174#define CS2_ERR (CS2_MDPE | CS2_MXF | 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/* RPDS - 176712 - drive status */\r
179\r
180#define DS_OF 0000001 /* offset mode */\r
181#define DS_VV 0000100 /* volume valid */\r
182#define DS_RDY 0000200 /* drive ready */\r
183#define DS_DPR 0000400 /* drive present */\r
184#define DS_PGM 0001000 /* programable NI */\r
185#define DS_LST 0002000 /* last sector */\r
186#define DS_WRL 0004000 /* write locked */\r
187#define DS_MOL 0010000 /* medium online */\r
188#define DS_PIP 0020000 /* pos in progress */\r
189#define DS_ERR 0040000 /* error */\r
190#define DS_ATA 0100000 /* attention active */\r
191#define DS_MBZ 0000076\r
192\r
193/* RPER1 - 176714 - error status 1 */\r
194\r
195#define ER1_ILF 0000001 /* illegal func */\r
196#define ER1_ILR 0000002 /* illegal register */\r
197#define ER1_RMR 0000004 /* reg mod refused */\r
198#define ER1_PAR 0000010 /* parity err */\r
199#define ER1_FER 0000020 /* format err NI */\r
200#define ER1_WCF 0000040 /* write clk fail NI */\r
201#define ER1_ECH 0000100 /* ECC hard err NI */\r
202#define ER1_HCE 0000200 /* hdr comp err NI */\r
203#define ER1_HCR 0000400 /* hdr CRC err NI */\r
204#define ER1_AOE 0001000 /* addr ovflo err */\r
205#define ER1_IAE 0002000 /* invalid addr err */\r
206#define ER1_WLE 0004000 /* write lock err */\r
207#define ER1_DTE 0010000 /* drive time err NI */\r
208#define ER1_OPI 0020000 /* op incomplete */\r
209#define ER1_UNS 0040000 /* drive unsafe */\r
210#define ER1_DCK 0100000 /* data check NI */\r
211\r
212/* RPAS - 176716 - attention summary */\r
213\r
214#define AS_U0 0000001 /* unit 0 flag */\r
215\r
216/* RPLA - 176720 - look ahead register */\r
217\r
218#define LA_V_SC 6 /* sector pos */\r
219\r
220/* RPDB - 176722 - data buffer */\r
221/* RPMR - 176724 - maintenace register */\r
222/* RPDT - 176726 - drive type */\r
223/* RPSN - 176730 - serial number */\r
224\r
225/* RPOF - 176732 - offset register */\r
226\r
227#define OF_HCI 0002000 /* hdr cmp inh NI */\r
228#define OF_ECI 0004000 /* ECC inhibit NI */\r
229#define OF_F22 0010000 /* format NI */\r
230#define OF_MBZ 0161400\r
231\r
232/* RPDC - 176734 - desired cylinder */\r
233\r
234#define DC_V_CY 0 /* cylinder pos */\r
235#define DC_M_CY 01777 /* cylinder mask */\r
236#define DC_MBZ 0176000\r
237#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY)\r
238#define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \\r
239 GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs))\r
240\r
241/* RPCC - 176736 - current cylinder */\r
242/* RPER2 - 176740 - error status 2 - drive unsafe conditions - unimplemented */\r
243/* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */\r
244/* RPEC1 - 176744 - ECC status 1 - unimplemented */\r
245/* RPEC2 - 176746 - ECC status 2 - unimplemented */\r
246\r
247/* This controller supports many different disk drive types. These drives\r
248 are operated in 576 bytes/sector (128 36b words/sector) mode, which gives\r
249 them somewhat different geometry from the PDP-11 variants:\r
250\r
251 type #sectors/ #surfaces/ #cylinders/\r
252 surface cylinder drive\r
253\r
254 RM02/3 30 5 823 =67MB\r
255 RP04/5 20 19 411 =88MB\r
256 RM80 30 14 559 =124MB\r
257 RP06 20 19 815 =176MB\r
258 RM05 30 19 823 =256MB\r
259 RP07 43 32 630 =516MB\r
260\r
261 In theory, each drive can be a different type. The size field in\r
262 each unit selects the drive capacity for each drive and thus the\r
263 drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.\r
264\r
265 The RP07, despite its name, uses an RM-style controller.\r
266*/\r
267\r
268#define RM03_DTYPE 0\r
269#define RM03_SECT 30\r
270#define RM03_SURF 5\r
271#define RM03_CYL 823\r
272#define RM03_DEV 020024\r
273#define RM03_SIZE (RM03_SECT * RM03_SURF * RM03_CYL * RP_NUMWD)\r
274\r
275#define RP04_DTYPE 1\r
276#define RP04_SECT 20\r
277#define RP04_SURF 19\r
278#define RP04_CYL 411\r
279#define RP04_DEV 020020\r
280#define RP04_SIZE (RP04_SECT * RP04_SURF * RP04_CYL * RP_NUMWD)\r
281\r
282#define RM80_DTYPE 2\r
283#define RM80_SECT 30\r
284#define RM80_SURF 14\r
285#define RM80_CYL 559\r
286#define RM80_DEV 020026\r
287#define RM80_SIZE (RM80_SECT * RM80_SURF * RM80_CYL * RP_NUMWD)\r
288\r
289#define RP06_DTYPE 3\r
290#define RP06_SECT 20\r
291#define RP06_SURF 19\r
292#define RP06_CYL 815\r
293#define RP06_DEV 020022\r
294#define RP06_SIZE (RP06_SECT * RP06_SURF * RP06_CYL * RP_NUMWD)\r
295\r
296#define RM05_DTYPE 4\r
297#define RM05_SECT 30\r
298#define RM05_SURF 19\r
299#define RM05_CYL 823\r
300#define RM05_DEV 020027\r
301#define RM05_SIZE (RM05_SECT * RM05_SURF * RM05_CYL * RP_NUMWD)\r
302\r
303#define RP07_DTYPE 5\r
304#define RP07_SECT 43\r
305#define RP07_SURF 32\r
306#define RP07_CYL 630\r
307#define RP07_DEV 020042\r
308#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD)\r
309\r
310struct drvtyp {\r
311 int32 sect; /* sectors */\r
312 int32 surf; /* surfaces */\r
313 int32 cyl; /* cylinders */\r
314 int32 size; /* #blocks */\r
315 int32 devtype; /* device type */\r
316 int32 ctrl; /* ctrl type */\r
317 };\r
318\r
319struct drvtyp drv_tab[] = {\r
320 { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, MBA_RM_CTRL },\r
321 { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, MBA_RP_CTRL },\r
322 { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, MBA_RM_CTRL },\r
323 { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, MBA_RP_CTRL },\r
324 { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, MBA_RM_CTRL },\r
325 { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, MBA_RM_CTRL },\r
326 { 0 }\r
327 };\r
328\r
329extern d10 *M; /* memory */\r
330extern int32 int_req;\r
331extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */\r
332extern int32 ubcs[UBANUM];\r
333extern UNIT cpu_unit;\r
334\r
335int32 rpcs1 = 0; /* control/status 1 */\r
336int32 rpwc = 0; /* word count */\r
337int32 rpba = 0; /* bus address */\r
338int32 rpcs2 = 0; /* control/status 2 */\r
339int32 rpdb = 0; /* data buffer */\r
340uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */\r
341uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */\r
342uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */\r
343uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */\r
344uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */\r
345uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */\r
346uint16 rpof[RP_NUMDR] = { 0 }; /* offset */\r
347uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */\r
348uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */\r
349uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */\r
350uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */\r
351uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */\r
352int32 rpiff = 0; /* INTR flip/flop */\r
353int32 rp_stopioe = 1; /* stop on error */\r
354int32 rp_swait = 10; /* seek time */\r
355int32 rp_rwait = 10; /* rotate time */\r
356static int32 reg_in_drive[32] = {\r
357 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1,\r
358 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
359 };\r
360\r
361t_stat rp_rd (int32 *data, int32 PA, int32 access);\r
362t_stat rp_wr (int32 data, int32 PA, int32 access);\r
363int32 rp_inta (void);\r
364t_stat rp_svc (UNIT *uptr);\r
365t_stat rp_reset (DEVICE *dptr);\r
366t_stat rp_boot (int32 unitno, DEVICE *dptr);\r
367t_stat rp_attach (UNIT *uptr, char *cptr);\r
368t_stat rp_detach (UNIT *uptr);\r
369void set_rper (int32 flag, int32 drv);\r
370void update_rpcs (int32 flags, int32 drv);\r
371void rp_go (int32 drv, int32 fnc);\r
372t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
373\r
374/* RP data structures\r
375\r
376 rp_dev RP device descriptor\r
377 rp_unit RP unit list\r
378 rp_reg RP register list\r
379 rp_mod RP modifier list\r
380*/\r
381\r
382DIB rp_dib = {\r
383 IOBA_RP, IOLN_RP, &rp_rd, &rp_wr,\r
384 1, IVCL (RP), VEC_RP, { &rp_inta }\r
385 };\r
386\r
387UNIT rp_unit[] = {\r
388 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
389 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
390 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
391 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
392 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
393 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
394 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
395 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
396 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
397 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
398 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
399 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
400 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
401 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },\r
402 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+\r
403 UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }\r
404 };\r
405\r
406REG rp_reg[] = {\r
407 { ORDATA (RPCS1, rpcs1, 16) },\r
408 { ORDATA (RPWC, rpwc, 16) },\r
409 { ORDATA (RPBA, rpba, 16) },\r
410 { ORDATA (RPCS2, rpcs2, 16) },\r
411 { ORDATA (RPDB, rpdb, 16) },\r
412 { BRDATA (RPDA, rpda, 8, 16, RP_NUMDR) },\r
413 { BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) },\r
414 { BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) },\r
415 { BRDATA (RPHR, rmhr, 8, 16, RP_NUMDR) },\r
416 { BRDATA (RPOF, rpof, 8, 16, RP_NUMDR) },\r
417 { BRDATA (RPDC, rpdc, 8, 16, RP_NUMDR) },\r
418 { BRDATA (RPER2, rper2, 8, 16, RP_NUMDR) },\r
419 { BRDATA (RPER3, rper3, 8, 16, RP_NUMDR) },\r
420 { BRDATA (RPEC1, rpec1, 8, 16, RP_NUMDR) },\r
421 { BRDATA (RPEC2, rpec2, 8, 16, RP_NUMDR) },\r
422 { BRDATA (RMMR, rpmr, 8, 16, RP_NUMDR) },\r
423 { BRDATA (RMMR2, rmmr2, 8, 16, RP_NUMDR) },\r
424 { FLDATA (IFF, rpiff, 0) },\r
425 { FLDATA (INT, int_req, INT_V_RP) },\r
426 { FLDATA (SC, rpcs1, CSR_V_ERR) },\r
427 { FLDATA (DONE, rpcs1, CSR_V_DONE) },\r
428 { FLDATA (IE, rpcs1, CSR_V_IE) },\r
429 { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT },\r
430 { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT },\r
431 { URDATA (FNC, rp_unit[0].FUNC, 8, 5, 0, RP_NUMDR, REG_HRO) },\r
432 { URDATA (CAPAC, rp_unit[0].capac, 10, T_ADDR_W, 0,\r
433 RP_NUMDR, PV_LEFT | REG_HRO) },\r
434 { FLDATA (STOP_IOE, rp_stopioe, 0) },\r
435 { NULL }\r
436 };\r
437\r
438MTAB rp_mod[] = {\r
439 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
440 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r
441 { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
442 "RM03", NULL, NULL },\r
443 { (UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
444 "RP04", NULL, NULL },\r
445 { (UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
446 "RM80", NULL, NULL },\r
447 { (UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
448 "RP06", NULL, NULL },\r
449 { (UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
450 "RM05", NULL, NULL },\r
451 { (UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
452 "RP07", NULL, NULL },\r
453 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE),\r
454 "RM03", NULL, NULL },\r
455 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE),\r
456 "RP04", NULL, NULL },\r
457 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE),\r
458 "RM80", NULL, NULL },\r
459 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE),\r
460 "RP06", NULL, NULL },\r
461 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE),\r
462 "RM05", NULL, NULL },\r
463 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE),\r
464 "RP07", NULL, NULL },\r
465 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },\r
466 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },\r
467 { (UNIT_AUTO+UNIT_DTYPE), (RM03_DTYPE << UNIT_V_DTYPE),\r
468 NULL, "RM03", &rp_set_size },\r
469 { (UNIT_AUTO+UNIT_DTYPE), (RP04_DTYPE << UNIT_V_DTYPE),\r
470 NULL, "RP04", &rp_set_size }, \r
471 { (UNIT_AUTO+UNIT_DTYPE), (RM80_DTYPE << UNIT_V_DTYPE),\r
472 NULL, "RM80", &rp_set_size },\r
473 { (UNIT_AUTO+UNIT_DTYPE), (RP06_DTYPE << UNIT_V_DTYPE),\r
474 NULL, "RP06", &rp_set_size },\r
475 { (UNIT_AUTO+UNIT_DTYPE), (RM05_DTYPE << UNIT_V_DTYPE),\r
476 NULL, "RM05", &rp_set_size },\r
477 { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE),\r
478 NULL, "RP07", &rp_set_size },\r
479 { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,\r
480 NULL, &show_addr, NULL },\r
481 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,\r
482 NULL, &show_vec, NULL },\r
483 { 0 }\r
484 };\r
485\r
486DEVICE rp_dev = {\r
487 "RP", rp_unit, rp_reg, rp_mod,\r
488 RP_NUMDR, 8, 30, 1, 8, 36,\r
489 NULL, NULL, &rp_reset,\r
490 &rp_boot, &rp_attach, &rp_detach,\r
491 &rp_dib, DEV_UBUS\r
492 };\r
493\r
494/* I/O dispatch routines, I/O addresses 17776700 - 17776776 */\r
495\r
496t_stat rp_rd (int32 *data, int32 PA, int32 access)\r
497{\r
498int32 drv, dtype, i, j;\r
499\r
500drv = GET_UNIT (rpcs2); /* get current unit */\r
501dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */\r
502j = (PA >> 1) & 037; /* get reg offset */\r
503if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */\r
504 rpcs2 = rpcs2 | CS2_NED; /* set error flag */\r
505 update_rpcs (CS1_SC, drv); /* request intr */\r
506 *data = 0;\r
507 return SCPE_OK;\r
508 }\r
509\r
510update_rpcs (0, drv); /* update status */\r
511switch (j) { /* decode PA<5:1> */\r
512\r
513 case 000: /* RPCS1 */\r
514 *data = rpcs1;\r
515 break;\r
516\r
517 case 001: /* RPWC */\r
518 *data = rpwc;\r
519 break;\r
520\r
521 case 002: /* RPBA */\r
522 *data = rpba = rpba & ~BA_MBZ;\r
523 break;\r
524\r
525 case 003: /* RPDA */\r
526 *data = rpda[drv] = rpda[drv] & ~DA_MBZ;\r
527 break;\r
528\r
529 case 004: /* RPCS2 */\r
530 *data = rpcs2 = (rpcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;\r
531 break;\r
532\r
533 case 005: /* RPDS */\r
534 *data = rpds[drv];\r
535 break;\r
536\r
537 case 006: /* RPER1 */\r
538 *data = rper1[drv];\r
539 break;\r
540\r
541 case 007: /* RPAS */\r
542 *data = 0;\r
543 for (i = 0; i < RP_NUMDR; i++)\r
544 if (rpds[i] & DS_ATA) *data = *data | (AS_U0 << i);\r
545 break;\r
546\r
547 case 010: /* RPLA */\r
548 *data = GET_SECTOR (rp_rwait, dtype) << LA_V_SC;\r
549 break;\r
550\r
551 case 011: /* RPDB */\r
552 *data = rpdb;\r
553 break;\r
554\r
555 case 012: /* RPMR */\r
556 *data = rpmr[drv];\r
557 break;\r
558\r
559 case 013: /* RPDT */\r
560 *data = drv_tab[dtype].devtype;\r
561 break;\r
562\r
563 case 014: /* RPSN */\r
564 *data = 020 | (drv + 1);\r
565 break;\r
566\r
567 case 015: /* RPOF */\r
568 *data = rpof[drv] = rpof[drv] & ~OF_MBZ;\r
569 break;\r
570\r
571 case 016: /* RPDC */\r
572 *data = rpdc[drv] = rpdc[drv] & ~DC_MBZ;\r
573 break;\r
574\r
575 case 017: /* RPCC, RMHR */\r
576 if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is CC */\r
577 *data = rp_unit[drv].CYL;\r
578 else *data = rmhr[drv] ^ 0177777; /* RM is HR */\r
579 break;\r
580\r
581 case 020: /* RPER2, RMMR2 */\r
582 if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER2 */\r
583 *data = rper2[drv];\r
584 else *data = rmmr2[drv]; /* RM is MR2 */\r
585 break;\r
586\r
587 case 021: /* RPER3, RMER2 */\r
588 if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER3 */\r
589 *data = rper3[drv];\r
590 else *data = rper2[drv]; /* RM is ER2 */\r
591 break;\r
592\r
593 case 022: /* RPEC1 */\r
594 *data = rpec1[drv];\r
595 break;\r
596\r
597 case 023: /* RPEC2 */\r
598 *data = rpec2[drv];\r
599 break;\r
600\r
601 default: /* all others */\r
602 set_rper (ER1_ILR, drv);\r
603 update_rpcs (0, drv);\r
604 break;\r
605 }\r
606return SCPE_OK;\r
607}\r
608\r
609t_stat rp_wr (int32 data, int32 PA, int32 access)\r
610{\r
611int32 cs1f, drv, dtype, i, j;\r
612UNIT *uptr;\r
613\r
614cs1f = 0; /* no int on cs1 upd */\r
615drv = GET_UNIT (rpcs2); /* get current unit */\r
616dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */\r
617uptr = rp_dev.units + drv; /* get unit */\r
618j = (PA >> 1) & 037; /* get reg offset */\r
619if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */\r
620 rpcs2 = rpcs2 | CS2_NED; /* set error flag */\r
621 update_rpcs (CS1_SC, drv); /* request intr */\r
622 return SCPE_OK;\r
623 }\r
624if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */\r
625 set_rper (ER1_RMR, drv); /* won't write */\r
626 update_rpcs (0, drv);\r
627 return SCPE_OK;\r
628 }\r
629rmhr[drv] = data;\r
630\r
631switch (j) { /* decode PA<5:1> */\r
632\r
633 case 000: /* RPCS1 */\r
634 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
635 if (data & CS1_TRE) { /* error clear? */\r
636 rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1<TRE> */\r
637 rpcs2 = rpcs2 & ~CS2_ERR; /* clr CS2<15:8> */\r
638 }\r
639 if ((access == WRITE) || (PA & 1)) { /* hi byte write? */\r
640 if (rpcs1 & CS1_DONE) /* done set? */\r
641 rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE);\r
642 }\r
643 if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */\r
644 if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */\r
645 rpiff = 1; /* set CSTB INTR */\r
646 rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE);\r
647 if (uptr->flags & UNIT_DIS) { /* nx disk? */\r
648 rpcs2 = rpcs2 | CS2_NED; /* set error flag */\r
649 cs1f = CS1_SC; /* req interrupt */\r
650 }\r
651 else if (sim_is_active (uptr))\r
652 set_rper (ER1_RMR, drv); /* won't write */\r
653 else if (data & CS1_GO) { /* start op */\r
654 uptr->FUNC = GET_FNC (data); /* set func */\r
655 if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */\r
656 ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */\r
657 rpcs2 = rpcs2 | CS2_PGE;\r
658 else rp_go (drv, uptr->FUNC);\r
659 }\r
660 }\r
661 break; \r
662\r
663 case 001: /* RPWC */\r
664 if (access == WRITEB) data = (PA & 1)?\r
665 (rpwc & 0377) | (data << 8): (rpwc & ~0377) | data;\r
666 rpwc = data;\r
667 break;\r
668\r
669 case 002: /* RPBA */\r
670 if (access == WRITEB) data = (PA & 1)?\r
671 (rpba & 0377) | (data << 8): (rpba & ~0377) | data;\r
672 rpba = data & ~BA_MBZ;\r
673 break;\r
674\r
675 case 003: /* RPDA */\r
676 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
677 rpda[drv] = data & ~DA_MBZ;\r
678 break;\r
679\r
680 case 004: /* RPCS2 */\r
681 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
682 if (data & CS2_CLR) rp_reset (&rp_dev); /* init? */\r
683 else {\r
684 if ((data & ~rpcs2) & (CS2_PE | CS2_MXF))\r
685 cs1f = CS1_SC; /* diagn intr */\r
686 if (access == WRITEB) data = (rpcs2 & /* merge data */\r
687 ((PA & 1)? 0377: 0177400)) | data;\r
688 rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR;\r
689 }\r
690 drv = GET_UNIT (rpcs2);\r
691 break;\r
692\r
693 case 006: /* RPER1 */\r
694 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
695 rper1[drv] = data;\r
696 break;\r
697\r
698 case 007: /* RPAS */\r
699 if ((access == WRITEB) && (PA & 1)) break;\r
700 for (i = 0; i < RP_NUMDR; i++)\r
701 if (data & (AS_U0 << i)) rpds[i] = rpds[i] & ~DS_ATA;\r
702 break;\r
703\r
704 case 011: /* RPDB */\r
705 if (access == WRITEB) data = (PA & 1)?\r
706 (rpdb & 0377) | (data << 8): (rpdb & ~0377) | data;\r
707 rpdb = data;\r
708 break;\r
709\r
710 case 012: /* RPMR */\r
711 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
712 rpmr[drv] = data;\r
713 break;\r
714\r
715 case 015: /* RPOF */\r
716 rpof[drv] = data & ~OF_MBZ;\r
717 break;\r
718\r
719 case 016: /* RPDC */\r
720 if ((access == WRITEB) && (PA & 1)) data = data << 8;\r
721 rpdc[drv] = data & ~DC_MBZ;\r
722 break;\r
723\r
724 case 005: /* RPDS */\r
725 case 010: /* RPLA */\r
726 case 013: /* RPDT */\r
727 case 014: /* RPSN */\r
728 case 017: /* RPCC, RMHR */\r
729 case 020: /* RPER2, RMMR2 */\r
730 case 021: /* RPER3, RMER2 */\r
731 case 022: /* RPEC1 */\r
732 case 023: /* RPEC2 */\r
733 break; /* read only */\r
734\r
735 default: /* all others */\r
736 set_rper (ER1_ILR, drv);\r
737 break;\r
738 } /* end switch */\r
739\r
740update_rpcs (cs1f, drv); /* update status */\r
741return SCPE_OK;\r
742}\r
743\r
744/* Initiate operation - unit not busy, function set */\r
745\r
746void rp_go (int32 drv, int32 fnc)\r
747{\r
748int32 dc, dtype, t;\r
749UNIT *uptr;\r
750\r
751uptr = rp_dev.units + drv; /* get unit */\r
752if (uptr->flags & UNIT_DIS) { /* nx unit? */\r
753 rpcs2 = rpcs2 | CS2_NED; /* set error flag */\r
754 update_rpcs (CS1_SC, drv); /* request intr */\r
755 return;\r
756 }\r
757if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */\r
758 set_rper (ER1_ILF, drv); /* set err, ATN */\r
759 update_rpcs (CS1_SC, drv); /* request intr */\r
760 return;\r
761 }\r
762dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
763rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */\r
764dc = rpdc[drv]; /* assume seek, sch */\r
765\r
766switch (fnc) { /* case on function */\r
767\r
768 case FNC_DCLR: /* drive clear */\r
769 rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */\r
770 rpec2[drv] = 0; /* clear EC2 */\r
771 if (drv_tab[dtype].ctrl == MBA_RM_CTRL) /* RM? */\r
772 rpmr[drv] = 0; /* clear maint */\r
773 else rpec1[drv] = 0; /* RP, clear EC1 */\r
774 case FNC_NOP: /* no operation */\r
775 case FNC_RELEASE: /* port release */\r
776 return;\r
777\r
778 case FNC_PRESET: /* read-in preset */\r
779 rpdc[drv] = 0; /* clear disk addr */\r
780 rpda[drv] = 0;\r
781 rpof[drv] = 0; /* clear offset */\r
782 case FNC_PACK: /* pack acknowledge */\r
783 rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */\r
784 return;\r
785\r
786 case FNC_OFFSET: /* offset mode */\r
787 case FNC_RETURN:\r
788 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
789 set_rper (ER1_UNS, drv); /* unsafe */\r
790 break;\r
791 }\r
792 rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */\r
793 sim_activate (uptr, rp_swait); /* time operation */\r
794 return;\r
795\r
796 case FNC_UNLOAD: /* unload */\r
797 case FNC_RECAL: /* recalibrate */\r
798 dc = 0; /* seek to 0 */\r
799 case FNC_SEEK: /* seek */\r
800 case FNC_SEARCH: /* search */\r
801 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
802 set_rper (ER1_UNS, drv); /* unsafe */\r
803 break;\r
804 }\r
805 if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */\r
806 (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */\r
807 (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */\r
808 set_rper (ER1_IAE, drv);\r
809 break;\r
810 }\r
811 rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */\r
812 t = abs (dc - uptr->CYL); /* cyl diff */\r
813 if (t == 0) t = 1; /* min time */\r
814 sim_activate (uptr, rp_swait * t); /* schedule */\r
815 uptr->CYL = dc; /* save cylinder */\r
816 return;\r
817\r
818 case FNC_WRITEH: /* write headers */\r
819 case FNC_WRITE: /* write */\r
820 case FNC_WCHK: /* write check */\r
821 case FNC_READ: /* read */\r
822 case FNC_READH: /* read headers */\r
823 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
824 set_rper (ER1_UNS, drv); /* unsafe */\r
825 break;\r
826 }\r
827 rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */\r
828 rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE);\r
829 if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */\r
830 (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */\r
831 (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */\r
832 set_rper (ER1_IAE, drv);\r
833 break;\r
834 }\r
835 rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */\r
836 sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL)));\r
837 uptr->CYL = dc; /* save cylinder */\r
838 return;\r
839\r
840 default: /* all others */\r
841 set_rper (ER1_ILF, drv); /* not supported */\r
842 break;\r
843 }\r
844\r
845update_rpcs (CS1_SC, drv); /* req intr */\r
846return;\r
847}\r
848\r
849/* Service unit timeout\r
850\r
851 Complete movement or data transfer command\r
852 Unit must exist - can't remove an active unit\r
853 Unit must be attached - detach cancels in progress operations\r
854*/\r
855\r
856t_stat rp_svc (UNIT *uptr)\r
857{\r
858int32 i, dtype, drv, err;\r
859int32 ba, da, vpn;\r
860a10 pa10, mpa10;\r
861int32 wc10, twc10, awc10, fc10;\r
862static d10 dbuf[RP_MAXFR];\r
863\r
864dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
865drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
866rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */\r
867\r
868switch (uptr->FUNC) { /* case on function */\r
869\r
870 case FNC_OFFSET: /* offset */\r
871 rpds[drv] = rpds[drv] | DS_OF | DS_ATA; /* set offset, attention */\r
872 update_rpcs (CS1_SC, drv);\r
873 break;\r
874\r
875 case FNC_RETURN: /* return to centerline */\r
876 rpds[drv] = (rpds[drv] & ~DS_OF) | DS_ATA; /* clear offset, set attn */\r
877 update_rpcs (CS1_SC, drv);\r
878 break; \r
879\r
880 case FNC_UNLOAD: /* unload */\r
881 rp_detach (uptr); /* detach unit */\r
882 break;\r
883\r
884 case FNC_RECAL: /* recalibrate */\r
885 case FNC_SEARCH: /* search */\r
886 case FNC_SEEK: /* seek */\r
887 rpds[drv] = rpds[drv] | DS_ATA; /* set attention */\r
888 update_rpcs (CS1_SC, drv);\r
889 break;\r
890\r
891/* Reads and writes must take into account the complicated relationship\r
892 between Unibus addresses and PDP-10 memory addresses, and Unibus\r
893 byte and word counts, PDP-10 UBA word counts, and simulator PDP-10\r
894 word counts (due to the fact that the simulator must transfer eight\r
895 8b bytes to do a 36b transfer, whereas the UBA did four 9b bytes).\r
896*/\r
897\r
898#define XWC_MBZ 0000001 /* wc<0> must be 0 */\r
899#define XBA_MBZ 0000003 /* addr<1:0> must be 0 */\r
900\r
901 case FNC_WRITE: /* write */\r
902 if (uptr->flags & UNIT_WPRT) { /* write locked? */\r
903 set_rper (ER1_WLE, drv); /* set drive error */\r
904 update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */\r
905 break;\r
906 }\r
907 case FNC_WCHK: /* write check */\r
908 case FNC_READ: /* read */\r
909 case FNC_READH: /* read headers */\r
910 ba = GET_UAE (rpcs1) | rpba; /* get byte addr */\r
911 wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */\r
912 da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */\r
913 if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */\r
914 set_rper (ER1_AOE, drv);\r
915 if (wc10 > (drv_tab[dtype].size - da))\r
916 wc10 = drv_tab[dtype].size - da;\r
917 }\r
918\r
919 err = fseek (uptr->fileref, da * sizeof (d10), SEEK_SET);\r
920 if (uptr->FUNC == FNC_WRITE) { /* write? */\r
921 for (twc10 = 0; twc10 < wc10; twc10++) {\r
922 pa10 = ba >> 2;\r
923 vpn = PAG_GETVPN (pa10); /* map addr */\r
924 if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) ||\r
925 ((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) {\r
926 rpcs2 = rpcs2 | CS2_NEM; /* set error */\r
927 ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */\r
928 break;\r
929 }\r
930 mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK;\r
931 if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */\r
932 rpcs2 = rpcs2 | CS2_NEM; /* set error */\r
933 ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */\r
934 break;\r
935 }\r
936 dbuf[twc10] = M[mpa10]; /* write to disk */\r
937 if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4;\r
938 }\r
939 if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */\r
940 fc10 = RP_NUMWD - fc10;\r
941 for (i = 0; i < fc10; i++) dbuf[twc10 + i] = 0;\r
942 }\r
943 fxwrite (dbuf, sizeof (d10), twc10 + fc10, uptr->fileref);\r
944 err = ferror (uptr->fileref);\r
945 } /* end if */\r
946 else { /* read, wchk, readh */\r
947 awc10 = fxread (dbuf, sizeof (d10), wc10, uptr->fileref);\r
948 err = ferror (uptr->fileref);\r
949 for ( ; awc10 < wc10; awc10++) dbuf[awc10] = 0;\r
950 for (twc10 = 0; twc10 < wc10; twc10++) {\r
951 pa10 = ba >> 2;\r
952 vpn = PAG_GETVPN (pa10); /* map addr */\r
953 if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) ||\r
954 ((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) {\r
955 rpcs2 = rpcs2 | CS2_NEM; /* set error */\r
956 ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */\r
957 break;\r
958 }\r
959 mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK;\r
960 if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */\r
961 rpcs2 = rpcs2 | CS2_NEM; /* set error */\r
962 ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */\r
963 break;\r
964 }\r
965 if ((uptr->FUNC == FNC_READ) || /* read or */\r
966 (uptr->FUNC == FNC_READH)) /* read header */\r
967 M[mpa10] = dbuf[twc10];\r
968 else if (M[mpa10] != dbuf[twc10]) { /* wchk, mismatch? */\r
969 rpcs2 = rpcs2 | CS2_WCE; /* set error */\r
970 break;\r
971 }\r
972 if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4;\r
973 }\r
974 } /* end else */\r
975\r
976 rpwc = (rpwc + (twc10 << 1)) & 0177777; /* final word count */\r
977 rpba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */\r
978 rpcs1 = (rpcs1 & ~ CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE);\r
979 da = da + twc10 + (RP_NUMWD - 1);\r
980 if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;\r
981 da = da / RP_NUMWD;\r
982 rpda[drv] = da % drv_tab[dtype].sect;\r
983 da = da / drv_tab[dtype].sect;\r
984 rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF);\r
985 rpdc[drv] = da / drv_tab[dtype].surf;\r
986\r
987 if (err != 0) { /* error? */\r
988 set_rper (ER1_PAR, drv); /* set drive error */\r
989 update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */\r
990 perror ("RP I/O error");\r
991 clearerr (uptr->fileref);\r
992 return SCPE_IOERR;\r
993 }\r
994\r
995 case FNC_WRITEH: /* write headers stub */\r
996 update_rpcs (CS1_DONE, drv); /* set done */\r
997 break;\r
998 } /* end case func */\r
999\r
1000return SCPE_OK;\r
1001}\r
1002\r
1003/* Set drive error */\r
1004\r
1005void set_rper (int32 flag, int32 drv)\r
1006{\r
1007rper1[drv] = rper1[drv] | flag;\r
1008rpds[drv] = rpds[drv] | DS_ATA;\r
1009rpcs1 = rpcs1 | CS1_SC;\r
1010return;\r
1011}\r
1012\r
1013/* Controller status update\r
1014\r
1015 Check for done transition\r
1016 Update drive status\r
1017 Update RPCS1\r
1018 Update interrupt request\r
1019*/\r
1020\r
1021void update_rpcs (int32 flag, int32 drv)\r
1022{\r
1023int32 i;\r
1024UNIT *uptr;\r
1025\r
1026if ((flag & ~rpcs1) & CS1_DONE) /* DONE 0 to 1? */\r
1027 rpiff = (rpcs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */\r
1028uptr = rp_dev.units + drv; /* get unit */\r
1029if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;\r
1030else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;\r
1031if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;\r
1032else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);\r
1033if (rper1[drv] | rper2[drv] | rper3[drv])\r
1034 rpds[drv] = rpds[drv] | DS_ERR;\r
1035else rpds[drv] = rpds[drv] & ~DS_ERR;\r
1036\r
1037rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag;\r
1038rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC);\r
1039if (sim_is_active (uptr)) rpcs1 = rpcs1 | CS1_GO;\r
1040if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC;\r
1041else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC;\r
1042for (i = 0; i < RP_NUMDR; i++)\r
1043 if (rpds[i] & DS_ATA) rpcs1 = rpcs1 | CS1_SC;\r
1044if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE)))\r
1045 int_req = int_req | INT_RP;\r
1046else int_req = int_req & ~INT_RP;\r
1047return;\r
1048}\r
1049\r
1050/* Interrupt acknowledge */\r
1051\r
1052int32 rp_inta (void)\r
1053{\r
1054rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */\r
1055rpiff = 0; /* clear CSTB INTR */\r
1056return VEC_RP; /* acknowledge */\r
1057}\r
1058\r
1059/* Device reset */\r
1060\r
1061t_stat rp_reset (DEVICE *dptr)\r
1062{\r
1063int32 i;\r
1064UNIT *uptr;\r
1065\r
1066rpcs1 = CS1_DVA | CS1_DONE;\r
1067rpcs2 = CS2_IR | CS2_OR;\r
1068rpba = rpwc = 0;\r
1069rpiff = 0; /* clear CSTB INTR */\r
1070int_req = int_req & ~INT_RP; /* clear intr req */\r
1071for (i = 0; i < RP_NUMDR; i++) {\r
1072 uptr = rp_dev.units + i;\r
1073 sim_cancel (uptr);\r
1074 uptr->CYL = uptr->FUNC = 0;\r
1075 if (uptr->flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) |\r
1076 DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r
1077 else if (uptr->flags & UNIT_DIS) rpds[i] = 0;\r
1078 else rpds[i] = DS_DPR;\r
1079 rper1[i] = 0;\r
1080 rper2[i] = 0;\r
1081 rper3[i] = 0;\r
1082 rpda[i] = 0;\r
1083 rpdc[i] = 0;\r
1084 rpmr[i] = 0;\r
1085 rpof[i] = 0;\r
1086 rpec1[i] = 0;\r
1087 rpec2[i] = 0;\r
1088 rmmr2[i] = 0;\r
1089 rmhr[i] = 0;\r
1090 }\r
1091return SCPE_OK;\r
1092}\r
1093\r
1094/* Device attach */\r
1095\r
1096t_stat rp_attach (UNIT *uptr, char *cptr)\r
1097{\r
1098int32 drv, i, p;\r
1099t_stat r;\r
1100\r
1101uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;\r
1102r = attach_unit (uptr, cptr);\r
1103if (r != SCPE_OK) return r;\r
1104drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
1105rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR |\r
1106 ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r
1107rper1[drv] = 0;\r
1108update_rpcs (CS1_SC, drv);\r
1109\r
1110if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */\r
1111if ((p = sim_fsize (uptr->fileref)) == 0) return SCPE_OK;\r
1112for (i = 0; drv_tab[i].sect != 0; i++) {\r
1113 if (p <= (drv_tab[i].size * (int) sizeof (d10))) {\r
1114 uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);\r
1115 uptr->capac = drv_tab[i].size;\r
1116 return SCPE_OK;\r
1117 }\r
1118 }\r
1119return SCPE_OK;\r
1120}\r
1121\r
1122/* Device detach */\r
1123\r
1124t_stat rp_detach (UNIT *uptr)\r
1125{\r
1126int32 drv;\r
1127\r
1128if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r
1129drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
1130rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) |\r
1131 DS_ATA;\r
1132if (sim_is_active (uptr)) { /* unit active? */\r
1133 sim_cancel (uptr); /* cancel operation */\r
1134 rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */\r
1135 if (uptr->FUNC >= FNC_WCHK) /* data transfer? */\r
1136 rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */\r
1137 }\r
1138update_rpcs (CS1_SC, drv); /* request intr */\r
1139return detach_unit (uptr);\r
1140}\r
1141\r
1142/* Set size command validation routine */\r
1143\r
1144t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1145{\r
1146int32 dtype = GET_DTYPE (val);\r
1147\r
1148if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
1149uptr->capac = drv_tab[dtype].size;\r
1150return SCPE_OK;\r
1151}\r
1152\r
1153/* Device bootstrap */\r
1154\r
1155#define BOOT_START 0377000 /* start */\r
1156#define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10))\r
1157\r
1158static const d10 boot_rom_dec[] = {\r
1159 0515040000001, /* boot:hrlzi 1,1 ; uba # */\r
1160 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */\r
1161 0713001000000+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */\r
1162 0435040000000+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */\r
1163 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */\r
1164 0201000000040, /* movei 0,40 ; ctrl reset */\r
1165 0713001000010, /* wrio 0,10(1) ; ->RPCS2 */\r
1166 0201000000021, /* movei 0,21 ; preset */\r
1167 0713001000000, /* wrio 0,0(1) ; ->RPCS1 */\r
1168 0201100000001, /* movei 2,1 ; blk #1 */\r
1169 0265740377032, /* jsp 17,rdbl ; read */\r
1170 0204140001000, /* movs 3,1000 ; id word */\r
1171 0306140505755, /* cain 3,sixbit /HOM/ */\r
1172 0254000377023, /* jrst .+6 ; match */\r
1173 0201100000010, /* movei 2,10 ; blk #10 */\r
1174 0265740377032, /* jsp 17,rdbl ; read */\r
1175 0204140001000, /* movs 3,1000 ; id word */\r
1176 0302140505755, /* caie 3,sixbit /HOM/ */\r
1177 0254200377022, /* halt . ; inv home */\r
1178 0336100001103, /* skipn 2,1103 ; pg of ptrs */\r
1179 0254200377024, /* halt . ; inv ptr */\r
1180 0265740377032, /* jsp 17,rdbl ; read */\r
1181 0336100001004, /* skipn 2,1004 ; mon boot */\r
1182 0254200377027, /* halt . ; inv ptr */\r
1183 0265740377032, /* jsp 17,rdbl ; read */\r
1184 0254000001000, /* jrst 1000 ; start */\r
1185 0201140176000, /* rdbl:movei 3,176000 ; wd cnt */\r
1186 0201200004000, /* movei 4,4000 ; addr */\r
1187 0200240000000+FE_UNIT, /* move 5,FE_UNIT ; unit */\r
1188 0200300000002, /* move 6,2 */\r
1189 0242300777750, /* lsh 6,-24. ; cyl */\r
1190 0713141000002, /* wrio 3,2(1) ; ->RPWC */\r
1191 0713201000004, /* wrio 4,4(1) ; ->RPBA */\r
1192 0713101000006, /* wrio 2,6(1) ; ->RPDA */\r
1193 0713241000010, /* wrio 5,10(1) ; ->RPCS2 */\r
1194 0713301000034, /* wrio 6,34(1) ; ->RPDC */\r
1195 0201000000071, /* movei 0,71 ; read+go */\r
1196 0713001000000, /* wrio 0,0(1) ; ->RPCS1 */\r
1197 0712341000000, /* rdio 7,0(1) ; read csr */\r
1198 0606340000200, /* trnn 7,200 ; test rdy */\r
1199 0254000377046, /* jrst .-2 ; loop */\r
1200 0602340100000, /* trne 7,100000 ; test err */\r
1201 0254200377052, /* halt */\r
1202 0254017000000, /* jrst 0(17) ; return */\r
1203 };\r
1204\r
1205static const d10 boot_rom_its[] = {\r
1206 0515040000001, /* boot:hrlzi 1,1 ; uba # */\r
1207 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */\r
1208 0715000000000+(IOBA_UBMAP+1 & RMASK), /* iowrq 0,763001 ; set ubmap */\r
1209 0435040000000+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */\r
1210 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */\r
1211 0201000000040, /* movei 0,40 ; ctrl reset */\r
1212 0715001000010, /* iowrq 0,10(1) ; ->RPCS2 */\r
1213 0201000000021, /* movei 0,21 ; preset */\r
1214 0715001000000, /* iowrq 0,0(1) ; ->RPCS1 */\r
1215 0201100000001, /* movei 2,1 ; blk #1 */\r
1216 0265740377032, /* jsp 17,rdbl ; read */\r
1217 0204140001000, /* movs 3,1000 ; id word */\r
1218 0306140505755, /* cain 3,sixbit /HOM/ */\r
1219 0254000377023, /* jrst .+6 ; match */\r
1220 0201100000010, /* movei 2,10 ; blk #10 */\r
1221 0265740377032, /* jsp 17,rdbl ; read */\r
1222 0204140001000, /* movs 3,1000 ; id word */\r
1223 0302140505755, /* caie 3,sixbit /HOM/ */\r
1224 0254200377022, /* halt . ; inv home */\r
1225 0336100001103, /* skipn 2,1103 ; pg of ptrs */\r
1226 0254200377024, /* halt . ; inv ptr */\r
1227 0265740377032, /* jsp 17,rdbl ; read */\r
1228 0336100001004, /* skipn 2,1004 ; mon boot */\r
1229 0254200377027, /* halt . ; inv ptr */\r
1230 0265740377032, /* jsp 17,rdbl ; read */\r
1231 0254000001000, /* jrst 1000 ; start */\r
1232 0201140176000, /* rdbl:movei 3,176000 ; wd cnt */\r
1233 0201200004000, /* movei 4,4000 ; addr */\r
1234 0200240000000+FE_UNIT, /* move 5,FE_UNIT ; unit */\r
1235 0200300000002, /* move 6,2 */\r
1236 0242300777750, /* lsh 6,-24. ; cyl */\r
1237 0715141000002, /* iowrq 3,2(1) ; ->RPWC */\r
1238 0715201000004, /* iowrq 4,4(1) ; ->RPBA */\r
1239 0715101000006, /* iowrq 2,6(1) ; ->RPDA */\r
1240 0715241000010, /* iowrq 5,10(1) ; ->RPCS2 */\r
1241 0715301000034, /* iowrq 6,34(1) ; ->RPDC */\r
1242 0201000000071, /* movei 0,71 ; read+go */\r
1243 0715001000000, /* iowrq 0,0(1) ; ->RPCS1 */\r
1244 0711341000000, /* iordq 7,0(1) ; read csr */\r
1245 0606340000200, /* trnn 7,200 ; test rdy */\r
1246 0254000377046, /* jrst .-2 ; loop */\r
1247 0602340100000, /* trne 7,100000 ; test err */\r
1248 0254200377052, /* halt */\r
1249 0254017000000, /* jrst 0(17) ; return */\r
1250 };\r
1251\r
1252t_stat rp_boot (int32 unitno, DEVICE *dptr)\r
1253{\r
1254int32 i;\r
1255extern a10 saved_PC;\r
1256\r
1257M[FE_UNIT] = unitno & CS2_M_UNIT;\r
1258for (i = 0; i < BOOT_LEN; i++)\r
1259 M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];\r
1260saved_PC = BOOT_START;\r
1261return SCPE_OK;\r
1262}\r