First Commit of my working state
[simh.git] / PDP11 / pdp11_rp.c
CommitLineData
196ba1fc
PH
1/* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 Massbus 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 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 17-May-07 RMS CS1 DVA resides in device, not MBA\r
29 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter\r
30 12-Nov-05 RMS Fixed DriveClear, does not clear disk address\r
31 16-Aug-05 RMS Fixed C++ declaration and cast problems\r
32 18-Mar-05 RMS Added attached test to detach routine\r
33 12-Sep-04 RMS Cloned from pdp11_rp.c\r
34\r
35 Note: The VMS driver and the RP controller documentation state that\r
36\r
37 ER2 = offset 8\r
38 SN = offset 12\r
39\r
40 But the TOPS-10 and TOPS-20 drivers, and the RP schematics state that\r
41\r
42 SN = offset 8\r
43 ER2 = offset 12\r
44\r
45 The simulation follows the schematics. The VMS drivers defines but does\r
46 not use these offsets, and the error logger follows the schematics.\r
47*/\r
48\r
49#if defined (VM_PDP10)\r
50#error "PDP-10 uses pdp10_rp.c!"\r
51\r
52#elif defined (VM_PDP11)\r
53#include "pdp11_defs.h"\r
54#define INIT_DTYPE RM03_DTYPE\r
55#define INIT_SIZE RM03_SIZE\r
56\r
57#elif defined (VM_VAX)\r
58#include "vax_defs.h"\r
59#define INIT_DTYPE RP06_DTYPE\r
60#define INIT_SIZE RP06_SIZE\r
61#define DMASK 0xFFFF\r
62#if (!UNIBUS)\r
63#error "Qbus not supported!"\r
64#endif\r
65\r
66#endif\r
67\r
68#include <math.h>\r
69\r
70#define RP_CTRL 0 /* ctrl is RP */\r
71#define RM_CTRL 1 /* ctrl is RM */\r
72#define RP_NUMDR 8 /* #drives */\r
73#define RP_NUMWD 256 /* words/sector */\r
74#define RP_MAXFR (1 << 16) /* max transfer */\r
75#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \\r
76 ((double) drv_tab[d].sect)))\r
77#define RM_OF (MBA_RMASK + 1)\r
78\r
79/* Flags in the unit flags word */\r
80\r
81#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */\r
82#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */\r
83#define UNIT_M_DTYPE 7\r
84#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */\r
85#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */\r
86#define UNIT_WLK (1 << UNIT_V_WLK)\r
87#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)\r
88#define UNIT_AUTO (1 << UNIT_V_AUTO)\r
89#define UNIT_DUMMY (1 << UNIT_V_DUMMY)\r
90#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)\r
91#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */\r
92\r
93/* Parameters in the unit descriptor */\r
94\r
95#define CYL u3 /* current cylinder */\r
96\r
97/* RPCS1, RMCS1 - control/status 1 - offset 0 */\r
98\r
99#define RP_CS1_OF 0\r
100#define RM_CS1_OF (0 + RM_OF)\r
101#define CS1_GO CSR_GO /* go */\r
102#define CS1_V_FNC 1 /* function pos */\r
103#define CS1_M_FNC 037 /* function mask */\r
104#define CS1_N_FNC (CS1_M_FNC + 1)\r
105#define FNC_NOP 000 /* no operation */\r
106#define FNC_UNLOAD 001 /* unload */\r
107#define FNC_SEEK 002 /* seek */\r
108#define FNC_RECAL 003 /* recalibrate */\r
109#define FNC_DCLR 004 /* drive clear */\r
110#define FNC_RELEASE 005 /* port release */\r
111#define FNC_OFFSET 006 /* offset */\r
112#define FNC_RETURN 007 /* return to center */\r
113#define FNC_PRESET 010 /* read-in preset */\r
114#define FNC_PACK 011 /* pack acknowledge */\r
115#define FNC_SEARCH 014 /* search */\r
116#define FNC_XFER 024 /* >=? data xfr */\r
117#define FNC_WCHK 024 /* write check */\r
118#define FNC_WRITE 030 /* write */\r
119#define FNC_WRITEH 031 /* write w/ headers */\r
120#define FNC_READ 034 /* read */\r
121#define FNC_READH 035 /* read w/ headers */\r
122#define CS1_RW 076\r
123#define CS1_DVA 04000 /* drive avail */\r
124#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)\r
125\r
126/* RPDS, RMDS - drive status - offset 1 */\r
127\r
128#define RP_DS_OF 1\r
129#define RM_DS_OF (1 + RM_OF)\r
130#define DS_OFM 0000001 /* offset mode */\r
131#define DS_VV 0000100 /* volume valid */\r
132#define DS_RDY 0000200 /* drive ready */\r
133#define DS_DPR 0000400 /* drive present */\r
134#define DS_PGM 0001000 /* programable NI */\r
135#define DS_LST 0002000 /* last sector */\r
136#define DS_WRL 0004000 /* write locked */\r
137#define DS_MOL 0010000 /* medium online */\r
138#define DS_PIP 0020000 /* pos in progress */\r
139#define DS_ERR 0040000 /* error */\r
140#define DS_ATA 0100000 /* attention active */\r
141#define DS_MBZ 0000076\r
142\r
143/* RPER1, RMER1 - error status 1 - offset 2 */\r
144\r
145#define RP_ER1_OF 2\r
146#define RM_ER1_OF (2 + RM_OF)\r
147#define ER1_ILF 0000001 /* illegal func */\r
148#define ER1_ILR 0000002 /* illegal register */\r
149#define ER1_RMR 0000004 /* reg mod refused */\r
150#define ER1_PAR 0000010 /* parity err */\r
151#define ER1_FER 0000020 /* format err NI */\r
152#define ER1_WCF 0000040 /* write clk fail NI */\r
153#define ER1_ECH 0000100 /* ECC hard err NI */\r
154#define ER1_HCE 0000200 /* hdr comp err NI */\r
155#define ER1_HCR 0000400 /* hdr CRC err NI */\r
156#define ER1_AOE 0001000 /* addr ovflo err */\r
157#define ER1_IAE 0002000 /* invalid addr err */\r
158#define ER1_WLE 0004000 /* write lock err */\r
159#define ER1_DTE 0010000 /* drive time err NI */\r
160#define ER1_OPI 0020000 /* op incomplete */\r
161#define ER1_UNS 0040000 /* drive unsafe */\r
162#define ER1_DCK 0100000 /* data check NI */\r
163\r
164/* RPMR, RMMR - maintenace register - offset 3*/\r
165\r
166#define RP_MR_OF 3\r
167#define RM_MR_OF (3 + RM_OF)\r
168\r
169/* RPAS, RMAS - attention summary - offset 4 */\r
170\r
171#define RP_AS_OF 4\r
172#define RM_AS_OF (4 + RM_OF)\r
173#define AS_U0 0000001 /* unit 0 flag */\r
174\r
175/* RPDA, RMDA - sector/track - offset 5 */\r
176\r
177#define RP_DA_OF 5\r
178#define RM_DA_OF (5 + RM_OF)\r
179#define DA_V_SC 0 /* sector pos */\r
180#define DA_M_SC 077 /* sector mask */\r
181#define DA_V_SF 8 /* track pos */\r
182#define DA_M_SF 077 /* track mask */\r
183#define DA_MBZ 0140300\r
184#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC)\r
185#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF)\r
186\r
187/* RPDT, RMDT - drive type - offset 6 */\r
188\r
189#define RP_DT_OF 6\r
190#define RM_DT_OF (6 + RM_OF)\r
191\r
192/* RPLA, RMLA - look ahead register - offset 7 */\r
193\r
194#define RP_LA_OF 7\r
195#define RM_LA_OF (7 + RM_OF)\r
196#define LA_V_SC 6 /* sector pos */\r
197\r
198/* RPSN, RMSN - serial number - offset 8 */\r
199\r
200#define RP_SN_OF 8\r
201#define RM_SN_OF (8 + RM_OF)\r
202\r
203/* RPOF, RMOF - offset register - offset 9 */\r
204\r
205#define RP_OF_OF 9\r
206#define RM_OF_OF (9 + RM_OF)\r
207#define OF_HCI 0002000 /* hdr cmp inh NI */\r
208#define OF_ECI 0004000 /* ECC inhibit NI */\r
209#define OF_F22 0010000 /* format NI */\r
210#define OF_MBZ 0161400\r
211\r
212/* RPDC, RMDC - desired cylinder - offset 10 */\r
213\r
214#define RP_DC_OF 10\r
215#define RM_DC_OF (10 + RM_OF)\r
216#define DC_V_CY 0 /* cylinder pos */\r
217#define DC_M_CY 01777 /* cylinder mask */\r
218#define DC_MBZ 0176000\r
219#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY)\r
220#define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \\r
221 GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs))\r
222\r
223/* RPCC - current cylinder - offset 11\r
224 RMHR - holding register - offset 11 */\r
225\r
226#define RP_CC_OF 11\r
227#define RM_HR_OF (11 + RM_OF)\r
228\r
229/* RPER2 - error status 2 - drive unsafe conditions - unimplemented - offset 12\r
230 RMMR2 - maintenance register - unimplemented - offset 12 */\r
231\r
232#define RP_ER2_OF 12\r
233#define RM_MR2_OF (12 + RM_OF)\r
234\r
235/* RPER3 - error status 3 - more unsafe conditions - unimplemented - offset 13\r
236 RMER2 - error status 2 - unimplemented - offset 13 */\r
237\r
238#define RP_ER3_OF 13\r
239#define RM_ER2_OF (13 + RM_OF)\r
240\r
241/* RPEC1, RMEC1 - ECC status 1 - unimplemented - offset 14 */\r
242\r
243#define RP_EC1_OF 14\r
244#define RM_EC1_OF (14 + RM_OF)\r
245\r
246/* RPEC2, RMEC1 - ECC status 2 - unimplemented - offset 15 */\r
247\r
248#define RP_EC2_OF 15\r
249#define RM_EC2_OF (15 + RM_OF)\r
250\r
251/* This controller supports many different disk drive types:\r
252\r
253 type #sectors/ #surfaces/ #cylinders/\r
254 surface cylinder drive\r
255\r
256 RM02/3 32 5 823 =67MB\r
257 RP04/5 22 19 411 =88MB\r
258 RM80 31 14 559 =124MB\r
259 RP06 22 19 815 =176MB\r
260 RM05 32 19 823 =256MB\r
261 RP07 50 32 630 =516MB\r
262\r
263 In theory, each drive can be a different type. The size field in\r
264 each unit selects the drive capacity for each drive and thus the\r
265 drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.\r
266\r
267 Note: the RP07, despite its designation, belongs to the RM family\r
268*/\r
269\r
270#define RM03_DTYPE 0\r
271#define RM03_SECT 32\r
272#define RM03_SURF 5\r
273#define RM03_CYL 823\r
274#define RM03_DEV 020024\r
275#define RM03_SIZE (RM03_SECT * RM03_SURF * RM03_CYL * RP_NUMWD)\r
276\r
277#define RP04_DTYPE 1\r
278#define RP04_SECT 22\r
279#define RP04_SURF 19\r
280#define RP04_CYL 411\r
281#define RP04_DEV 020020\r
282#define RP04_SIZE (RP04_SECT * RP04_SURF * RP04_CYL * RP_NUMWD)\r
283\r
284#define RM80_DTYPE 2\r
285#define RM80_SECT 31\r
286#define RM80_SURF 14\r
287#define RM80_CYL 559\r
288#define RM80_DEV 020026\r
289#define RM80_SIZE (RM80_SECT * RM80_SURF * RM80_CYL * RP_NUMWD)\r
290\r
291#define RP06_DTYPE 3\r
292#define RP06_SECT 22\r
293#define RP06_SURF 19\r
294#define RP06_CYL 815\r
295#define RP06_DEV 020022\r
296#define RP06_SIZE (RP06_SECT * RP06_SURF * RP06_CYL * RP_NUMWD)\r
297\r
298#define RM05_DTYPE 4\r
299#define RM05_SECT 32\r
300#define RM05_SURF 19\r
301#define RM05_CYL 823\r
302#define RM05_DEV 020027\r
303#define RM05_SIZE (RM05_SECT * RM05_SURF * RM05_CYL * RP_NUMWD)\r
304\r
305#define RP07_DTYPE 5\r
306#define RP07_SECT 50\r
307#define RP07_SURF 32\r
308#define RP07_CYL 630\r
309#define RP07_DEV 020042\r
310#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD)\r
311\r
312#define RP_CTRL 0\r
313#define RM_CTRL 1\r
314\r
315struct drvtyp {\r
316 int32 sect; /* sectors */\r
317 int32 surf; /* surfaces */\r
318 int32 cyl; /* cylinders */\r
319 int32 size; /* #blocks */\r
320 int32 devtype; /* device type */\r
321 int32 ctrl; /* ctrl type */\r
322 };\r
323\r
324static struct drvtyp drv_tab[] = {\r
325 { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, RM_CTRL },\r
326 { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, RP_CTRL },\r
327 { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, RM_CTRL },\r
328 { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, RP_CTRL },\r
329 { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, RM_CTRL },\r
330 { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, RM_CTRL },\r
331 { 0 }\r
332 };\r
333\r
334uint16 *rpxb = NULL; /* xfer buffer */\r
335uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */\r
336uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */\r
337uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */\r
338uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */\r
339uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */\r
340uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */\r
341uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */\r
342uint16 rpof[RP_NUMDR] = { 0 }; /* offset */\r
343uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */\r
344uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */\r
345uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */\r
346uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */\r
347uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */\r
348int32 rp_stopioe = 1; /* stop on error */\r
349int32 rp_swait = 10; /* seek time */\r
350int32 rp_rwait = 10; /* rotate time */\r
351static const char *rp_fname[CS1_N_FNC] = {\r
352 "NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN",\r
353 "PRESET", "PACK", "12", "13", "SCH", "15", "16", "17",\r
354 "20", "21", "22", "23", "WRCHK", "25", "26", "27",\r
355 "WRITE", "WRHDR", "32", "33", "READ", "RDHDR", "36", "37"\r
356 };\r
357\r
358extern FILE *sim_deb;\r
359\r
360t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv);\r
361t_stat rp_mbwr (int32 data, int32 ofs, int32 drv);\r
362t_stat rp_svc (UNIT *uptr);\r
363t_stat rp_reset (DEVICE *dptr);\r
364t_stat rp_attach (UNIT *uptr, char *cptr);\r
365t_stat rp_detach (UNIT *uptr);\r
366t_stat rp_boot (int32 unitno, DEVICE *dptr);\r
367void rp_set_er (int32 flg, int32 drv);\r
368void rp_clr_as (int32 mask);\r
369void rp_update_ds (int32 flg, int32 drv);\r
370t_stat rp_go (int32 drv);\r
371t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
372t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);\r
373int32 rp_abort (void);\r
374\r
375extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);\r
376\r
377/* RP data structures\r
378\r
379 rp_dev RP device descriptor\r
380 rp_unit RP unit list\r
381 rp_reg RP register list\r
382 rp_mod RP modifier list\r
383*/\r
384\r
385DIB rp_dib = { MBA_RP, 0, &rp_mbrd, &rp_mbwr, 0, 0, 0, { &rp_abort } };\r
386\r
387UNIT rp_unit[] = {\r
388 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
389 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
390 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
391 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
392 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
393 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
394 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
395 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
396 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
397 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
398 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
399 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
400 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
401 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) },\r
402 { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+\r
403 UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }\r
404 };\r
405\r
406REG rp_reg[] = {\r
407 { BRDATA (CS1, rpcs1, DEV_RDX, 16, RP_NUMDR) },\r
408 { BRDATA (DA, rpda, DEV_RDX, 16, RP_NUMDR) },\r
409 { BRDATA (DS, rpds, DEV_RDX, 16, RP_NUMDR) },\r
410 { BRDATA (ER1, rper1, DEV_RDX, 16, RP_NUMDR) },\r
411 { BRDATA (HR, rmhr, DEV_RDX, 16, RP_NUMDR) },\r
412 { BRDATA (OF, rpof, DEV_RDX, 16, RP_NUMDR) },\r
413 { BRDATA (DC, rpdc, DEV_RDX, 16, RP_NUMDR) },\r
414 { BRDATA (ER2, rper2, DEV_RDX, 16, RP_NUMDR) },\r
415 { BRDATA (ER3, rper3, DEV_RDX, 16, RP_NUMDR) },\r
416 { BRDATA (EC1, rpec1, DEV_RDX, 16, RP_NUMDR) },\r
417 { BRDATA (EC2, rpec2, DEV_RDX, 16, RP_NUMDR) },\r
418 { BRDATA (MR, rpmr, DEV_RDX, 16, RP_NUMDR) },\r
419 { BRDATA (MR2, rmmr2, DEV_RDX, 16, RP_NUMDR) },\r
420 { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT },\r
421 { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT },\r
422 { URDATA (CAPAC, rp_unit[0].capac, 10, T_ADDR_W, 0,\r
423 RP_NUMDR, PV_LEFT | REG_HRO) },\r
424 { FLDATA (STOP_IOE, rp_stopioe, 0) },\r
425 { GRDATA (CTRLTYPE, rp_dib.lnt, DEV_RDX, 16, 0), REG_HRO },\r
426 { NULL }\r
427 };\r
428\r
429MTAB rp_mod[] = {\r
430 { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num },\r
431 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
432 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r
433 { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rp_set_bad },\r
434 { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
435 "RM03", NULL, NULL },\r
436 { (UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
437 "RP04", NULL, NULL },\r
438 { (UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
439 "RM80", NULL, NULL },\r
440 { (UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
441 "RP06", NULL, NULL },\r
442 { (UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
443 "RM05", NULL, NULL },\r
444 { (UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,\r
445 "RP07", NULL, NULL },\r
446 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE),\r
447 "RM03", NULL, NULL },\r
448 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE),\r
449 "RP04", NULL, NULL },\r
450 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE),\r
451 "RM80", NULL, NULL },\r
452 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE),\r
453 "RP06", NULL, NULL },\r
454 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE),\r
455 "RM05", NULL, NULL },\r
456 { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE),\r
457 "RP07", NULL, NULL },\r
458 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },\r
459 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },\r
460 { (UNIT_AUTO+UNIT_DTYPE), (RM03_DTYPE << UNIT_V_DTYPE),\r
461 NULL, "RM03", &rp_set_size },\r
462 { (UNIT_AUTO+UNIT_DTYPE), (RP04_DTYPE << UNIT_V_DTYPE),\r
463 NULL, "RP04", &rp_set_size }, \r
464 { (UNIT_AUTO+UNIT_DTYPE), (RM80_DTYPE << UNIT_V_DTYPE),\r
465 NULL, "RM80", &rp_set_size },\r
466 { (UNIT_AUTO+UNIT_DTYPE), (RP06_DTYPE << UNIT_V_DTYPE),\r
467 NULL, "RP06", &rp_set_size },\r
468 { (UNIT_AUTO+UNIT_DTYPE), (RM05_DTYPE << UNIT_V_DTYPE),\r
469 NULL, "RM05", &rp_set_size },\r
470 { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE),\r
471 NULL, "RP07", &rp_set_size },\r
472 { 0 }\r
473 };\r
474\r
475DEVICE rp_dev = {\r
476 "RP", rp_unit, rp_reg, rp_mod,\r
477 RP_NUMDR, DEV_RDX, 30, 1, DEV_RDX, 16,\r
478 NULL, NULL, &rp_reset,\r
479 &rp_boot, &rp_attach, &rp_detach,\r
480 &rp_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_MBUS | DEV_DEBUG\r
481 };\r
482\r
483/* Massbus register read */\r
484\r
485t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv)\r
486{\r
487uint32 val, dtype, i;\r
488UNIT *uptr;\r
489\r
490rp_update_ds (0, drv); /* update ds */\r
491uptr = rp_dev.units + drv; /* get unit */\r
492if (uptr->flags & UNIT_DIS) { /* nx disk */\r
493 *data = 0;\r
494 return MBE_NXD;\r
495 }\r
496dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
497ofs = ofs & MBA_RMASK; /* mask offset */\r
498if (drv_tab[dtype].ctrl == RM_CTRL) ofs = ofs + RM_OF; /* RM? convert */\r
499\r
500switch (ofs) { /* decode offset */\r
501\r
502 case RP_CS1_OF: case RM_CS1_OF: /* RPCS1 */\r
503 val = (rpcs1[drv] & CS1_RW) | CS1_DVA; /* DVA always set */\r
504 break;\r
505\r
506 case RP_DA_OF: case RM_DA_OF: /* RPDA */\r
507 val = rpda[drv] = rpda[drv] & ~DA_MBZ;\r
508 break;\r
509\r
510 case RP_DS_OF: case RM_DS_OF: /* RPDS */\r
511 val = rpds[drv];\r
512 break;\r
513\r
514 case RP_ER1_OF: case RM_ER1_OF: /* RPER1 */\r
515 val = rper1[drv];\r
516 break;\r
517\r
518 case RP_AS_OF: case RM_AS_OF: /* RPAS */\r
519 val = 0;\r
520 for (i = 0; i < RP_NUMDR; i++)\r
521 if (rpds[i] & DS_ATA) val |= (AS_U0 << i);\r
522 break;\r
523\r
524 case RP_LA_OF: case RM_LA_OF: /* RPLA */\r
525 val = GET_SECTOR (rp_rwait, dtype) << LA_V_SC;\r
526 break;\r
527\r
528 case RP_MR_OF: case RM_MR_OF: /* RPMR */\r
529 val = rpmr[drv];\r
530 break;\r
531\r
532 case RP_DT_OF: case RM_DT_OF: /* RPDT */\r
533 val = drv_tab[dtype].devtype;\r
534 break;\r
535\r
536 case RP_SN_OF: case RM_SN_OF: /* RPSN */\r
537 val = 020 | (drv + 1);\r
538 break;\r
539\r
540 case RP_OF_OF: case RM_OF_OF: /* RPOF */\r
541 val = rpof[drv] = rpof[drv] & ~OF_MBZ;\r
542 break;\r
543\r
544 case RP_DC_OF: case RM_DC_OF: /* RPDC */\r
545 val = rpdc[drv] = rpdc[drv] & ~DC_MBZ;\r
546 break;\r
547\r
548 case RP_CC_OF: /* RPCC */\r
549 val = rp_unit[drv].CYL;\r
550 break;\r
551\r
552 case RP_ER2_OF: case RM_ER2_OF: /* RPER2 */\r
553 val = rper2[drv];\r
554 break;\r
555\r
556 case RP_ER3_OF: /* RPER3 */\r
557 val = rper3[drv];\r
558 break;\r
559\r
560 case RP_EC1_OF: case RM_EC1_OF: /* RPEC1 */\r
561 val = rpec1[drv];\r
562 break;\r
563\r
564 case RP_EC2_OF: case RM_EC2_OF: /* RPEC2 */\r
565 val = rpec2[drv];\r
566 break;\r
567\r
568 case RM_HR_OF: /* RMHR */\r
569 val = rmhr[drv] ^ DMASK;\r
570 break;\r
571\r
572 case RM_MR2_OF: /* RHMR2 */\r
573 val = rmmr2[drv];\r
574 break;\r
575\r
576 default: /* all others */\r
577 *data = 0;\r
578 return MBE_NXR;\r
579 }\r
580\r
581*data = val;\r
582return SCPE_OK;\r
583}\r
584\r
585/* Massbus register write */\r
586\r
587t_stat rp_mbwr (int32 data, int32 ofs, int32 drv)\r
588{\r
589int32 dtype;\r
590UNIT *uptr;\r
591\r
592uptr = rp_dev.units + drv; /* get unit */\r
593if (uptr->flags & UNIT_DIS) return MBE_NXD; /* nx disk */\r
594if ((ofs != RP_AS_OF) && sim_is_active (uptr)) { /* unit busy? */\r
595 rp_set_er (ER1_RMR, drv); /* won't write */\r
596 rp_update_ds (0, drv);\r
597 return SCPE_OK;\r
598 }\r
599rmhr[drv] = data; /* save write */\r
600dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
601ofs = ofs & MBA_RMASK; /* mask offset */\r
602if (drv_tab[dtype].ctrl == RM_CTRL) ofs = ofs + RM_OF; /* RM? convert */\r
603\r
604switch (ofs) { /* decode PA<5:1> */\r
605\r
606 case RP_CS1_OF: case RM_CS1_OF: /* RPCS1 */\r
607 rpcs1[drv] = data & CS1_RW;\r
608 if (data & CS1_GO) return rp_go (drv); /* start op */\r
609 break; \r
610\r
611 case RP_DA_OF: case RM_DA_OF: /* RPDA */\r
612 rpda[drv] = data & ~DA_MBZ;\r
613 break;\r
614\r
615 case RP_AS_OF: case RM_AS_OF: /* RPAS */\r
616 rp_clr_as (data);\r
617 break;\r
618\r
619 case RP_MR_OF: case RM_MR_OF: /* RPMR */\r
620 rpmr[drv] = data;\r
621 break;\r
622\r
623 case RP_OF_OF: case RM_OF_OF: /* RPOF */\r
624 rpof[drv] = data & ~OF_MBZ;\r
625 break;\r
626\r
627 case RP_DC_OF: case RM_DC_OF: /* RPDC */\r
628 rpdc[drv] = data & ~DC_MBZ;\r
629 break;\r
630\r
631 case RM_MR2_OF: /* RMMR2 */\r
632 rmmr2[drv] = data;\r
633 break;\r
634\r
635 case RP_ER1_OF: case RM_ER1_OF: /* RPER1 */\r
636 case RP_DS_OF: case RM_DS_OF: /* RPDS */\r
637 case RP_LA_OF: case RM_LA_OF: /* RPLA */\r
638 case RP_DT_OF: case RM_DT_OF: /* RPDT */\r
639 case RP_SN_OF: case RM_SN_OF: /* RPSN */\r
640 case RP_CC_OF: /* RPCC */\r
641 case RP_ER2_OF: case RM_ER2_OF: /* RPER2 */\r
642 case RP_ER3_OF: /* RPER3 */\r
643 case RP_EC1_OF: case RM_EC1_OF: /* RPEC1 */\r
644 case RP_EC2_OF: case RM_EC2_OF: /* RPEC2 */\r
645 case RM_HR_OF: /* RMHR */\r
646 break; /* read only */\r
647\r
648 default: /* all others */\r
649 return MBE_NXR;\r
650 } /* end switch */\r
651\r
652rp_update_ds (0, drv); /* update status */\r
653return SCPE_OK;\r
654}\r
655\r
656/* Initiate operation - unit not busy, function set */\r
657\r
658t_stat rp_go (int32 drv)\r
659{\r
660int32 dc, fnc, dtype, t;\r
661UNIT *uptr;\r
662\r
663fnc = GET_FNC (rpcs1[drv]); /* get function */\r
664if (DEBUG_PRS (rp_dev)) fprintf (sim_deb,\r
665 ">>RP%d STRT: fnc=%s, ds=%o, cyl=%o, da=%o, er=%o\n",\r
666 drv, rp_fname[fnc], rpds[drv], rpdc[drv], rpda[drv], rper1[drv]);\r
667uptr = rp_dev.units + drv; /* get unit */\r
668rp_clr_as (AS_U0 << drv); /* clear attention */\r
669dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
670dc = rpdc[drv]; /* assume seek, sch */\r
671if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */\r
672 rp_set_er (ER1_ILF, drv); /* not allowed */\r
673 rp_update_ds (DS_ATA, drv); /* set attention */\r
674 return MBE_GOE;\r
675 }\r
676\r
677switch (fnc) { /* case on function */\r
678\r
679 case FNC_DCLR: /* drive clear */\r
680 rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */\r
681 rpec2[drv] = 0; /* clear EC2 */\r
682 if (drv_tab[dtype].ctrl == RM_CTRL) /* RM? */\r
683 rpmr[drv] = 0; /* clear maint */\r
684 else rpec1[drv] = 0; /* RP, clear EC1 */\r
685 case FNC_NOP: /* no operation */\r
686 case FNC_RELEASE: /* port release */\r
687 return SCPE_OK;\r
688\r
689 case FNC_PRESET: /* read-in preset */\r
690 rpdc[drv] = 0; /* clear disk addr */\r
691 rpda[drv] = 0;\r
692 rpof[drv] = 0; /* clear offset */\r
693 case FNC_PACK: /* pack acknowledge */\r
694 rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */\r
695 return SCPE_OK;\r
696\r
697 case FNC_OFFSET: /* offset mode */\r
698 case FNC_RETURN:\r
699 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
700 rp_set_er (ER1_UNS, drv); /* unsafe */\r
701 break;\r
702 }\r
703 rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */\r
704 sim_activate (uptr, rp_swait); /* time operation */\r
705 return SCPE_OK;\r
706\r
707 case FNC_UNLOAD: /* unload */\r
708 case FNC_RECAL: /* recalibrate */\r
709 dc = 0; /* seek to 0 */\r
710 case FNC_SEEK: /* seek */\r
711 case FNC_SEARCH: /* search */\r
712 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
713 rp_set_er (ER1_UNS, drv); /* unsafe */\r
714 break;\r
715 }\r
716 if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */\r
717 (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */\r
718 (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */\r
719 rp_set_er (ER1_IAE, drv);\r
720 break;\r
721 }\r
722 rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */\r
723 t = abs (dc - uptr->CYL); /* cyl diff */\r
724 if (t == 0) t = 1; /* min time */\r
725 sim_activate (uptr, rp_swait * t); /* schedule */\r
726 uptr->CYL = dc; /* save cylinder */\r
727 return SCPE_OK;\r
728\r
729 case FNC_WRITEH: /* write headers */\r
730 case FNC_WRITE: /* write */\r
731 case FNC_WCHK: /* write check */\r
732 case FNC_READ: /* read */\r
733 case FNC_READH: /* read headers */\r
734 if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
735 rp_set_er (ER1_UNS, drv); /* unsafe */\r
736 break;\r
737 }\r
738 if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */\r
739 (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */\r
740 (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */\r
741 rp_set_er (ER1_IAE, drv);\r
742 break;\r
743 }\r
744 rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */\r
745 sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL)));\r
746 uptr->CYL = dc; /* save cylinder */\r
747 return SCPE_OK;\r
748\r
749 default: /* all others */\r
750 rp_set_er (ER1_ILF, drv); /* not supported */\r
751 break;\r
752 }\r
753\r
754rp_update_ds (DS_ATA, drv); /* set attn, req int */\r
755return MBE_GOE;\r
756}\r
757\r
758/* Abort opertion - there is a data transfer in progress */\r
759\r
760int32 rp_abort (void)\r
761{\r
762return rp_reset (&rp_dev);\r
763}\r
764\r
765/* Service unit timeout\r
766\r
767 Complete movement or data transfer command\r
768 Unit must exist - can't remove an active unit\r
769 Unit must be attached - detach cancels in progress operations\r
770*/\r
771\r
772t_stat rp_svc (UNIT *uptr)\r
773{\r
774int32 i, fnc, dtype, drv, err;\r
775int32 wc, abc, awc, mbc, da;\r
776\r
777dtype = GET_DTYPE (uptr->flags); /* get drive type */\r
778drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
779da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */\r
780fnc = GET_FNC (rpcs1[drv]); /* get function */\r
781\r
782if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r
783 rp_set_er (ER1_UNS, drv); /* set drive error */\r
784 if (fnc >= FNC_XFER) mba_set_don (rp_dib.ba); /* xfr? set done */\r
785 rp_update_ds (DS_ATA, drv); /* set attn */\r
786 return (rp_stopioe? SCPE_UNATT: SCPE_OK);\r
787 }\r
788rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */\r
789\r
790switch (fnc) { /* case on function */\r
791\r
792 case FNC_OFFSET: /* offset */\r
793 rp_update_ds (DS_OFM | DS_ATA, drv);\r
794 break;\r
795\r
796 case FNC_RETURN: /* return to centerline */\r
797 rpds[drv] = rpds[drv] & ~DS_OFM; /* clear offset, set attn */\r
798 rp_update_ds (DS_ATA, drv);\r
799 break; \r
800\r
801 case FNC_UNLOAD: /* unload */\r
802 rp_detach (uptr); /* detach unit */\r
803 break;\r
804\r
805 case FNC_RECAL: /* recalibrate */\r
806 case FNC_SEARCH: /* search */\r
807 case FNC_SEEK: /* seek */\r
808 rp_update_ds (DS_ATA, drv);\r
809 break;\r
810\r
811 case FNC_WRITE: /* write */\r
812 if (uptr->flags & UNIT_WPRT) { /* write locked? */\r
813 rp_set_er (ER1_WLE, drv); /* set drive error */\r
814 mba_set_exc (rp_dib.ba); /* set exception */\r
815 rp_update_ds (DS_ATA, drv); /* set attn */\r
816 return SCPE_OK;\r
817 }\r
818 case FNC_WCHK: /* write check */\r
819 case FNC_READ: /* read */\r
820 case FNC_READH: /* read headers */\r
821 err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);\r
822 mbc = mba_get_bc (rp_dib.ba); /* get byte count */\r
823 wc = (mbc + 1) >> 1; /* convert to words */\r
824 if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */\r
825 rp_set_er (ER1_AOE, drv); /* set err */\r
826 wc = drv_tab[dtype].size - da; /* trim xfer */\r
827 mbc = wc << 1; /* trim mb count */\r
828 if (da >= drv_tab[dtype].size) { /* none left? */\r
829 mba_set_exc (rp_dib.ba); /* set exception */\r
830 rp_update_ds (DS_ATA, drv); /* set attn */\r
831 break;\r
832 }\r
833 }\r
834 if (fnc == FNC_WRITE) { /* write? */\r
835 abc = mba_rdbufW (rp_dib.ba, mbc, rpxb); /* get buffer */\r
836 wc = (abc + 1) >> 1; /* actual # wds */\r
837 awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1);\r
838 for (i = wc; i < awc; i++) rpxb[i] = 0; /* fill buf */\r
839 if (wc && !err) { /* write buf */\r
840 fxwrite (rpxb, sizeof (uint16), awc, uptr->fileref);\r
841 err = ferror (uptr->fileref);\r
842 }\r
843 } /* end if wr */\r
844 else { /* read or wchk */\r
845 awc = fxread (rpxb, sizeof (uint16), wc, uptr->fileref);\r
846 err = ferror (uptr->fileref);\r
847 for (i = awc; i < wc; i++) rpxb[i] = 0; /* fill buf */\r
848 if (fnc == FNC_WCHK) /* write check? */\r
849 mba_chbufW (rp_dib.ba, mbc, rpxb); /* check vs mem */\r
850 else mba_wrbufW (rp_dib.ba, mbc, rpxb); /* store in mem */\r
851 } /* end if read */\r
852 da = da + wc + (RP_NUMWD - 1);\r
853 if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;\r
854 da = da / RP_NUMWD;\r
855 rpda[drv] = da % drv_tab[dtype].sect;\r
856 da = da / drv_tab[dtype].sect;\r
857 rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF);\r
858 rpdc[drv] = da / drv_tab[dtype].surf;\r
859 uptr->CYL = rpdc[drv];\r
860\r
861 if (err != 0) { /* error? */\r
862 rp_set_er (ER1_PAR, drv); /* set drive error */\r
863 mba_set_exc (rp_dib.ba); /* set exception */\r
864 rp_update_ds (DS_ATA, drv);\r
865 perror ("RP I/O error");\r
866 clearerr (uptr->fileref);\r
867 return SCPE_IOERR;\r
868 }\r
869\r
870 case FNC_WRITEH: /* write headers stub */\r
871 mba_set_don (rp_dib.ba); /* set done */\r
872 rp_update_ds (0, drv); /* update ds */\r
873 break;\r
874 } /* end case func */\r
875\r
876if (DEBUG_PRS (rp_dev)) fprintf (sim_deb,\r
877 ">>RP%d DONE: fnc=%s, ds=%o, cyl=%o, da=%o, er=%d\n",\r
878 drv, rp_fname[fnc], rpds[drv], rpdc[drv], rpda[drv], rper1[drv]);\r
879return SCPE_OK;\r
880}\r
881\r
882/* Set drive error */\r
883\r
884void rp_set_er (int32 flag, int32 drv)\r
885{\r
886rper1[drv] = rper1[drv] | flag;\r
887rpds[drv] = rpds[drv] | DS_ATA;\r
888mba_upd_ata (rp_dib.ba, 1);\r
889return;\r
890}\r
891\r
892/* Clear attention flags */\r
893\r
894void rp_clr_as (int32 mask)\r
895{\r
896uint32 i, as;\r
897\r
898for (i = as = 0; i < RP_NUMDR; i++) {\r
899 if (mask & (AS_U0 << i)) rpds[i] &= ~DS_ATA;\r
900 if (rpds[i] & DS_ATA) as = 1;\r
901 }\r
902mba_upd_ata (rp_dib.ba, as);\r
903return;\r
904}\r
905\r
906/* Drive status update */\r
907\r
908void rp_update_ds (int32 flag, int32 drv)\r
909{\r
910if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;\r
911else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;\r
912if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;\r
913else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);\r
914if (rper1[drv] | rper2[drv] | rper3[drv]) rpds[drv] = rpds[drv] | DS_ERR;\r
915else rpds[drv] = rpds[drv] & ~DS_ERR;\r
916rpds[drv] = rpds[drv] | flag;\r
917if (flag & DS_ATA) mba_upd_ata (rp_dib.ba, 1);\r
918return;\r
919}\r
920\r
921/* Device reset */\r
922\r
923t_stat rp_reset (DEVICE *dptr)\r
924{\r
925int32 i;\r
926UNIT *uptr;\r
927\r
928mba_set_enbdis (MBA_RP, rp_dev.flags & DEV_DIS);\r
929for (i = 0; i < RP_NUMDR; i++) {\r
930 uptr = rp_dev.units + i;\r
931 sim_cancel (uptr);\r
932 uptr->CYL = 0;\r
933 if (uptr->flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) |\r
934 DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r
935 else if (uptr->flags & UNIT_DIS) rpds[i] = 0;\r
936 else rpds[i] = DS_DPR;\r
937 rpcs1[i] = 0;\r
938 rper1[i] = 0;\r
939 rpof[i] = 0;\r
940 rpdc[i] = 0;\r
941 rpda[i] = 0;\r
942 rpmr[i] = 0;\r
943 rper2[i] = 0;\r
944 rper3[i] = 0;\r
945 rpec1[i] = 0;\r
946 rpec2[i] = 0;\r
947 rmmr2[i] = 0;\r
948 rmhr[i] = 0;\r
949 }\r
950if (rpxb == NULL) rpxb = (uint16 *) calloc (RP_MAXFR, sizeof (uint16));\r
951if (rpxb == NULL) return SCPE_MEM;\r
952return SCPE_OK;\r
953}\r
954\r
955/* Device attach */\r
956\r
957t_stat rp_attach (UNIT *uptr, char *cptr)\r
958{\r
959int32 drv, i, p;\r
960t_stat r;\r
961\r
962uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;\r
963r = attach_unit (uptr, cptr); /* attach unit */\r
964if (r != SCPE_OK) return r; /* error? */\r
965drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
966rpds[drv] = DS_MOL | DS_RDY | DS_DPR | /* upd drv status */\r
967 ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r
968rper1[drv] = 0;\r
969rp_update_ds (DS_ATA, drv); /* upd ctlr status */\r
970\r
971if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */\r
972 if (uptr->flags & UNIT_RO) return SCPE_OK;\r
973 return pdp11_bad_block (uptr,\r
974 drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD);\r
975 }\r
976if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */\r
977for (i = 0; drv_tab[i].sect != 0; i++) {\r
978 if (p <= (drv_tab[i].size * (int) sizeof (int16))) {\r
979 uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);\r
980 uptr->capac = drv_tab[i].size;\r
981 return SCPE_OK;\r
982 }\r
983 }\r
984return SCPE_OK;\r
985}\r
986\r
987/* Device detach */\r
988\r
989t_stat rp_detach (UNIT *uptr)\r
990{\r
991int32 drv;\r
992\r
993if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r
994drv = (int32) (uptr - rp_dev.units); /* get drv number */\r
995rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM);\r
996rp_update_ds (DS_ATA, drv); /* request intr */\r
997return detach_unit (uptr);\r
998}\r
999\r
1000/* Set size command validation routine */\r
1001\r
1002t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1003{\r
1004int32 dtype = GET_DTYPE (val);\r
1005\r
1006if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r
1007uptr->capac = drv_tab[dtype].size;\r
1008return SCPE_OK;\r
1009}\r
1010\r
1011/* Set bad block routine */\r
1012\r
1013t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1014{\r
1015return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD);\r
1016}\r
1017\r
1018/* Boot routine */\r
1019\r
1020#if defined (VM_PDP11)\r
1021\r
1022#define BOOT_START 02000 /* start */\r
1023#define BOOT_ENTRY (BOOT_START + 002) /* entry */\r
1024#define BOOT_UNIT (BOOT_START + 010) /* unit number */\r
1025#define BOOT_CSR (BOOT_START + 014) /* CSR */\r
1026#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))\r
1027\r
1028static const uint16 boot_rom[] = {\r
1029 0042102, /* "BD" */\r
1030 0012706, BOOT_START, /* mov #boot_start, sp */\r
1031 0012700, 0000000, /* mov #unit, r0 */\r
1032 0012701, 0176700, /* mov #RPCS1, r1 */\r
1033 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */\r
1034 0010061, 0000010, /* mov r0, 10(r1) ; set unit */\r
1035 0012711, 0000021, /* mov #RIP+GO, (r1) ; pack ack */\r
1036 0012761, 0010000, 0000032, /* mov #FMT16B, 32(r1) ; 16b mode */\r
1037 0012761, 0177000, 0000002, /* mov #-512., 2(r1) ; set wc */\r
1038 0005061, 0000004, /* clr 4(r1) ; clr ba */\r
1039 0005061, 0000006, /* clr 6(r1) ; clr da */\r
1040 0005061, 0000034, /* clr 34(r1) ; clr cyl */\r
1041 0012711, 0000071, /* mov #READ+GO, (r1) ; read */\r
1042 0105711, /* tstb (r1) ; wait */\r
1043 0100376, /* bpl .-2 */\r
1044 0005002, /* clr R2 */\r
1045 0005003, /* clr R3 */\r
1046 0012704, BOOT_START+020, /* mov #start+020, r4 */\r
1047 0005005, /* clr R5 */\r
1048 0105011, /* clrb (r1) */\r
1049 0005007 /* clr PC */\r
1050 };\r
1051\r
1052t_stat rp_boot (int32 unitno, DEVICE *dptr)\r
1053{\r
1054int32 i;\r
1055extern int32 saved_PC;\r
1056extern uint16 *M;\r
1057UNIT *uptr = rp_dev.units + unitno;\r
1058\r
1059for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r
1060M[BOOT_UNIT >> 1] = unitno & (RP_NUMDR - 1);\r
1061M[BOOT_CSR >> 1] = mba_get_csr (rp_dib.ba) & DMASK;\r
1062if (drv_tab[GET_DTYPE (uptr->flags)].ctrl == RP_CTRL)\r
1063 M[BOOT_START >> 1] = 042102; /* "BD" */\r
1064else M[BOOT_START >> 1] = 042122; /* "RD" */\r
1065saved_PC = BOOT_ENTRY;\r
1066return SCPE_OK;\r
1067}\r
1068\r
1069#else\r
1070\r
1071t_stat rp_boot (int32 unitno, DEVICE *dptr)\r
1072{\r
1073return SCPE_NOFNC;\r
1074}\r
1075\r
1076#endif\r