First Commit of my working state
[simh.git] / HP2100 / hp2100_ms.c
1 /* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape 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 ms 13181A 7970B 800bpi nine track magnetic tape
27 13183A 7970E 1600bpi nine track magnetic tape
28
29 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified)
30 18-Sep-06 JDB Fixed 2nd CLR after WC causing another write
31 Improve debug reporting, add debug flags
32 14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot
33 30-Aug-06 JDB Added erase gap support, improved tape lib err reporting
34 07-Jul-06 JDB Added CAPACITY as alternate for REEL
35 Fixed EOT test for unlimited reel size
36 16-Feb-06 RMS Revised for new EOT test
37 22-Jul-05 RMS Fixed compiler warning on Solaris (from Doug Glyn)
38 01-Mar-05 JDB Added SET OFFLINE; rewind/offline now does not detach
39 07-Oct-04 JDB Fixed enable/disable from either device
40 14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan)
41 - fixed erroneous execution of rejected command
42 - fixed erroneous execution of select-only command
43 - fixed erroneous execution of clear command
44 - fixed odd byte handling for read
45 - fixed spurious odd byte status on 13183A EOF
46 - modified handling of end of medium
47 - added detailed timing, with fast and realistic modes
48 - added reel sizes to simulate end of tape
49 - added debug printouts
50 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)
51 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
52 Fixed SR setting in IBL
53 Revised IBL loader
54 Implemented DMA SRQ (follows FLG)
55 25-Apr-03 RMS Revised for extended file support
56 28-Mar-03 RMS Added multiformat support
57 28-Feb-03 RMS Revised for magtape library
58 18-Oct-02 RMS Added BOOT command, added 13183A support
59 30-Sep-02 RMS Revamped error handling
60 29-Aug-02 RMS Added end of medium support
61 30-May-02 RMS Widened POS to 32b
62 22-Apr-02 RMS Added maximum record length test
63
64 Magnetic tapes are represented as a series of variable records
65 of the form:
66
67 32b byte count
68 byte 0
69 byte 1
70 :
71 byte n-2
72 byte n-1
73 32b byte count
74
75 If the byte count is odd, the record is padded with an extra byte
76 of junk. File marks are represented by a byte count of 0.
77
78 References:
79 - 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
80 (13181-90901, Nov-1982)
81 - 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
82 (13183-90901, Nov-1983)
83 */
84
85 #include "hp2100_defs.h"
86 #include "sim_tape.h"
87
88 #define UNIT_V_OFFLINE (MTUF_V_UF + 0) /* unit offline */
89 #define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
90
91 #define MS_NUMDR 4 /* number of drives */
92 #define DB_N_SIZE 16 /* max data buf */
93 #define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
94 #define FNC u3 /* function */
95 #define UST u4 /* unit status */
96 #define REEL u5 /* tape reel size */
97
98 #define BPI_13181 800 /* 800 bpi for 13181 cntlr */
99 #define BPI_13183 1600 /* 1600 bpi for 13183 cntlr */
100 #define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */
101 #define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */
102 #define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */
103
104 /* Debug flags */
105
106 #define DEB_CMDS (1 << 0) /* command init and compl */
107 #define DEB_CPU (1 << 1) /* CPU I/O */
108 #define DEB_RWS (1 << 2) /* tape reads, writes, status */
109
110 /* Command - msc_fnc */
111
112 #define FNC_CLR 00110 /* clear */
113 #define FNC_GAP 00015 /* write gap */
114 #define FNC_GFM 00215 /* gap+file mark */
115 #define FNC_RC 00023 /* read */
116 #define FNC_WC 00031 /* write */
117 #define FNC_FSR 00003 /* forward space */
118 #define FNC_BSR 00041 /* backward space */
119 #define FNC_FSF 00203 /* forward file */
120 #define FNC_BSF 00241 /* backward file */
121 #define FNC_REW 00101 /* rewind */
122 #define FNC_RWS 00105 /* rewind and offline */
123 #define FNC_WFM 00211 /* write file mark */
124 #define FNC_RFF 00223 /* read file fwd (diag) */
125 #define FNC_RRR 00061 /* read record rev (diag) */
126 #define FNC_CMPL 00400 /* completion state */
127 #define FNC_V_SEL 9 /* select */
128 #define FNC_M_SEL 017
129 #define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL)
130
131 #define FNF_MOT 00001 /* motion */
132 #define FNF_OFL 00004
133 #define FNF_WRT 00010 /* write */
134 #define FNF_REV 00040 /* reverse */
135 #define FNF_RWD 00100 /* rewind */
136 #define FNF_CHS 00400 /* change select */
137
138 #define FNC_SEL ((FNC_M_SEL << FNC_V_SEL) | FNF_CHS)
139
140 /* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */
141
142 #define STA_PE 0100000 /* 1600 bpi (d) */
143 #define STA_V_SEL 13 /* unit sel (d) */
144 #define STA_M_SEL 03
145 #define STA_SEL (STA_M_SEL << STA_V_SEL)
146 #define STA_ODD 0004000 /* odd bytes */
147 #define STA_REW 0002000 /* rewinding (u) */
148 #define STA_TBSY 0001000 /* transport busy (d) */
149 #define STA_BUSY 0000400 /* ctrl busy */
150 #define STA_EOF 0000200 /* end of file */
151 #define STA_BOT 0000100 /* beg of tape (d) */
152 #define STA_EOT 0000040 /* end of tape (d) */
153 #define STA_TIM 0000020 /* timing error */
154 #define STA_REJ 0000010 /* programming error */
155 #define STA_WLK 0000004 /* write locked (d) */
156 #define STA_PAR 0000002 /* parity error */
157 #define STA_LOCAL 0000001 /* local (d) */
158 #define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \
159 STA_EOT | STA_WLK | STA_LOCAL)
160
161 extern uint32 PC, SR;
162 extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
163 extern int32 sim_switches;
164 extern FILE *sim_deb;
165
166 int32 ms_ctype = 0; /* ctrl type */
167 int32 ms_timing = 1; /* timing type */
168 int32 msc_sta = 0; /* status */
169 int32 msc_buf = 0; /* buffer */
170 int32 msc_usl = 0; /* unit select */
171 int32 msc_1st = 0; /* first service */
172 int32 msc_stopioe = 1; /* stop on error */
173 int32 msd_buf = 0; /* data buffer */
174 uint8 msxb[DBSIZE] = { 0 }; /* data buffer */
175 t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */
176
177 /* Hardware timing at 45 IPS 13181 13183
178 (based on 1580 instr/msec) instr msec SCP instr msec SCP
179 -------------------- --------------------
180 - BOT start delay : btime = 161512 102.22 184 252800 160.00 288
181 - motion cmd start delay : ctime = 14044 8.89 16 17556 11.11 20
182 - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120
183 - IRG traversal time : itime = 24885 15.75 - 27387 17.33 -
184 - rewind initiation time : rtime = 878 0.56 1 878 0.56 1
185 - data xfer time / word : xtime = 88 55.56us - 44 27.78us -
186
187 NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with
188 "E116 BYTE TIME SHORT" if the correct data transfer time is used for
189 13181A interface. Set "xtime" to 115 (instructions) to pass that
190 diagnostic. Rev. 2040 of the tape diagnostic fixes this problem and
191 passes with the correct data transfer time.
192 */
193
194 int32 msc_btime = 0; /* BOT start delay */
195 int32 msc_ctime = 0; /* motion cmd start delay */
196 int32 msc_gtime = 0; /* GAP traversal time */
197 int32 msc_itime = 0; /* IRG traversal time */
198 int32 msc_rtime = 0; /* rewind initiation time */
199 int32 msc_xtime = 0; /* data xfer time / word */
200
201 typedef int32 TIMESET[6]; /* set of controller times */
202
203 int32 *const timers[] = { &msc_btime, &msc_ctime, &msc_gtime,
204 &msc_itime, &msc_rtime, &msc_xtime };
205
206 const TIMESET msc_times[3] = {
207 { 161512, 14044, 175553, 24885, 878, 88 }, /* 13181A */
208 { 252800, 17556, 105333, 27387, 878, 44 }, /* 13183A */
209 { 1, 1000, 1, 1, 100, 10 } /* FAST */
210 };
211
212 DEVICE msd_dev, msc_dev;
213 int32 msdio (int32 inst, int32 IR, int32 dat);
214 int32 mscio (int32 inst, int32 IR, int32 dat);
215 t_stat msc_svc (UNIT *uptr);
216 t_stat msc_reset (DEVICE *dptr);
217 t_stat msc_attach (UNIT *uptr, char *cptr);
218 t_stat msc_detach (UNIT *uptr);
219 t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc);
220 t_stat msc_boot (int32 unitno, DEVICE *dptr);
221 t_stat ms_write_gap (UNIT *uptr);
222 t_stat ms_map_err (UNIT *uptr, t_stat st);
223 t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
224 t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
225 t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc);
226 t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);
227 t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc);
228 t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc);
229 void ms_config_timing (void);
230 char *ms_cmd_name (uint32 cmd);
231
232 /* MSD data structures
233
234 msd_dev MSD device descriptor
235 msd_unit MSD unit list
236 msd_reg MSD register list
237 */
238
239 DIB ms_dib[] = {
240 { MSD, 0, 0, 0, 0, 0, &msdio },
241 { MSC, 0, 0, 0, 0, 0, &mscio }
242 };
243
244 #define msd_dib ms_dib[0]
245 #define msc_dib ms_dib[1]
246
247 UNIT msd_unit = { UDATA (NULL, 0, 0) };
248
249 REG msd_reg[] = {
250 { ORDATA (BUF, msd_buf, 16) },
251 { FLDATA (CMD, msd_dib.cmd, 0), REG_HRO },
252 { FLDATA (CTL, msd_dib.ctl, 0) },
253 { FLDATA (FLG, msd_dib.flg, 0) },
254 { FLDATA (FBF, msd_dib.fbf, 0) },
255 { FLDATA (SRQ, msd_dib.srq, 0) },
256 { BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
257 { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
258 { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
259 { ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
260 { NULL }
261 };
262
263 MTAB msd_mod[] = {
264 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
265 &hp_setdev, &hp_showdev, &msd_dev },
266 { 0 }
267 };
268
269 DEVICE msd_dev = {
270 "MSD", &msd_unit, msd_reg, msd_mod,
271 1, 10, DB_N_SIZE, 1, 8, 8,
272 NULL, NULL, &msc_reset,
273 NULL, NULL, NULL,
274 &msd_dib, DEV_DISABLE
275 };
276
277 /* MSC data structures
278
279 msc_dev MSC device descriptor
280 msc_unit MSC unit list
281 msc_reg MSC register list
282 msc_mod MSC modifier list
283 msc_deb MSC debug flags
284 */
285
286 UNIT msc_unit[] = {
287 { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE |
288 UNIT_DISABLE | UNIT_OFFLINE, 0) },
289 { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE |
290 UNIT_DISABLE | UNIT_OFFLINE, 0) },
291 { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE |
292 UNIT_DISABLE | UNIT_OFFLINE, 0) },
293 { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE |
294 UNIT_DISABLE | UNIT_OFFLINE, 0) }
295 };
296
297 REG msc_reg[] = {
298 { ORDATA (STA, msc_sta, 12) },
299 { ORDATA (BUF, msc_buf, 16) },
300 { ORDATA (USEL, msc_usl, 2) },
301 { FLDATA (FSVC, msc_1st, 0) },
302 { FLDATA (CMD, msc_dib.cmd, 0), REG_HRO },
303 { FLDATA (CTL, msc_dib.ctl, 0) },
304 { FLDATA (FLG, msc_dib.flg, 0) },
305 { FLDATA (FBF, msc_dib.fbf, 0) },
306 { FLDATA (SRQ, msc_dib.srq, 0) },
307 { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) },
308 { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) },
309 { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) },
310 { URDATA (REEL, msc_unit[0].REEL, 10, 2, 0, MS_NUMDR, REG_HRO) },
311 { DRDATA (BTIME, msc_btime, 24), REG_NZ + PV_LEFT },
312 { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT },
313 { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT },
314 { DRDATA (ITIME, msc_itime, 24), REG_NZ + PV_LEFT },
315 { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT },
316 { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT },
317 { FLDATA (TIMING, ms_timing, 0), REG_HRO },
318 { FLDATA (STOP_IOE, msc_stopioe, 0) },
319 { FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
320 { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO },
321 { NULL }
322 };
323
324 MTAB msc_mod[] = {
325 { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },
326 { UNIT_OFFLINE, 0, "online", "ONLINE", msc_online },
327 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
328 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
329 { MTAB_XTD | MTAB_VUN, 0, "CAPACITY", "CAPACITY",
330 &ms_set_reelsize, &ms_show_reelsize, NULL },
331 { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "REEL", "REEL",
332 &ms_set_reelsize, &ms_show_reelsize, NULL },
333 { MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT",
334 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
335 { MTAB_XTD | MTAB_VDV, 0, NULL, "13181A",
336 &ms_settype, NULL, NULL },
337 { MTAB_XTD | MTAB_VDV, 1, NULL, "13183A",
338 &ms_settype, NULL, NULL },
339 { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
340 NULL, &ms_showtype, NULL },
341 { MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME",
342 &ms_set_timing, NULL, NULL },
343 { MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME",
344 &ms_set_timing, NULL, NULL },
345 { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL,
346 NULL, &ms_show_timing, NULL },
347 { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
348 &hp_setdev, &hp_showdev, &msd_dev },
349 { 0 }
350 };
351
352 DEBTAB msc_deb[] = {
353 { "CMDS", DEB_CMDS },
354 { "CPU", DEB_CPU },
355 { "RWS", DEB_RWS },
356 { NULL, 0 }
357 };
358
359 DEVICE msc_dev = {
360 "MSC", msc_unit, msc_reg, msc_mod,
361 MS_NUMDR, 10, 31, 1, 8, 8,
362 NULL, NULL, &msc_reset,
363 &msc_boot, &msc_attach, &msc_detach,
364 &msc_dib, DEV_DISABLE | DEV_DEBUG,
365 0, msc_deb, NULL, NULL
366 };
367
368 /* IO instructions */
369
370 int32 msdio (int32 inst, int32 IR, int32 dat)
371 {
372 int32 devd;
373
374 devd = IR & I_DEVMASK; /* get device no */
375 switch (inst) { /* case on opcode */
376
377 case ioFLG: /* flag clear/set */
378 if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */
379 break;
380
381 case ioSFC: /* skip flag clear */
382 if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
383 break;
384
385 case ioSFS: /* skip flag set */
386 if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
387 break;
388
389 case ioOTX: /* output */
390 msd_buf = dat; /* store data */
391 break;
392
393 case ioMIX: /* merge */
394 dat = dat | msd_buf;
395 break;
396
397 case ioLIX: /* load */
398 dat = msd_buf;
399 break;
400
401 case ioCRS: /* control reset (action unverif) */
402 case ioCTL: /* control clear/set */
403 if (IR & I_CTL) { /* CLC */
404 clrCTL (devd); /* clr ctl, cmd */
405 clrCMD (devd);
406 }
407 else { /* STC */
408 setCTL (devd); /* set ctl, cmd */
409 setCMD (devd);
410 }
411 break;
412
413 case ioEDT: /* DMA end */
414 clrFSR (devd); /* same as CLF */
415 break;
416
417 default:
418 break;
419 }
420
421 if (IR & I_HC) { clrFSR (devd); } /* H/C option */
422 return dat;
423 }
424
425 int32 mscio (int32 inst, int32 IR, int32 dat)
426 {
427 int32 i, devc, devd, sched_time;
428 t_stat st;
429 UNIT *uptr = msc_dev.units + msc_usl;
430 static const uint8 map_sel[16] = {
431 0, 0, 1, 1, 2, 2, 2, 2,
432 3, 3, 3, 3, 3, 3, 3, 3
433 };
434
435 devc = IR & I_DEVMASK; /* get device no */
436 devd = devc - 1;
437 switch (inst) { /* case on opcode */
438
439 case ioFLG: /* flag clear/set */
440 if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */
441 break;
442
443 case ioSFC: /* skip flag clear */
444 if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
445 break;
446
447 case ioSFS: /* skip flag set */
448 if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
449 break;
450
451 case ioOTX: /* output */
452 if (DEBUG_PRI (msc_dev, DEB_CPU))
453 fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", dat);
454 msc_buf = dat;
455 msc_sta = msc_sta & ~STA_REJ; /* clear reject */
456 if ((dat & 0377) == FNC_CLR) break; /* clear always ok */
457 if (msc_sta & STA_BUSY) { /* busy? reject */
458 msc_sta = msc_sta | STA_REJ; /* dont chg select */
459 break;
460 }
461 if (dat & FNF_CHS) { /* select change */
462 msc_usl = map_sel[FNC_GETSEL (dat)]; /* is immediate */
463 uptr = msc_dev.units + msc_usl;
464 if (DEBUG_PRI (msc_dev, DEB_CMDS))
465 fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl);
466 }
467 if (((dat & FNF_MOT) && sim_is_active (uptr)) ||
468 ((dat & FNF_REV) && sim_tape_bot (uptr)) ||
469 ((dat & FNF_WRT) && sim_tape_wrp (uptr)))
470 msc_sta = msc_sta | STA_REJ; /* reject? */
471 break;
472
473 case ioLIX: /* load */
474 dat = 0;
475 case ioMIX: /* merge */
476 dat = dat | (msc_sta & ~STA_DYN); /* get card status */
477 if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */
478 dat = dat | uptr->UST; /* add unit status */
479 if (sim_tape_bot (uptr)) /* BOT? */
480 dat = dat | STA_BOT;
481 if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */
482 !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr)))
483 dat = dat | STA_TBSY;
484 if (sim_tape_wrp (uptr)) /* write prot? */
485 dat = dat | STA_WLK;
486 if (sim_tape_eot (uptr)) /* EOT? */
487 dat = dat | STA_EOT;
488 }
489 else dat = dat | STA_TBSY | STA_LOCAL;
490 if (ms_ctype) dat = dat | STA_PE | /* 13183A? */
491 (msc_usl << STA_V_SEL);
492 if (DEBUG_PRI (msc_dev, DEB_CPU))
493 fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", dat);
494 break;
495
496 case ioCRS: /* control reset (action unverif) */
497 case ioCTL: /* control clear/set */
498 if (IR & I_CTL) { clrCTL (devc); } /* CLC */
499 else if (!(msc_sta & STA_REJ)) { /* STC, last cmd rejected? */
500 if ((msc_buf & 0377) == FNC_CLR) { /* clear? */
501 for (i = 0; i < MS_NUMDR; i++) { /* look for write in progr */
502 if (sim_is_active (&msc_unit[i]) && /* unit active? */
503 (msc_unit[i].FNC == FNC_WC) && /* last cmd write? */
504 (ms_ptr > 0)) { /* partial buffer? */
505 if (DEBUG_PRI (msc_dev, DEB_RWS))
506 fprintf (sim_deb,
507 ">>MSC STC: Unit %d wrote %d word partial record\n",
508 i, ms_ptr / 2);
509 if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF))
510 ms_map_err (uptr, st); /* discard any error */
511 ms_ptr = 0; /* clear partial */
512 }
513 if ((msc_unit[i].UST & STA_REW) == 0)
514 sim_cancel (&msc_unit[i]); /* stop if not rew */
515 }
516 setCTL (devc); /* set CTL for STC */
517 setFSR (devc); /* set FLG for completion */
518 msc_sta = msc_1st = 0; /* clr ctlr status */
519 if (DEBUG_PRI (msc_dev, DEB_CMDS))
520 fputs (">>MSC STC: Controller cleared\n", sim_deb);
521 return SCPE_OK;
522 }
523 uptr->FNC = msc_buf & 0377; /* save function */
524 if (uptr->FNC & FNF_RWD) { /* rewind? */
525 if (!sim_tape_bot (uptr)) /* not at BOT? */
526 uptr->UST = STA_REW; /* set rewinding */
527 sched_time = msc_rtime; /* set response time */
528 }
529 else {
530 if (sim_tape_bot (uptr)) /* at BOT? */
531 sched_time = msc_btime; /* use BOT start time */
532 else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM))
533 sched_time = msc_gtime; /* use gap traversal time */
534 else sched_time = 0;
535 if (uptr->FNC != FNC_GAP)
536 sched_time += msc_ctime; /* add base command time */
537 }
538 if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */
539 sim_activate (uptr, sched_time); /* else schedule op */
540 if (DEBUG_PRI (msc_dev, DEB_CMDS))
541 fprintf (sim_deb,
542 ">>MSC STC: Unit %d command %03o (%s) scheduled, "
543 "pos = %d, time = %d\n",
544 msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC),
545 uptr->pos, sched_time);
546 }
547 else if (DEBUG_PRI (msc_dev, DEB_CMDS))
548 fputs (">>MSC STC: Unit select (NOP)\n", sim_deb);
549 msc_sta = STA_BUSY; /* ctrl is busy */
550 msc_1st = 1;
551 setCTL (devc); /* go */
552 }
553 break;
554
555 case ioEDT: /* DMA end */
556 clrFSR (devc); /* same as CLF */
557 break;
558
559 default:
560 break;
561 }
562
563 if (IR & I_HC) { clrFSR (devc); } /* H/C option */
564 return dat;
565 }
566
567 /* Unit service
568
569 If rewind done, reposition to start of tape, set status
570 else, do operation, set done, interrupt.
571
572 In addition to decreasing the timing intervals, the FASTTIME option enables
573 two additional optimizations: WFM for GFM substitution, and BOT gap
574 elimination. If FASTTIME is selected, gap and file mark (GFM) commands are
575 processed as WFM (write file mark) commands. That is, the preceding GAP is
576 not performed. Also, the initial gap that normally precedes the first data
577 record or EOF mark at the beginning of the tape is omitted. These omissions
578 result in smaller tape image files. If REALTIME is selected, the gaps are
579 included. Note that the gaps (and realistic timing) are necessary to pass
580 the 7970 diagnostics.
581 */
582
583 t_stat msc_svc (UNIT *uptr)
584 {
585 int32 devc, devd, unum;
586 t_mtrlnt tbc;
587 t_stat st, r = SCPE_OK;
588
589 devc = msc_dib.devno; /* get device nos */
590 devd = msd_dib.devno;
591 unum = uptr - msc_dev.units; /* get unit number */
592
593 if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */
594 msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */
595 setFSR (devc); /* set cch flg */
596 return IORETURN (msc_stopioe, SCPE_UNATT);
597 }
598
599 switch (uptr->FNC) { /* case on function */
600
601 case FNC_RWS: /* rewind offline */
602 sim_tape_rewind (uptr); /* rewind tape */
603 uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */
604 uptr->UST = 0; /* clear REW status */
605 break; /* we're done */
606
607 case FNC_REW: /* rewind */
608 if (uptr->UST & STA_REW) { /* rewind in prog? */
609 uptr->FNC |= FNC_CMPL; /* set compl state */
610 sim_activate (uptr, msc_ctime); /* sched completion */
611 }
612 break; /* anyway, ctrl done */
613
614 case FNC_REW | FNC_CMPL: /* complete rewind */
615 sim_tape_rewind (uptr); /* rewind tape */
616 uptr->UST = 0; /* clear REW status */
617 return SCPE_OK; /* drive is free */
618
619 case FNC_GFM: /* gap + file mark */
620 if (ms_timing == 1) /* fast timing? */
621 goto DO_WFM; /* do plain file mark */
622 /* else fall into GAP */
623 case FNC_GAP: /* erase gap */
624 if (DEBUG_PRI (msc_dev, DEB_RWS))
625 fprintf (sim_deb,
626 ">>MSC svc: Unit %d wrote gap\n",
627 unum);
628 if ((r = ms_write_gap (uptr)) || /* write tape gap; error? */
629 (uptr->FNC != FNC_GFM)) /* not GFM? */
630 break; /* bail out now */
631 /* else drop into WFM */
632 case FNC_WFM: /* write file mark */
633 if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
634 if (DEBUG_PRI (msc_dev, DEB_RWS))
635 fprintf (sim_deb,
636 ">>MSC svc: Unit %d wrote initial gap\n",
637 unum);
638 if (st = ms_write_gap (uptr)) { /* write initial gap; error? */
639 r = ms_map_err (uptr, st); /* map error */
640 break; /* terminate operation */
641 }
642 }
643 DO_WFM:
644 if (DEBUG_PRI (msc_dev, DEB_RWS))
645 fprintf (sim_deb,
646 ">>MSC svc: Unit %d wrote file mark\n",
647 unum);
648 if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
649 r = ms_map_err (uptr, st); /* map error */
650 msc_sta = STA_EOF; /* set EOF status */
651 break;
652
653 case FNC_FSR: /* space forward */
654 if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */
655 r = ms_map_err (uptr, st); /* map error */
656 if (tbc & 1) msc_sta = msc_sta | STA_ODD;
657 else msc_sta = msc_sta & ~STA_ODD;
658 break;
659
660 case FNC_BSR: /* space reverse */
661 if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */
662 r = ms_map_err (uptr, st); /* map error */
663 if (tbc & 1) msc_sta = msc_sta | STA_ODD;
664 else msc_sta = msc_sta & ~STA_ODD;
665 break;
666
667 case FNC_FSF: /* space fwd file */
668 while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) {
669 if (sim_tape_eot (uptr)) break; /* EOT stops */
670 }
671 r = ms_map_err (uptr, st); /* map error */
672 break;
673
674 case FNC_BSF: /* space rev file */
675 while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
676 r = ms_map_err (uptr, st); /* map error */
677 break;
678
679 case FNC_RFF: /* diagnostic read */
680 case FNC_RC: /* read */
681 if (msc_1st) { /* first svc? */
682 msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */
683 st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
684 if (DEBUG_PRI (msc_dev, DEB_RWS))
685 fprintf (sim_deb,
686 ">>MSC svc: Unit %d read %d word record\n",
687 unum, ms_max / 2);
688 if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */
689 else if (st != MTSE_OK) { /* other error? */
690 r = ms_map_err (uptr, st); /* map error */
691 if (r == SCPE_OK) { /* recoverable? */
692 sim_activate (uptr, msc_itime); /* sched IRG */
693 uptr->FNC |= FNC_CMPL; /* set completion */
694 return SCPE_OK;
695 }
696 break; /* err, done */
697 }
698 if (ms_ctype) msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */
699 }
700 if (CTL (devd) && (ms_ptr < ms_max)) { /* DCH on, more data? */
701 if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR;
702 msd_buf = ((uint16) msxb[ms_ptr] << 8) |
703 ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]);
704 ms_ptr = ms_ptr + 2;
705 setFSR (devd); /* set dch flg */
706 sim_activate (uptr, msc_xtime); /* re-activate */
707 return SCPE_OK;
708 }
709 if (ms_max & 1) msc_sta = msc_sta | STA_ODD; /* set ODD by rec len */
710 else msc_sta = msc_sta & ~STA_ODD;
711 sim_activate (uptr, msc_itime); /* sched IRG */
712 if (uptr->FNC == FNC_RFF) msc_1st = 1; /* diagnostic? */
713 else uptr->FNC |= FNC_CMPL; /* set completion */
714 return SCPE_OK;
715
716 case FNC_RFF | FNC_CMPL: /* diagnostic read completion */
717 case FNC_RC | FNC_CMPL: /* read completion */
718 break;
719
720 case FNC_WC: /* write */
721 if (msc_1st) { /* first service? */
722 msc_1st = ms_ptr = 0; /* no data xfer on first svc */
723 if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */
724 if (DEBUG_PRI (msc_dev, DEB_RWS))
725 fprintf (sim_deb,
726 ">>MSC svc: Unit %d wrote initial gap\n",
727 unum);
728 if (st = ms_write_gap (uptr)) { /* write initial gap; error? */
729 r = ms_map_err (uptr, st); /* map error */
730 break; /* terminate operation */
731 }
732 }
733 }
734 else { /* not 1st, next char */
735 if (ms_ptr < DBSIZE) { /* room in buffer? */
736 msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */
737 msxb[ms_ptr + 1] = msd_buf & 0377;
738 ms_ptr = ms_ptr + 2;
739 }
740 else msc_sta = msc_sta | STA_PAR;
741 }
742 if (CTL (devd)) { /* xfer flop set? */
743 setFSR (devd); /* set dch flag */
744 sim_activate (uptr, msc_xtime); /* re-activate */
745 return SCPE_OK;
746 }
747 if (ms_ptr) { /* any data? write */
748 if (DEBUG_PRI (msc_dev, DEB_RWS))
749 fprintf (sim_deb,
750 ">>MSC svc: Unit %d wrote %d word record\n",
751 unum, ms_ptr / 2);
752 if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */
753 r = ms_map_err (uptr, st); /* map error */
754 break;
755 }
756 }
757 sim_activate (uptr, msc_itime); /* sched IRG */
758 uptr->FNC |= FNC_CMPL; /* set completion */
759 return SCPE_OK;
760
761 case FNC_WC | FNC_CMPL: /* write completion */
762 break;
763
764 case FNC_RRR: /* not supported */
765 default: /* unknown command */
766 if (DEBUG_PRI (msc_dev, DEB_CMDS))
767 fprintf (sim_deb,
768 ">>MSC svc: Unit %d command %03o is unknown (NOP)\n",
769 unum, uptr->FNC);
770 break;
771 }
772
773 setFSR (devc); /* set cch flg */
774 msc_sta = msc_sta & ~STA_BUSY; /* update status */
775 if (DEBUG_PRI (msc_dev, DEB_CMDS))
776 fprintf (sim_deb,
777 ">>MSC svc: Unit %d command %03o (%s) complete\n",
778 unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC));
779 return r;
780 }
781
782 /* Write an erase gap */
783
784 t_stat ms_write_gap (UNIT *uptr)
785 {
786 t_stat st;
787 uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */
788 uint32 tape_bpi = ms_ctype ? BPI_13183 : BPI_13181; /* establish nominal bpi */
789
790 if (st = sim_tape_wrgap (uptr, gap_len, tape_bpi)) /* write gap */
791 return ms_map_err (uptr, st); /* map error if failure */
792 else
793 return SCPE_OK;
794 }
795
796 /* Map tape error status */
797
798 t_stat ms_map_err (UNIT *uptr, t_stat st)
799 {
800 int32 unum = uptr - msc_dev.units; /* get unit number */
801
802 if (DEBUG_PRI (msc_dev, DEB_RWS))
803 fprintf (sim_deb,
804 ">>MSC err: Unit %d tape library status = %d\n",
805 unum, st);
806
807 switch (st) {
808
809 case MTSE_FMT: /* illegal fmt */
810 msc_sta = msc_sta | STA_REJ; /* reject cmd */
811 return SCPE_FMT; /* format error */
812
813 case MTSE_UNATT: /* unattached */
814 msc_detach (uptr); /* resync status (ignore rtn) */
815 msc_sta = msc_sta | STA_REJ; /* reject cmd */
816 return SCPE_UNATT; /* unit unattached */
817
818 case MTSE_OK: /* no error */
819 return SCPE_IERR; /* never get here! */
820
821 case MTSE_EOM: /* end of medium */
822 case MTSE_TMK: /* end of file */
823 msc_sta = msc_sta | STA_EOF | (ms_ctype ? 0 : STA_ODD);
824 break; /* EOF also sets ODD for 13181A */
825
826 case MTSE_INVRL: /* invalid rec lnt */
827 msc_sta = msc_sta | STA_PAR;
828 return SCPE_MTRLNT;
829
830 case MTSE_IOERR: /* IO error */
831 msc_sta = msc_sta | STA_PAR; /* error */
832 if (msc_stopioe) return SCPE_IOERR;
833 break;
834
835 case MTSE_RECE: /* record in error */
836 msc_sta = msc_sta | STA_PAR; /* error */
837 break;
838
839 case MTSE_WRP: /* write protect */
840 msc_sta = msc_sta | STA_REJ; /* reject */
841 break;
842 }
843
844 return SCPE_OK;
845 }
846
847 /* Reset routine */
848
849 t_stat msc_reset (DEVICE *dptr)
850 {
851 int32 i;
852 UNIT *uptr;
853
854 hp_enbdis_pair (dptr, /* make pair cons */
855 (dptr == &msd_dev)? &msc_dev: &msd_dev);
856 msc_buf = msd_buf = 0;
857 msc_sta = msc_usl = 0;
858 msc_1st = 0;
859 msc_dib.cmd = msd_dib.cmd = 0; /* clear cmd */
860 msc_dib.ctl = msd_dib.ctl = 0; /* clear ctl */
861 msc_dib.flg = msd_dib.flg = 1; /* set flg */
862 msc_dib.fbf = msd_dib.fbf = 1; /* set fbf */
863 msc_dib.srq = msd_dib.srq = 1; /* srq follows flg */
864 for (i = 0; i < MS_NUMDR; i++) {
865 uptr = msc_dev.units + i;
866 sim_tape_reset (uptr);
867 sim_cancel (uptr);
868 uptr->UST = 0;
869 }
870 ms_config_timing ();
871 return SCPE_OK;
872 }
873
874 /* Attach routine */
875
876 t_stat msc_attach (UNIT *uptr, char *cptr)
877 {
878 t_stat r;
879
880 r = sim_tape_attach (uptr, cptr); /* attach unit */
881 if (r == SCPE_OK)
882 uptr->flags = uptr->flags & ~UNIT_OFFLINE; /* set online */
883 return r;
884 }
885
886 /* Detach routine */
887
888 t_stat msc_detach (UNIT* uptr)
889 {
890 uptr->UST = 0; /* clear status */
891 uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */
892 return sim_tape_detach (uptr); /* detach unit */
893 }
894
895 /* Online routine */
896
897 t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc)
898 {
899 if (uptr->flags & UNIT_ATT) return SCPE_OK;
900 else return SCPE_UNATT;
901 }
902
903 /* Configure timing */
904
905 void ms_config_timing (void)
906 {
907 uint32 i, tset;
908
909 tset = (ms_timing << 1) | (ms_timing? 0 : ms_ctype); /* select timing set */
910 for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++)
911 *timers[i] = msc_times[tset][i]; /* assign times */
912 }
913
914 /* Set controller timing */
915
916 t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc)
917 {
918 if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
919 ms_timing = val;
920 ms_config_timing ();
921 return SCPE_OK;
922 }
923
924 /* Show controller timing */
925
926 t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc)
927 {
928 if (ms_timing) fputs ("fast timing", st);
929 else fputs ("realistic timing", st);
930 return SCPE_OK;
931 }
932
933 /* Set controller type */
934
935 t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
936 {
937 int32 i;
938
939 if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
940 for (i = 0; i < MS_NUMDR; i++) {
941 if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT;
942 }
943 ms_ctype = val;
944 ms_config_timing (); /* update for new type */
945 return SCPE_OK;
946 }
947
948 /* Show controller type */
949
950 t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
951 {
952 if (ms_ctype) fprintf (st, "13183A");
953 else fprintf (st, "13181A");
954 return SCPE_OK;
955 }
956
957 /* Set unit reel size
958
959 val = 0 -> SET MSCn CAPACITY=n
960 val = 1 -> SET MSCn REEL=n */
961
962 t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc)
963 {
964 int32 reel;
965 t_stat status;
966
967 if (val == 0) {
968 status = sim_tape_set_capac (uptr, val, cptr, desc);
969 if (status == SCPE_OK) uptr->REEL = 0;
970 return status;
971 }
972
973 if (cptr == NULL) return SCPE_ARG;
974 reel = (int32) get_uint (cptr, 10, 2400, &status);
975 if (status != SCPE_OK) return status;
976 else switch (reel) {
977
978 case 0:
979 uptr->REEL = 0; /* type 0 = unlimited/custom */
980 break;
981
982 case 600:
983 uptr->REEL = 1; /* type 1 = 600 foot */
984 break;
985
986 case 1200:
987 uptr->REEL = 2; /* type 2 = 1200 foot */
988 break;
989
990 case 2400:
991 uptr->REEL = 3; /* type 3 = 2400 foot */
992 break;
993
994 default:
995 return SCPE_ARG;
996 }
997
998 uptr->capac = uptr->REEL? (TCAP << uptr->REEL) << ms_ctype: 0;
999 return SCPE_OK;
1000 }
1001
1002 /* Show unit reel size
1003
1004 val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY
1005 val = 1 -> SHOW MSCn REEL */
1006
1007 t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc)
1008 {
1009 t_stat status = SCPE_OK;
1010
1011 if (uptr->REEL == 0) status = sim_tape_show_capac (st, uptr, val, desc);
1012 else fprintf (st, "%4d foot reel", 300 << uptr->REEL);
1013 if (val == 1) fputc ('\n', st); /* MTAB_NMO omits \n */
1014 return status;
1015 }
1016
1017 /* Translate command to mnemonic for debug logging
1018
1019 The command names and descriptions are taken from the 13181 interface
1020 manual. */
1021
1022 char *ms_cmd_name (uint32 cmd)
1023 {
1024
1025 switch (cmd & 0377) {
1026 case FNC_WC: return "WCC"; /* Write command */
1027 case FNC_WFM: return "WFM"; /* Write file mark */
1028 case FNC_RC: return "RRF"; /* Read record forward */
1029 case FNC_FSR: return "FSR"; /* Forward space record */
1030 case FNC_FSF: return "FSF"; /* Forward space file */
1031 case FNC_GAP: return "GAP"; /* Write gap */
1032 case FNC_BSR: return "BSR"; /* Backspace record */
1033 case FNC_BSF: return "BSF"; /* Backspace file */
1034 case FNC_REW: return "REW"; /* Rewind */
1035 case FNC_RWS: return "RWO"; /* Rewind off-line */
1036 case FNC_CLR: return "CLR"; /* Clear controller */
1037 case FNC_GFM: return "GFM"; /* Gap file mark */
1038 case FNC_RFF: return "RFF"; /* Read forward until file mark (diag) */
1039 case FNC_RRR: return "RRR"; /* Read record in reverse (diag) */
1040
1041 default: return "???"; /* Unknown command */
1042 }
1043 }
1044
1045 /* 7970B/7970E bootstrap routine (HP 12992D ROM) */
1046
1047 const uint16 ms_rom[IBL_LNT] = {
1048 0106501, /*ST LIB 1 ; read sw */
1049 0006011, /* SLB,RSS ; bit 0 set? */
1050 0027714, /* JMP RD ; no read */
1051 0003004, /* CMA,INA ; A is ctr */
1052 0073775, /* STA WC ; save */
1053 0067772, /* LDA SL0RW ; sel 0, rew */
1054 0017762, /*FF JSB CMD ; do cmd */
1055 0102311, /* SFS CC ; done? */
1056 0027707, /* JMP *-1 ; wait */
1057 0067774, /* LDB FFC ; get file fwd */
1058 0037775, /* ISZ WC ; done files? */
1059 0027706, /* JMP FF ; no */
1060 0067773, /*RD LDB RDCMD ; read cmd */
1061 0017762, /* JSB CMD ; do cmd */
1062 0103710, /* STC DC,C ; start dch */
1063 0102211, /* SFC CC ; read done? */
1064 0027752, /* JMP STAT ; no, get stat */
1065 0102310, /* SFS DC ; any data? */
1066 0027717, /* JMP *-3 ; wait */
1067 0107510, /* LIB DC,C ; get rec cnt */
1068 0005727, /* BLF,BLF ; move to lower */
1069 0007000, /* CMB ; make neg */
1070 0077775, /* STA WC ; save */
1071 0102211, /* SFC CC ; read done? */
1072 0027752, /* JMP STAT ; no, get stat */
1073 0102310, /* SFS DC ; any data? */
1074 0027727, /* JMP *-3 ; wait */
1075 0107510, /* LIB DC,C ; get load addr */
1076 0074000, /* STB 0 ; start csum */
1077 0077762, /* STA CMD ; save address */
1078 0027742, /* JMP *+4 */
1079 0177762, /*NW STB CMD,I ; store data */
1080 0040001, /* ADA 1 ; add to csum */
1081 0037762, /* ISZ CMD ; adv addr ptr */
1082 0102310, /* SFS DC ; any data? */
1083 0027742, /* JMP *-1 ; wait */
1084 0107510, /* LIB DC,C ; get word */
1085 0037775, /* ISZ WC ; done? */
1086 0027737, /* JMP NW ; no */
1087 0054000, /* CPB 0 ; csum ok? */
1088 0027717, /* JMP RD+3 ; yes, cont */
1089 0102011, /* HLT 11 ; no, halt */
1090 0102511, /*ST LIA CC ; get status */
1091 0001727, /* ALF,ALF ; get eof bit */
1092 0002020, /* SSA ; set? */
1093 0102077, /* HLT 77 ; done */
1094 0001727, /* ALF,ALF ; put status back */
1095 0001310, /* RAR,SLA ; read ok? */
1096 0102000, /* HLT 0 ; no */
1097 0027714, /* JMP RD ; read next */
1098 0000000, /*CMD 0 */
1099 0106611, /* OTB CC ; output cmd */
1100 0102511, /* LIA CC ; check for reject */
1101 0001323, /* RAR,RAR */
1102 0001310, /* RAR,SLA */
1103 0027763, /* JMP CMD+1 ; try again */
1104 0103711, /* STC CC,C ; start command */
1105 0127762, /* JMP CMD,I ; exit */
1106 0001501, /*SL0RW 001501 ; select 0, rewind */
1107 0001423, /*RDCMD 001423 ; read record */
1108 0000203, /*FFC 000203 ; space forward file */
1109 0000000, /*WC 000000 */
1110 0000000,
1111 0000000
1112 };
1113
1114 t_stat msc_boot (int32 unitno, DEVICE *dptr)
1115 {
1116 int32 dev;
1117 extern uint32 saved_AR;
1118
1119 if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
1120 dev = msd_dib.devno; /* get data chan dev */
1121 if (ibl_copy (ms_rom, dev)) return SCPE_IERR; /* copy boot to memory */
1122 SR = (SR & IBL_OPT) | IBL_MS | (dev << IBL_V_DEV); /* set SR */
1123 if ((sim_switches & SWMASK ('S')) && saved_AR) SR = SR | 1; /* skip? */
1124 return SCPE_OK;
1125 }
1126