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