Commit | Line | Data |
---|---|---|
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 | |
315 | struct 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 | |
324 | static 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 | |
334 | uint16 *rpxb = NULL; /* xfer buffer */\r | |
335 | uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */\r | |
336 | uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */\r | |
337 | uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */\r | |
338 | uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */\r | |
339 | uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */\r | |
340 | uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */\r | |
341 | uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */\r | |
342 | uint16 rpof[RP_NUMDR] = { 0 }; /* offset */\r | |
343 | uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */\r | |
344 | uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */\r | |
345 | uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */\r | |
346 | uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */\r | |
347 | uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */\r | |
348 | int32 rp_stopioe = 1; /* stop on error */\r | |
349 | int32 rp_swait = 10; /* seek time */\r | |
350 | int32 rp_rwait = 10; /* rotate time */\r | |
351 | static 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 | |
358 | extern FILE *sim_deb;\r | |
359 | \r | |
360 | t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv);\r | |
361 | t_stat rp_mbwr (int32 data, int32 ofs, int32 drv);\r | |
362 | t_stat rp_svc (UNIT *uptr);\r | |
363 | t_stat rp_reset (DEVICE *dptr);\r | |
364 | t_stat rp_attach (UNIT *uptr, char *cptr);\r | |
365 | t_stat rp_detach (UNIT *uptr);\r | |
366 | t_stat rp_boot (int32 unitno, DEVICE *dptr);\r | |
367 | void rp_set_er (int32 flg, int32 drv);\r | |
368 | void rp_clr_as (int32 mask);\r | |
369 | void rp_update_ds (int32 flg, int32 drv);\r | |
370 | t_stat rp_go (int32 drv);\r | |
371 | t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
372 | t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
373 | int32 rp_abort (void);\r | |
374 | \r | |
375 | extern 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 | |
385 | DIB rp_dib = { MBA_RP, 0, &rp_mbrd, &rp_mbwr, 0, 0, 0, { &rp_abort } };\r | |
386 | \r | |
387 | UNIT 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 | |
406 | REG 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 | |
429 | MTAB 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 | |
475 | DEVICE 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 | |
485 | t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv)\r | |
486 | {\r | |
487 | uint32 val, dtype, i;\r | |
488 | UNIT *uptr;\r | |
489 | \r | |
490 | rp_update_ds (0, drv); /* update ds */\r | |
491 | uptr = rp_dev.units + drv; /* get unit */\r | |
492 | if (uptr->flags & UNIT_DIS) { /* nx disk */\r | |
493 | *data = 0;\r | |
494 | return MBE_NXD;\r | |
495 | }\r | |
496 | dtype = GET_DTYPE (uptr->flags); /* get drive type */\r | |
497 | ofs = ofs & MBA_RMASK; /* mask offset */\r | |
498 | if (drv_tab[dtype].ctrl == RM_CTRL) ofs = ofs + RM_OF; /* RM? convert */\r | |
499 | \r | |
500 | switch (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 | |
582 | return SCPE_OK;\r | |
583 | }\r | |
584 | \r | |
585 | /* Massbus register write */\r | |
586 | \r | |
587 | t_stat rp_mbwr (int32 data, int32 ofs, int32 drv)\r | |
588 | {\r | |
589 | int32 dtype;\r | |
590 | UNIT *uptr;\r | |
591 | \r | |
592 | uptr = rp_dev.units + drv; /* get unit */\r | |
593 | if (uptr->flags & UNIT_DIS) return MBE_NXD; /* nx disk */\r | |
594 | if ((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 | |
599 | rmhr[drv] = data; /* save write */\r | |
600 | dtype = GET_DTYPE (uptr->flags); /* get drive type */\r | |
601 | ofs = ofs & MBA_RMASK; /* mask offset */\r | |
602 | if (drv_tab[dtype].ctrl == RM_CTRL) ofs = ofs + RM_OF; /* RM? convert */\r | |
603 | \r | |
604 | switch (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 | |
652 | rp_update_ds (0, drv); /* update status */\r | |
653 | return SCPE_OK;\r | |
654 | }\r | |
655 | \r | |
656 | /* Initiate operation - unit not busy, function set */\r | |
657 | \r | |
658 | t_stat rp_go (int32 drv)\r | |
659 | {\r | |
660 | int32 dc, fnc, dtype, t;\r | |
661 | UNIT *uptr;\r | |
662 | \r | |
663 | fnc = GET_FNC (rpcs1[drv]); /* get function */\r | |
664 | if (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 | |
667 | uptr = rp_dev.units + drv; /* get unit */\r | |
668 | rp_clr_as (AS_U0 << drv); /* clear attention */\r | |
669 | dtype = GET_DTYPE (uptr->flags); /* get drive type */\r | |
670 | dc = rpdc[drv]; /* assume seek, sch */\r | |
671 | if ((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 | |
677 | switch (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 | |
754 | rp_update_ds (DS_ATA, drv); /* set attn, req int */\r | |
755 | return MBE_GOE;\r | |
756 | }\r | |
757 | \r | |
758 | /* Abort opertion - there is a data transfer in progress */\r | |
759 | \r | |
760 | int32 rp_abort (void)\r | |
761 | {\r | |
762 | return 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 | |
772 | t_stat rp_svc (UNIT *uptr)\r | |
773 | {\r | |
774 | int32 i, fnc, dtype, drv, err;\r | |
775 | int32 wc, abc, awc, mbc, da;\r | |
776 | \r | |
777 | dtype = GET_DTYPE (uptr->flags); /* get drive type */\r | |
778 | drv = (int32) (uptr - rp_dev.units); /* get drv number */\r | |
779 | da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */\r | |
780 | fnc = GET_FNC (rpcs1[drv]); /* get function */\r | |
781 | \r | |
782 | if ((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 | |
788 | rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */\r | |
789 | \r | |
790 | switch (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 | |
876 | if (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 | |
879 | return SCPE_OK;\r | |
880 | }\r | |
881 | \r | |
882 | /* Set drive error */\r | |
883 | \r | |
884 | void rp_set_er (int32 flag, int32 drv)\r | |
885 | {\r | |
886 | rper1[drv] = rper1[drv] | flag;\r | |
887 | rpds[drv] = rpds[drv] | DS_ATA;\r | |
888 | mba_upd_ata (rp_dib.ba, 1);\r | |
889 | return;\r | |
890 | }\r | |
891 | \r | |
892 | /* Clear attention flags */\r | |
893 | \r | |
894 | void rp_clr_as (int32 mask)\r | |
895 | {\r | |
896 | uint32 i, as;\r | |
897 | \r | |
898 | for (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 | |
902 | mba_upd_ata (rp_dib.ba, as);\r | |
903 | return;\r | |
904 | }\r | |
905 | \r | |
906 | /* Drive status update */\r | |
907 | \r | |
908 | void rp_update_ds (int32 flag, int32 drv)\r | |
909 | {\r | |
910 | if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;\r | |
911 | else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;\r | |
912 | if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;\r | |
913 | else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);\r | |
914 | if (rper1[drv] | rper2[drv] | rper3[drv]) rpds[drv] = rpds[drv] | DS_ERR;\r | |
915 | else rpds[drv] = rpds[drv] & ~DS_ERR;\r | |
916 | rpds[drv] = rpds[drv] | flag;\r | |
917 | if (flag & DS_ATA) mba_upd_ata (rp_dib.ba, 1);\r | |
918 | return;\r | |
919 | }\r | |
920 | \r | |
921 | /* Device reset */\r | |
922 | \r | |
923 | t_stat rp_reset (DEVICE *dptr)\r | |
924 | {\r | |
925 | int32 i;\r | |
926 | UNIT *uptr;\r | |
927 | \r | |
928 | mba_set_enbdis (MBA_RP, rp_dev.flags & DEV_DIS);\r | |
929 | for (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 | |
950 | if (rpxb == NULL) rpxb = (uint16 *) calloc (RP_MAXFR, sizeof (uint16));\r | |
951 | if (rpxb == NULL) return SCPE_MEM;\r | |
952 | return SCPE_OK;\r | |
953 | }\r | |
954 | \r | |
955 | /* Device attach */\r | |
956 | \r | |
957 | t_stat rp_attach (UNIT *uptr, char *cptr)\r | |
958 | {\r | |
959 | int32 drv, i, p;\r | |
960 | t_stat r;\r | |
961 | \r | |
962 | uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;\r | |
963 | r = attach_unit (uptr, cptr); /* attach unit */\r | |
964 | if (r != SCPE_OK) return r; /* error? */\r | |
965 | drv = (int32) (uptr - rp_dev.units); /* get drv number */\r | |
966 | rpds[drv] = DS_MOL | DS_RDY | DS_DPR | /* upd drv status */\r | |
967 | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);\r | |
968 | rper1[drv] = 0;\r | |
969 | rp_update_ds (DS_ATA, drv); /* upd ctlr status */\r | |
970 | \r | |
971 | if ((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 | |
976 | if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */\r | |
977 | for (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 | |
984 | return SCPE_OK;\r | |
985 | }\r | |
986 | \r | |
987 | /* Device detach */\r | |
988 | \r | |
989 | t_stat rp_detach (UNIT *uptr)\r | |
990 | {\r | |
991 | int32 drv;\r | |
992 | \r | |
993 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r | |
994 | drv = (int32) (uptr - rp_dev.units); /* get drv number */\r | |
995 | rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM);\r | |
996 | rp_update_ds (DS_ATA, drv); /* request intr */\r | |
997 | return detach_unit (uptr);\r | |
998 | }\r | |
999 | \r | |
1000 | /* Set size command validation routine */\r | |
1001 | \r | |
1002 | t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1003 | {\r | |
1004 | int32 dtype = GET_DTYPE (val);\r | |
1005 | \r | |
1006 | if (uptr->flags & UNIT_ATT) return SCPE_ALATT;\r | |
1007 | uptr->capac = drv_tab[dtype].size;\r | |
1008 | return SCPE_OK;\r | |
1009 | }\r | |
1010 | \r | |
1011 | /* Set bad block routine */\r | |
1012 | \r | |
1013 | t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
1014 | {\r | |
1015 | return 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 | |
1028 | static 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 | |
1052 | t_stat rp_boot (int32 unitno, DEVICE *dptr)\r | |
1053 | {\r | |
1054 | int32 i;\r | |
1055 | extern int32 saved_PC;\r | |
1056 | extern uint16 *M;\r | |
1057 | UNIT *uptr = rp_dev.units + unitno;\r | |
1058 | \r | |
1059 | for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r | |
1060 | M[BOOT_UNIT >> 1] = unitno & (RP_NUMDR - 1);\r | |
1061 | M[BOOT_CSR >> 1] = mba_get_csr (rp_dib.ba) & DMASK;\r | |
1062 | if (drv_tab[GET_DTYPE (uptr->flags)].ctrl == RP_CTRL)\r | |
1063 | M[BOOT_START >> 1] = 042102; /* "BD" */\r | |
1064 | else M[BOOT_START >> 1] = 042122; /* "RD" */\r | |
1065 | saved_PC = BOOT_ENTRY;\r | |
1066 | return SCPE_OK;\r | |
1067 | }\r | |
1068 | \r | |
1069 | #else\r | |
1070 | \r | |
1071 | t_stat rp_boot (int32 unitno, DEVICE *dptr)\r | |
1072 | {\r | |
1073 | return SCPE_NOFNC;\r | |
1074 | }\r | |
1075 | \r | |
1076 | #endif\r |