1 /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
3 Copyright (c) 1993-2006, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 dr 12606B 2770/2771 fixed head disk
27 12610B 2773/2774/2775 drum
29 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
30 07-Oct-04 JDB Fixed enable/disable from either device
31 Fixed sector return in status word
32 Provided protected tracks and "Writing Enabled" status bit
33 Fixed DMA last word write, incomplete sector fill value
34 Added "parity error" status return on writes for 12606
35 Added track origin test for 12606
36 Added SCP test for 12606
37 Fixed 12610 SFC operation
38 Added "Sector Flag" status bit
39 Added "Read Inhibit" status bit for 12606
40 Fixed current-sector determination
41 Added PROTECTED, UNPROTECTED, TRACKPROT modifiers
42 26-Aug-04 RMS Fixed CLC to stop operation (from Dave Bryan)
43 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
44 Revised boot rom to use IBL algorithm
45 Implemented DMA SRQ (follows FLG)
46 27-Jul-03 RMS Fixed drum sizes
47 Fixed variable capacity interaction with SAVE/RESTORE
48 10-Nov-02 RMS Added BOOT command
50 These head-per-track devices are buffered in memory, to minimize overhead.
52 The drum data channel does not have a command flip-flop. Its control
53 flip-flop is not wired into the interrupt chain; accordingly, the
54 simulator uses command rather than control for the data channel. Its
55 flag does not respond to SFS, SFC, or STF.
57 The drum control channel does not have any of the traditional flip-flops.
59 The 12606 interface implements two diagnostic tests. An SFS CC instruction
60 will skip if the disk has passed the track origin (sector 0) since the last
61 CLF CC instruction, and an SFC CC instruction will skip if the Sector Clock
62 Phase (SCP) flip-flop is clear, indicating that the current sector is
63 accessible. The 12610 interface does not support these tests; the SKF signal
64 is not driven, so neither SFC CC nor SFS CC will skip.
66 The interface implements a track protect mechanism via a switch and a set of
67 on-card diodes. The switch sets the protected/unprotected status, and the
68 particular diodes installed indicate the range of tracks (a power of 2) that
69 are read-only in the protected mode.
71 Somewhat unusually, writing to a protected track completes normally, but the
72 data isn't actually written, as the write current is inhibited. There is no
73 "failure" status indication. Instead, a program must note the lack of
74 "Writing Enabled" status before the write is attempted.
76 Specifications (2770/2771):
77 - 90 sectors per logical track
78 - 45 sectors per revolution
80 - 2880 words per revolution
81 - 3450 RPM = 17.4 ms/revolution
82 - data timing = 6.0 us/word, 375 us/sector
83 - inst timing = 4 inst/word, 11520 inst/revolution
85 Specifications 2773/2774/2775:
86 - 32 sectors per logical track
87 - 32 sectors per revolution
89 - 2048 words per revolution
90 - 3450 RPM = 17.4 ms/revolution
91 - data timing = 8.5 us/word, 550 us/sector
92 - inst timing = 6 inst/word, 12288 inst/revolution
95 - 12606B Disc Memory Interface Kit Operating and Service Manual
96 (12606-90012, Mar-1970)
97 - 12610B Drum Memory Interface Kit Operating and Service Manual
98 (12610-9001, Feb-1970)
101 #include "hp2100_defs.h"
106 #define DR_NUMWD 64 /* words/sector */
107 #define DR_FNUMSC 90 /* fhd sec/track */
108 #define DR_DNUMSC 32 /* drum sec/track */
109 #define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
110 #define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
111 #define DR_FTIME 4 /* fhd per-word time */
112 #define DR_DTIME 6 /* drum per-word time */
113 #define DR_OVRHEAD 5 /* overhead words at track start */
114 #define UNIT_V_PROT (UNIT_V_UF + 0) /* track protect */
115 #define UNIT_V_SZ (UNIT_V_UF + 1) /* disk vs drum */
116 #define UNIT_M_SZ 017 /* size */
117 #define UNIT_PROT (1 << UNIT_V_PROT)
118 #define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ)
119 #define UNIT_DR (1 << UNIT_V_SZ) /* low order bit */
120 #define SZ_180K 000 /* disks */
123 #define SZ_1024K 001 /* drums: default size */
130 #define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ)
134 #define CW_WR 0100000 /* write vs read */
135 #define CW_V_FTRK 7 /* fhd track */
136 #define CW_M_FTRK 0177
137 #define CW_V_DTRK 5 /* drum track */
138 #define CW_M_DTRK 01777
139 #define MAX_TRK (((drc_unit.flags & UNIT_DR)? CW_M_DTRK: CW_M_FTRK) + 1)
140 #define CW_GETTRK(x) ((drc_unit.flags & UNIT_DR)? \
141 (((x) >> CW_V_DTRK) & CW_M_DTRK): \
142 (((x) >> CW_V_FTRK) & CW_M_FTRK))
143 #define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DR)? \
144 (((x) & CW_M_DTRK) << CW_V_DTRK): \
145 (((x) & CW_M_FTRK) << CW_V_FTRK))
146 #define CW_V_FSEC 0 /* fhd sector */
147 #define CW_M_FSEC 0177
148 #define CW_V_DSEC 0 /* drum sector */
149 #define CW_M_DSEC 037
150 #define CW_GETSEC(x) ((drc_unit.flags & UNIT_DR)? \
151 (((x) >> CW_V_DSEC) & CW_M_DSEC): \
152 (((x) >> CW_V_FSEC) & CW_M_FSEC))
153 #define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DR)? \
154 (((x) & CW_M_DSEC) << CW_V_DSEC): \
155 (((x) & CW_M_FSEC) << CW_V_FSEC))
157 /* Status register, ^ = dynamic */
159 #define DRS_V_NS 8 /* ^next sector */
160 #define DRS_M_NS 0177
161 #define DRS_SEC 0100000 /* ^sector flag */
162 #define DRS_RDY 0000200 /* ^ready */
163 #define DRS_RIF 0000100 /* ^read inhibit */
164 #define DRS_SAC 0000040 /* sector coincidence */
165 #define DRS_ABO 0000010 /* abort */
166 #define DRS_WEN 0000004 /* ^write enabled */
167 #define DRS_PER 0000002 /* parity error */
168 #define DRS_BSY 0000001 /* ^busy */
170 #define CALC_SCP(x) (((int32) fmod ((x) / (double) dr_time, \
171 (double) (DR_NUMWD))) >= (DR_NUMWD - 3))
173 extern UNIT cpu_unit
;
176 extern uint32 dev_cmd
[2], dev_ctl
[2], dev_flg
[2], dev_fbf
[2], dev_srq
[2];
178 int32 drc_cw
= 0; /* fnc, addr */
179 int32 drc_sta
= 0; /* status */
180 int32 drc_run
= 0; /* run flip-flop */
181 int32 drd_ibuf
= 0; /* input buffer */
182 int32 drd_obuf
= 0; /* output buffer */
183 int32 drd_ptr
= 0; /* sector pointer */
184 int32 drc_pcount
= 1; /* number of prot tracks */
185 int32 dr_stopioe
= 1; /* stop on error */
186 int32 dr_time
= DR_DTIME
; /* time per word */
188 static int32 sz_tab
[16] = {
189 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
190 0, 655360, 0, 786432, 0, 917504, 0, 0 };
192 DEVICE drd_dev
, drc_dev
;
193 int32
drdio (int32 inst
, int32 IR
, int32 dat
);
194 int32
drcio (int32 inst
, int32 IR
, int32 dat
);
195 t_stat
drc_svc (UNIT
*uptr
);
196 t_stat
drc_reset (DEVICE
*dptr
);
197 t_stat
drc_attach (UNIT
*uptr
, char *cptr
);
198 t_stat
drc_boot (int32 unitno
, DEVICE
*dptr
);
199 int32
dr_incda (int32 trk
, int32 sec
, int32 ptr
);
200 int32
dr_seccntr (double simtime
);
201 t_stat
dr_set_prot (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
202 t_stat
dr_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
204 /* DRD data structures
206 drd_dev device descriptor
207 drd_unit unit descriptor
208 drd_reg register list
212 { DRD
, 0, 0, 0, 0, 0, &drdio
},
213 { DRC
, 0, 0, 0, 0, 0, &drcio
}
216 #define drd_dib dr_dib[0]
217 #define drc_dib dr_dib[1]
220 { UDATA (NULL
, 0, 0) },
221 { UDATA (NULL
, UNIT_DIS
, 0) }
224 #define TMR_ORG 0 /* origin timer */
225 #define TMR_INH 1 /* inhibit timer */
228 { ORDATA (IBUF
, drd_ibuf
, 16) },
229 { ORDATA (OBUF
, drd_obuf
, 16) },
230 { FLDATA (CMD
, drd_dib
.cmd
, 0) },
231 { FLDATA (CTL
, drd_dib
.ctl
, 0) },
232 { FLDATA (FLG
, drd_dib
.flg
, 0) },
233 { FLDATA (FBF
, drd_dib
.fbf
, 0) },
234 { FLDATA (SRQ
, drd_dib
.srq
, 0) },
235 { ORDATA (BPTR
, drd_ptr
, 6) },
236 { ORDATA (DEVNO
, drd_dib
.devno
, 6), REG_HRO
},
241 { MTAB_XTD
| MTAB_VDV
, 1, "DEVNO", "DEVNO",
242 &hp_setdev
, &hp_showdev
, &drd_dev
},
247 "DRD", drd_unit
, drd_reg
, drd_mod
,
249 NULL
, NULL
, &drc_reset
,
251 &drd_dib
, DEV_DISABLE
254 /* DRC data structures
256 drc_dev device descriptor
257 drc_unit unit descriptor
258 drc_mod unit modifiers
259 drc_reg register list
263 UDATA (&drc_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+
264 UNIT_MUSTBUF
+UNIT_DR
+UNIT_BINK
, DR_SIZE
)
268 { DRDATA (PCNT
, drc_pcount
, 10), REG_HIDDEN
| PV_LEFT
},
269 { ORDATA (CW
, drc_cw
, 16) },
270 { ORDATA (STA
, drc_sta
, 16) },
271 { FLDATA (RUN
, drc_run
, 0) },
272 { FLDATA (CMD
, drc_dib
.cmd
, 0) },
273 { FLDATA (CTL
, drc_dib
.ctl
, 0) },
274 { FLDATA (FLG
, drc_dib
.flg
, 0) },
275 { FLDATA (FBF
, drc_dib
.fbf
, 0) },
276 { FLDATA (SRQ
, drc_dib
.srq
, 0) },
277 { DRDATA (TIME
, dr_time
, 24), REG_NZ
+ PV_LEFT
},
278 { FLDATA (STOP_IOE
, dr_stopioe
, 0) },
279 { ORDATA (DEVNO
, drc_dib
.devno
, 6), REG_HRO
},
280 { DRDATA (CAPAC
, drc_unit
.capac
, 24), REG_HRO
},
285 { UNIT_DR
, 0, "disk", NULL
, NULL
},
286 { UNIT_DR
, UNIT_DR
, "drum", NULL
, NULL
},
287 { UNIT_SZ
, (SZ_180K
<< UNIT_V_SZ
), NULL
, "180K", &dr_set_size
},
288 { UNIT_SZ
, (SZ_360K
<< UNIT_V_SZ
), NULL
, "360K", &dr_set_size
},
289 { UNIT_SZ
, (SZ_720K
<< UNIT_V_SZ
), NULL
, "720K", &dr_set_size
},
290 { UNIT_SZ
, (SZ_384K
<< UNIT_V_SZ
), NULL
, "384K", &dr_set_size
},
291 { UNIT_SZ
, (SZ_512K
<< UNIT_V_SZ
), NULL
, "512K", &dr_set_size
},
292 { UNIT_SZ
, (SZ_640K
<< UNIT_V_SZ
), NULL
, "640K", &dr_set_size
},
293 { UNIT_SZ
, (SZ_768K
<< UNIT_V_SZ
), NULL
, "768K", &dr_set_size
},
294 { UNIT_SZ
, (SZ_896K
<< UNIT_V_SZ
), NULL
, "896K", &dr_set_size
},
295 { UNIT_SZ
, (SZ_1024K
<< UNIT_V_SZ
), NULL
, "1024K", &dr_set_size
},
296 { UNIT_SZ
, (SZ_1536K
<< UNIT_V_SZ
), NULL
, "1536K", &dr_set_size
},
297 { UNIT_PROT
, UNIT_PROT
, "protected", "PROTECTED", NULL
},
298 { UNIT_PROT
, 0, "unprotected", "UNPROTECTED", NULL
},
299 { MTAB_XTD
| MTAB_VDV
| MTAB_VAL
, 0, "tracks protected", "TRACKPROT",
300 &dr_set_prot
, NULL
, &drc_reg
[0] },
301 { MTAB_XTD
| MTAB_VDV
, 1, "DEVNO", "DEVNO",
302 &hp_setdev
, &hp_showdev
, &drd_dev
},
307 "DRC", &drc_unit
, drc_reg
, drc_mod
,
309 NULL
, NULL
, &drc_reset
,
310 &drc_boot
, &drc_attach
, NULL
,
311 &drc_dib
, DEV_DISABLE
314 /* IO instructions */
316 int32
drdio (int32 inst
, int32 IR
, int32 dat
)
320 devd
= IR
& I_DEVMASK
; /* get device no */
321 switch (inst
) { /* case on opcode */
323 case ioOTX
: /* output */
327 case ioMIX
: /* merge */
328 dat
= dat
| drd_ibuf
;
331 case ioLIX
: /* load */
335 case ioCRS
: /* control reset (action unverif) */
336 case ioCTL
: /* control clear/set */
337 if (IR
& I_AB
) { /* CLC */
338 clrCMD (devd
); /* clr "ctl" */
339 clrFSR (devd
); /* clr flg */
340 if (!drc_run
) sim_cancel (&drc_unit
); /* cancel curr op */
341 drc_sta
= drc_sta
& ~DRS_SAC
; /* clear SAC flag */
343 else if (!CMD (devd
)) { /* STC, not set? */
344 setCMD (devd
); /* set "ctl" */
345 if (drc_cw
& CW_WR
) { setFSR (devd
); } /* prime DMA */
346 drc_sta
= 0; /* clr status */
347 drd_ptr
= 0; /* clear sec ptr */
348 sim_cancel (&drc_unit
); /* cancel curr op */
349 t
= CW_GETSEC (drc_cw
) - dr_seccntr (sim_gtime());
350 if (t
<= 0) t
= t
+ DR_NUMSC
;
351 sim_activate (&drc_unit
, t
* DR_NUMWD
* dr_time
);
359 if (IR
& I_HC
) { clrFSR (devd
); } /* H/C option */
363 int32
drcio (int32 inst
, int32 IR
, int32 dat
)
367 switch (inst
) { /* case on opcode */
369 case ioFLG
: /* flag clear/set */
370 if ((IR
& I_HC
) && !(drc_unit
.flags
& UNIT_DR
)) { /* CLF disk */
371 sec
= dr_seccntr (sim_gtime ()); /* current sector */
372 sim_cancel (&drd_unit
[TMR_ORG
]); /* sched origin tmr */
373 sim_activate (&drd_unit
[TMR_ORG
],
374 (DR_FNUMSC
- sec
) * DR_NUMWD
* dr_time
);
378 case ioSFC
: /* skip flag clear */
379 if (drc_unit
.flags
& UNIT_DR
) break; /* 12610 never skips */
380 if (!(CALC_SCP (sim_gtime()))) /* nearing end of sector? */
381 PC
= (PC
+ 1) & VAMASK
; /* skip if SCP clear */
384 case ioSFS
: /* skip flag set */
385 if (drc_unit
.flags
& UNIT_DR
) break; /* 12610 never skips */
386 if (!sim_is_active (&drd_unit
[TMR_ORG
])) /* passed origin? */
387 PC
= (PC
+ 1) & VAMASK
; /* skip if origin seen */
390 case ioOTX
: /* output */
391 if (!(drc_unit
.flags
& UNIT_DR
)) { /* disk? */
392 sim_cancel (&drd_unit
[TMR_INH
]); /* schedule inhibit timer */
393 sim_activate (&drd_unit
[TMR_INH
], DR_FTIME
* DR_NUMWD
);
395 drc_cw
= dat
; /* get control word */
398 case ioLIX
: /* load */
400 case ioMIX
: /* merge */
401 dat
= dat
| drc_sta
; /* static bits */
402 if (!(drc_unit
.flags
& UNIT_PROT
) || /* not protected? */
403 (CW_GETTRK(drc_cw
) >= drc_pcount
)) /* or not in range? */
404 dat
= dat
| DRS_WEN
; /* set wrt enb status */
405 if (drc_unit
.flags
& UNIT_ATT
) { /* attached? */
406 dat
= dat
| (dr_seccntr (sim_gtime()) << DRS_V_NS
) | DRS_RDY
;
407 if (sim_is_active (&drc_unit
)) /* op in progress? */
409 if (CALC_SCP (sim_gtime())) /* SCP ff set? */
410 dat
= dat
| DRS_SEC
; /* set sector flag */
411 if (sim_is_active (&drd_unit
[TMR_INH
]) && /* inhibit timer on? */
413 dat
= dat
| DRS_RIF
; /* set read inh flag */
426 t_stat
drc_svc (UNIT
*uptr
)
428 int32 devd
, trk
, sec
;
430 uint16
*bptr
= (uint16
*) uptr
->filebuf
;
432 if ((uptr
->flags
& UNIT_ATT
) == 0) {
434 return IORETURN (dr_stopioe
, SCPE_UNATT
);
437 devd
= drd_dib
.devno
; /* get dch devno */
438 trk
= CW_GETTRK (drc_cw
);
439 sec
= CW_GETSEC (drc_cw
);
440 da
= ((trk
* DR_NUMSC
) + sec
) * DR_NUMWD
;
441 drc_sta
= drc_sta
| DRS_SAC
;
442 drc_run
= 1; /* set run ff */
444 if (drc_cw
& CW_WR
) { /* write? */
445 if ((da
< uptr
->capac
) && (sec
< DR_NUMSC
)) {
446 bptr
[da
+ drd_ptr
] = drd_obuf
;
447 if (((uint32
) (da
+ drd_ptr
)) >= uptr
->hwmark
)
448 uptr
->hwmark
= da
+ drd_ptr
+ 1;
450 drd_ptr
= dr_incda (trk
, sec
, drd_ptr
); /* inc disk addr */
451 if (CMD (devd
)) { /* dch active? */
452 setFSR (devd
); /* set dch flg */
453 sim_activate (uptr
, dr_time
); /* sched next word */
456 if (drd_ptr
) /* need to fill? */
457 for ( ; drd_ptr
< DR_NUMWD
; drd_ptr
++)
458 bptr
[da
+ drd_ptr
] = drd_obuf
; /* fill with last word */
459 if (!(drc_unit
.flags
& UNIT_DR
)) /* disk? */
460 drc_sta
= drc_sta
| DRS_PER
; /* parity bit sets on write */
461 drc_run
= 0; /* clear run ff */
465 if (CMD (devd
)) { /* dch active? */
466 if ((da
>= uptr
->capac
) || (sec
>= DR_NUMSC
)) drd_ibuf
= 0;
467 else drd_ibuf
= bptr
[da
+ drd_ptr
];
468 drd_ptr
= dr_incda (trk
, sec
, drd_ptr
);
469 setFSR (devd
); /* set dch flg */
470 sim_activate (uptr
, dr_time
); /* sched next word */
472 else drc_run
= 0; /* clear run ff */
477 /* Increment current disk address */
479 int32
dr_incda (int32 trk
, int32 sec
, int32 ptr
)
481 ptr
= ptr
+ 1; /* inc pointer */
482 if (ptr
>= DR_NUMWD
) { /* end sector? */
483 ptr
= 0; /* new sector */
484 sec
= sec
+ 1; /* adv sector */
485 if (sec
>= DR_NUMSC
) { /* end track? */
486 sec
= 0; /* new track */
487 trk
= trk
+ 1; /* adv track */
488 if (trk
>= MAX_TRK
) trk
= 0; /* wraps at max */
490 drc_cw
= (drc_cw
& CW_WR
) | CW_PUTTRK (trk
) | CW_PUTSEC (sec
);
495 /* Read the sector counter
497 The hardware sector counter contains the number of the next sector that will
498 pass under the heads (so it is one ahead of the current sector). For the
499 duration of the last sector of the track, the sector counter contains 90 for
500 the 12606 and 0 for the 12610. The sector counter resets to 0 at track
501 origin and increments at the start of the first sector. Therefore, the
502 counter value ranges from 0-90 for the 12606 and 0-31 for the 12610. The 0
503 state is quite short in the 12606 and long in the 12610, relative to the
504 other sector counter states.
506 The simulated sector counter is calculated from the simulation time, based on
507 the time per word and the number of words per track.
510 int32
dr_seccntr (double simtime
)
514 curword
= (int32
) fmod (simtime
/ (double) dr_time
,
515 (double) (DR_NUMWD
* DR_NUMSC
+ DR_OVRHEAD
));
516 if (curword
<= DR_OVRHEAD
) return 0;
517 else return ((curword
- DR_OVRHEAD
) / DR_NUMWD
+
518 ((drc_unit
.flags
& UNIT_DR
)? 0: 1));
523 t_stat
drc_reset (DEVICE
*dptr
)
525 hp_enbdis_pair (dptr
, /* make pair cons */
526 (dptr
== &drd_dev
)? &drc_dev
: &drd_dev
);
527 drc_sta
= drc_cw
= drd_ptr
= 0;
528 drc_dib
.cmd
= drd_dib
.cmd
= 0; /* clear cmd */
529 drc_dib
.ctl
= drd_dib
.ctl
= 0; /* clear ctl */
530 drc_dib
.fbf
= drd_dib
.fbf
= 0; /* clear fbf */
531 drc_dib
.flg
= drd_dib
.flg
= 0; /* clear flg */
532 drc_dib
.srq
= drd_dib
.srq
= 0; /* srq follows flg */
533 sim_cancel (&drc_unit
);
534 sim_cancel (&drd_unit
[TMR_ORG
]);
535 sim_cancel (&drd_unit
[TMR_INH
]);
541 t_stat
drc_attach (UNIT
*uptr
, char *cptr
)
543 int32 sz
= sz_tab
[DR_GETSZ (uptr
->flags
)];
545 if (sz
== 0) return SCPE_IERR
;
547 return attach_unit (uptr
, cptr
);
550 /* Set protected track count */
552 t_stat
dr_set_prot (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
557 if (cptr
== NULL
) return SCPE_ARG
;
558 count
= (int32
) get_uint (cptr
, 10, 768, &status
);
559 if (status
!= SCPE_OK
) return status
;
560 else switch (count
) {
574 if (drc_unit
.flags
& UNIT_DR
) drc_pcount
= count
;
575 else return SCPE_ARG
;
583 /* Set size routine */
585 t_stat
dr_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
590 if (val
< 0) return SCPE_IERR
;
591 if ((sz
= sz_tab
[szindex
= DR_GETSZ (val
)]) == 0) return SCPE_IERR
;
592 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
594 if (szindex
& UNIT_DR
) dr_time
= DR_DTIME
; /* drum */
596 dr_time
= DR_FTIME
; /* disk */
597 if (drc_pcount
> 128) drc_pcount
= 128; /* max prot track count */
602 /* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */
604 #define BOOT_BASE 056
605 #define BOOT_START 060
607 static const uint16 dr_rom
[IBL_LNT
- BOOT_BASE
] = {
608 0020010, /*DMA 20000+DC */
610 0107700, /* CLC 0,C */
611 0063756, /* LDA DMA ; DMA ctrl */
613 0002700, /* CLA,CCE */
614 0102611, /* OTA CC ; trk = sec = 0 */
615 0001500, /* ERA ; A = 100000 */
616 0102602, /* OTA 2 ; DMA in, addr */
617 0063777, /* LDA M64 */
619 0102602, /* OTA 2 ; DMA wc = -64 */
620 0103706, /* STC 6,C ; start DMA */
621 0067776, /* LDB JSF ; get JMP . */
622 0074077, /* STB 77 ; in base page */
623 0102710, /* STC DC ; start disc */
624 0024077, /*JSF JMP 77 ; go wait */
625 0177700 /*M64 -100 */
628 t_stat
drc_boot (int32 unitno
, DEVICE
*dptr
)
633 if (unitno
!= 0) return SCPE_NOFNC
; /* only unit 0 */
634 dev
= drd_dib
.devno
; /* get data chan dev */
635 ad
= ((MEMSIZE
- 1) & ~IBL_MASK
) & VAMASK
; /* start at mem top */
636 for (i
= BOOT_BASE
; i
< IBL_LNT
; i
++) { /* copy bootstrap */
637 wd
= dr_rom
[i
- BOOT_BASE
]; /* get word */
638 if (((wd
& I_NMRMASK
) == I_IO
) && /* IO instruction? */
639 ((wd
& I_DEVMASK
) >= 010) && /* dev >= 10? */
640 (I_GETIOOP (wd
) != ioHLT
)) /* not a HALT? */
641 M
[ad
+ i
] = (wd
+ (dev
- 010)) & DMASK
;
644 PC
= ad
+ BOOT_START
;