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