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