First Commit of my working state
[simh.git] / HP2100 / hp2100_dr.c
1 /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
2
3 Copyright (c) 1993-2006, 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 dr 12606B 2770/2771 fixed head disk
27 12610B 2773/2774/2775 drum
28
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
49
50 These head-per-track devices are buffered in memory, to minimize overhead.
51
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.
56
57 The drum control channel does not have any of the traditional flip-flops.
58
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.
65
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.
70
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.
75
76 Specifications (2770/2771):
77 - 90 sectors per logical track
78 - 45 sectors per revolution
79 - 64 words per sector
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
84
85 Specifications 2773/2774/2775:
86 - 32 sectors per logical track
87 - 32 sectors per revolution
88 - 64 words per sector
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
93
94 References:
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)
99 */
100
101 #include "hp2100_defs.h"
102 #include <math.h>
103
104 /* Constants */
105
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 */
121 #define SZ_360K 002
122 #define SZ_720K 004
123 #define SZ_1024K 001 /* drums: default size */
124 #define SZ_1536K 003
125 #define SZ_384K 005
126 #define SZ_512K 007
127 #define SZ_640K 011
128 #define SZ_768K 013
129 #define SZ_896K 015
130 #define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ)
131
132 /* Command word */
133
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))
156
157 /* Status register, ^ = dynamic */
158
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 */
169
170 #define CALC_SCP(x) (((int32) fmod ((x) / (double) dr_time, \
171 (double) (DR_NUMWD))) >= (DR_NUMWD - 3))
172
173 extern UNIT cpu_unit;
174 extern uint16 *M;
175 extern uint32 PC;
176 extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
177
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 */
187
188 static int32 sz_tab[16] = {
189 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
190 0, 655360, 0, 786432, 0, 917504, 0, 0 };
191
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);
203
204 /* DRD data structures
205
206 drd_dev device descriptor
207 drd_unit unit descriptor
208 drd_reg register list
209 */
210
211 DIB dr_dib[] = {
212 { DRD, 0, 0, 0, 0, 0, &drdio },
213 { DRC, 0, 0, 0, 0, 0, &drcio }
214 };
215
216 #define drd_dib dr_dib[0]
217 #define drc_dib dr_dib[1]
218
219 UNIT drd_unit[] = {
220 { UDATA (NULL, 0, 0) },
221 { UDATA (NULL, UNIT_DIS, 0) }
222 };
223
224 #define TMR_ORG 0 /* origin timer */
225 #define TMR_INH 1 /* inhibit timer */
226
227 REG drd_reg[] = {
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 },
237 { NULL }
238 };
239
240 MTAB drd_mod[] = {
241 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
242 &hp_setdev, &hp_showdev, &drd_dev },
243 { 0 }
244 };
245
246 DEVICE drd_dev = {
247 "DRD", drd_unit, drd_reg, drd_mod,
248 2, 0, 0, 0, 0, 0,
249 NULL, NULL, &drc_reset,
250 NULL, NULL, NULL,
251 &drd_dib, DEV_DISABLE
252 };
253
254 /* DRC data structures
255
256 drc_dev device descriptor
257 drc_unit unit descriptor
258 drc_mod unit modifiers
259 drc_reg register list
260 */
261
262 UNIT drc_unit = {
263 UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
264 UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE)
265 };
266
267 REG drc_reg[] = {
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 },
281 { NULL }
282 };
283
284 MTAB drc_mod[] = {
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 },
303 { 0 }
304 };
305
306 DEVICE drc_dev = {
307 "DRC", &drc_unit, drc_reg, drc_mod,
308 1, 8, 21, 1, 8, 16,
309 NULL, NULL, &drc_reset,
310 &drc_boot, &drc_attach, NULL,
311 &drc_dib, DEV_DISABLE
312 };
313
314 /* IO instructions */
315
316 int32 drdio (int32 inst, int32 IR, int32 dat)
317 {
318 int32 devd, t;
319
320 devd = IR & I_DEVMASK; /* get device no */
321 switch (inst) { /* case on opcode */
322
323 case ioOTX: /* output */
324 drd_obuf = dat;
325 break;
326
327 case ioMIX: /* merge */
328 dat = dat | drd_ibuf;
329 break;
330
331 case ioLIX: /* load */
332 dat = drd_ibuf;
333 break;
334
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 */
342 }
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);
352 }
353 break;
354
355 default:
356 break;
357 }
358
359 if (IR & I_HC) { clrFSR (devd); } /* H/C option */
360 return dat;
361 }
362
363 int32 drcio (int32 inst, int32 IR, int32 dat)
364 {
365 int32 sec;
366
367 switch (inst) { /* case on opcode */
368
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);
375 }
376 break;
377
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 */
382 break;
383
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 */
388 break;
389
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);
394 }
395 drc_cw = dat; /* get control word */
396 break;
397
398 case ioLIX: /* load */
399 dat = 0;
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? */
408 dat = dat | DRS_BSY;
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? */
412 !(drc_cw & CW_WR))
413 dat = dat | DRS_RIF; /* set read inh flag */
414 }
415 break;
416
417 default:
418 break;
419 }
420
421 return dat;
422 }
423
424 /* Unit service */
425
426 t_stat drc_svc (UNIT *uptr)
427 {
428 int32 devd, trk, sec;
429 uint32 da;
430 uint16 *bptr = (uint16 *) uptr->filebuf;
431
432 if ((uptr->flags & UNIT_ATT) == 0) {
433 drc_sta = DRS_ABO;
434 return IORETURN (dr_stopioe, SCPE_UNATT);
435 }
436
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 */
443
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;
449 }
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 */
454 }
455 else { /* done */
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 */
462 }
463 } /* end write */
464 else { /* read */
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 */
471 }
472 else drc_run = 0; /* clear run ff */
473 }
474 return SCPE_OK;
475 }
476
477 /* Increment current disk address */
478
479 int32 dr_incda (int32 trk, int32 sec, int32 ptr)
480 {
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 */
489 }
490 drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec);
491 }
492 return ptr;
493 }
494
495 /* Read the sector counter
496
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.
505
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.
508 */
509
510 int32 dr_seccntr (double simtime)
511 {
512 int32 curword;
513
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));
519 }
520
521 /* Reset routine */
522
523 t_stat drc_reset (DEVICE *dptr)
524 {
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]);
536 return SCPE_OK;
537 }
538
539 /* Attach routine */
540
541 t_stat drc_attach (UNIT *uptr, char *cptr)
542 {
543 int32 sz = sz_tab[DR_GETSZ (uptr->flags)];
544
545 if (sz == 0) return SCPE_IERR;
546 uptr->capac = sz;
547 return attach_unit (uptr, cptr);
548 }
549
550 /* Set protected track count */
551
552 t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc)
553 {
554 int32 count;
555 t_stat status;
556
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) {
561 case 1:
562 case 2:
563 case 4:
564 case 8:
565 case 16:
566 case 32:
567 case 64:
568 case 128:
569 drc_pcount = count;
570 break;
571 case 256:
572 case 512:
573 case 768:
574 if (drc_unit.flags & UNIT_DR) drc_pcount = count;
575 else return SCPE_ARG;
576 break;
577 default:
578 return SCPE_ARG;
579 }
580 return SCPE_OK;
581 }
582
583 /* Set size routine */
584
585 t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
586 {
587 int32 sz;
588 int32 szindex;
589
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;
593 uptr->capac = sz;
594 if (szindex & UNIT_DR) dr_time = DR_DTIME; /* drum */
595 else {
596 dr_time = DR_FTIME; /* disk */
597 if (drc_pcount > 128) drc_pcount = 128; /* max prot track count */
598 }
599 return SCPE_OK;
600 }
601
602 /* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */
603
604 #define BOOT_BASE 056
605 #define BOOT_START 060
606
607 static const uint16 dr_rom[IBL_LNT - BOOT_BASE] = {
608 0020010, /*DMA 20000+DC */
609 0000000, /* 0 */
610 0107700, /* CLC 0,C */
611 0063756, /* LDA DMA ; DMA ctrl */
612 0102606, /* OTA 6 */
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 */
618 0102702, /* STC 2 */
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 */
626 };
627
628 t_stat drc_boot (int32 unitno, DEVICE *dptr)
629 {
630 int32 i, dev, ad;
631 uint16 wd;
632
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;
642 else M[ad + i] = wd;
643 }
644 PC = ad + BOOT_START;
645 return SCPE_OK;
646 }