1 /* i7094_mt.c: IBM 7094 magnetic tape simulator
2
3 Copyright (c) 2003-2012, 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 mt magtape simulator
27
28 19-Mar-12 RMS Fixed declaration of sel_name (Mark Pizzolato)
29 16-Jul-10 RMS Fixed handling of BSR, BSF (Dave Pitts)
30 */
31
32 #include "i7094_defs.h"
33 #include "sim_tape.h"
34
35 #define UST u3 /* unit state */
36 #define UCH u4 /* channel number */
37 #define MTUF_V_LDN (MTUF_V_UF + 0)
38 #define MTUF_LDN (1 << MTUF_V_LDN)
39 #define MT_MAXFR ((1 << 18) + 2)
40
41 #define QCHRONO(c,u) ((cpu_model & I_CT) && \
42 ((c) == CHRONO_CH) && ((u) == CHRONO_UNIT))
43
44 uint8 *mtxb[NUM_CHAN] = { NULL }; /* xfer buffer */
45 uint32 mt_unit[NUM_CHAN]; /* unit */
46 uint32 mt_bptr[NUM_CHAN];
47 uint32 mt_blnt[NUM_CHAN];
48 t_uint64 mt_chob[NUM_CHAN];
49 uint32 mt_chob_v[NUM_CHAN];
50 uint32 mt_tshort = 2; /* "a few microseconds" */
51 uint32 mt_twef = 25000; /* 50 msec */
52 uint32 mt_tstart = 29000; /* 58 msec */
53 uint32 mt_tstop = 10000; /* 20 msec */
54 uint32 mt_tword = 50; /* 125 usec */
55
56 static const uint8 odd_par[64] = {
57 1, 0, 0, 1, 0, 1, 1, 0,
58 0, 1, 1, 0, 1, 0, 0, 1,
59 0, 1, 1, 0, 1, 0, 0, 1,
60 1, 0, 0, 1, 0, 1, 1, 0,
61 0, 1, 1, 0, 1, 0, 0, 1,
62 1, 0, 0, 1, 0, 1, 1, 0,
63 1, 0, 0, 1, 0, 1, 1, 0,
64 0, 1, 1, 0, 1, 0, 0, 1
65 };
66
67 static const char *tape_stat[] = {
68 "OK", "TMK", "UNATT", "IOERR", "INVRECLNT",
69 "FMT", "BOT", "EOM", "RECERR", "WRPROT"
70 };
71
72 extern uint32 PC;
73 extern uint32 cpu_model;
74 extern uint32 ind_ioc;
75 extern FILE *sim_deb;
76 extern const char *sel_name[];
77
78 t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit);
79 t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags);
80 t_stat mt_rec_end (UNIT *uptr);
81 t_stat mt_svc (UNIT *uptr);
82 t_stat mt_reset (DEVICE *dptr);
83 t_stat mt_attach (UNIT *uptr, char *cptr);
84 t_stat mt_boot (int32 unitno, DEVICE *dptr);
85 t_stat mt_map_err (UNIT *uptr, t_stat st);
86
87 extern uint32 chrono_rd (uint8 *buf, uint32 bufsiz);
88
89 /* MT data structures
90
91 mt_dev MT device descriptor
92 mt_unit MT unit list
93 mt_reg MT register list
94 mt_mod MT modifier list
95 */
96
97 DIB mt_dib = { &mt_chsel, &mt_chwr };
98
99 MTAB mt_mod[] = {
100 { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
101 { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
102 { MTUF_LDN, 0, "high density", "HIGH", NULL },
103 { MTUF_LDN, MTUF_LDN, "low density", "LOW", NULL },
104 { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
105 &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
106 { 0 }
107 };
108
109 UNIT mta_unit[] = {
110 { UDATA (NULL, UNIT_DIS, 0) },
111 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
112 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
113 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
114 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
115 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
116 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
117 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
118 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
119 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
120 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
121 };
122
123 REG mta_reg[] = {
124 { ORDATA (UNIT, mt_unit[0], 5) },
125 { ORDATA (CHOB, mt_chob[0], 36) },
126 { FLDATA (CHOBV, mt_chob_v[0], 0) },
127 { DRDATA (BPTR, mt_bptr[0], 16), PV_LEFT },
128 { DRDATA (BLNT, mt_blnt[0], 16), PV_LEFT },
129 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
130 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
131 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
132 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
133 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
134 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
135 { URDATA (UST, mta_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
136 { URDATA (POS, mta_unit[0].pos, 10, T_ADDR_W, 0,
137 MT_NUMDR + 1, PV_LEFT | REG_RO) },
138 { NULL }
139 };
140
141 UNIT mtb_unit[] = {
142 { UDATA (NULL, UNIT_DIS, 0) },
143 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
144 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
145 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
146 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
147 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
148 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
149 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
150 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
151 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
152 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
153 };
154
155 REG mtb_reg[] = {
156 { ORDATA (UNIT, mt_unit[1], 5) },
157 { ORDATA (CHOB, mt_chob[1], 36) },
158 { FLDATA (CHOBV, mt_chob_v[1], 0) },
159 { DRDATA (BPTR, mt_bptr[1], 16), PV_LEFT },
160 { DRDATA (BLNT, mt_blnt[1], 16), PV_LEFT },
161 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
162 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
163 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
164 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
165 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
166 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
167 { URDATA (UST, mtb_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
168 { URDATA (POS, mtb_unit[0].pos, 10, T_ADDR_W, 0,
169 MT_NUMDR + 1, PV_LEFT | REG_RO) },
170 { NULL }
171 };
172
173 UNIT mtc_unit[] = {
174 { UDATA (NULL, UNIT_DIS, 0) },
175 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
176 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
177 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
178 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
179 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
180 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
181 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
182 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
183 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
184 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
185 };
186
187 REG mtc_reg[] = {
188 { ORDATA (UNIT, mt_unit[2], 5) },
189 { ORDATA (CHOB, mt_chob[2], 36) },
190 { FLDATA (CHOBV, mt_chob_v[2], 0) },
191 { DRDATA (BPTR, mt_bptr[2], 16), PV_LEFT },
192 { DRDATA (BLNT, mt_blnt[2], 16), PV_LEFT },
193 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
194 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
195 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
196 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
197 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
198 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
199 { URDATA (UST, mtc_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
200 { URDATA (POS, mtc_unit[0].pos, 10, T_ADDR_W, 0,
201 MT_NUMDR + 1, PV_LEFT | REG_RO) },
202 { NULL }
203 };
204
205 UNIT mtd_unit[] = {
206 { UDATA (NULL, UNIT_DIS, 0) },
207 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
208 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
209 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
210 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
211 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
212 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
213 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
214 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
215 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
216 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
217 };
218
219 REG mtd_reg[] = {
220 { ORDATA (UNIT, mt_unit[3], 5) },
221 { ORDATA (CHOB, mt_chob[3], 36) },
222 { FLDATA (CHOBV, mt_chob_v[3], 0) },
223 { DRDATA (BPTR, mt_bptr[3], 16), PV_LEFT },
224 { DRDATA (BLNT, mt_blnt[3], 16), PV_LEFT },
225 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
226 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
227 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
228 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
229 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
230 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
231 { URDATA (UST, mtd_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
232 { URDATA (POS, mtd_unit[0].pos, 10, T_ADDR_W, 0,
233 MT_NUMDR + 1, PV_LEFT | REG_RO) },
234 { NULL }
235 };
236
237 UNIT mte_unit[] = {
238 { UDATA (NULL, UNIT_DIS, 0) },
239 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
240 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
241 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
242 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
243 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
244 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
245 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
246 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
247 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
248 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
249 };
250
251 REG mte_reg[] = {
252 { ORDATA (UNIT, mt_unit[4], 5) },
253 { ORDATA (CHOB, mt_chob[4], 36) },
254 { FLDATA (CHOBV, mt_chob_v[4], 0) },
255 { DRDATA (BPTR, mt_bptr[4], 16), PV_LEFT },
256 { DRDATA (BLNT, mt_blnt[4], 16), PV_LEFT },
257 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
258 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
259 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
260 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
261 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
262 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
263 { URDATA (UST, mte_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
264 { URDATA (POS, mte_unit[0].pos, 10, T_ADDR_W, 0,
265 MT_NUMDR + 1, PV_LEFT | REG_RO) },
266 { NULL }
267 };
268
269 UNIT mtf_unit[] = {
270 { UDATA (NULL, UNIT_DIS, 0) },
271 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
272 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
273 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
274 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
275 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
276 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
277 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
278 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
279 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
280 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
281 };
282
283 REG mtf_reg[] = {
284 { ORDATA (UNIT, mt_unit[5], 5) },
285 { ORDATA (CHOB, mt_chob[5], 36) },
286 { FLDATA (CHOBV, mt_chob_v[5], 0) },
287 { DRDATA (BPTR, mt_bptr[5], 16), PV_LEFT },
288 { DRDATA (BLNT, mt_blnt[5], 16), PV_LEFT },
289 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
290 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
291 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
292 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
293 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
294 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
295 { URDATA (UST, mtf_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
296 { URDATA (POS, mtf_unit[0].pos, 10, T_ADDR_W, 0,
297 MT_NUMDR + 1, PV_LEFT | REG_RO) },
298 { NULL }
299 };
300
301 UNIT mtg_unit[] = {
302 { UDATA (NULL, UNIT_DIS, 0) },
303 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
304 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
305 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
306 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
307 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
308 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
309 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
310 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
311 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
312 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
313 };
314
315 REG mtg_reg[] = {
316 { ORDATA (UNIT, mt_unit[6], 5) },
317 { ORDATA (CHOB, mt_chob[6], 36) },
318 { FLDATA (CHOBV, mt_chob_v[6], 0) },
319 { DRDATA (BPTR, mt_bptr[6], 16), PV_LEFT },
320 { DRDATA (BLNT, mt_blnt[6], 16), PV_LEFT },
321 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
322 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
323 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
324 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
325 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
326 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
327 { URDATA (UST, mtg_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
328 { URDATA (POS, mtg_unit[0].pos, 10, T_ADDR_W, 0,
329 MT_NUMDR + 1, PV_LEFT | REG_RO) },
330 { NULL }
331 };
332
333 UNIT mth_unit[] = {
334 { UDATA (NULL, UNIT_DIS, 0) },
335 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
336 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
337 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
338 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
339 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
340 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
341 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
342 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
343 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) },
344 { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }
345 };
346
347 REG mth_reg[] = {
348 { ORDATA (UNIT, mt_unit[7], 5) },
349 { ORDATA (CHOB, mt_chob[7], 36) },
350 { FLDATA (CHOBV, mt_chob_v[7], 0) },
351 { DRDATA (BPTR, mt_bptr[7], 16), PV_LEFT },
352 { DRDATA (BLNT, mt_blnt[7], 16), PV_LEFT },
353 { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) },
354 { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT },
355 { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT },
356 { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT },
357 { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT },
358 { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT },
359 { URDATA (UST, mth_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) },
360 { URDATA (POS, mth_unit[0].pos, 10, T_ADDR_W, 0,
361 MT_NUMDR + 1, PV_LEFT | REG_RO) },
362 { NULL }
363 };
364
365 DEVICE mt_dev[NUM_CHAN] = {
366 {
367 "MTA", mta_unit, mta_reg, mt_mod,
368 MT_NUMDR + 1, 10, 31, 1, 8, 8,
369 NULL, NULL, &mt_reset,
370 &mt_boot, &mt_attach, &sim_tape_detach,
371 &mt_dib, DEV_DEBUG
372 },
373 {
374 "MTB", mtb_unit, mtb_reg, mt_mod,
375 MT_NUMDR + 1, 10, 31, 1, 8, 8,
376 NULL, NULL, &mt_reset,
377 NULL, &mt_attach, &sim_tape_detach,
378 &mt_dib, DEV_DIS|DEV_DEBUG
379 },
380 {
381 "MTC", mtc_unit, mtc_reg, mt_mod,
382 MT_NUMDR + 1, 10, 31, 1, 8, 8,
383 NULL, NULL, &mt_reset,
384 NULL, &mt_attach, &sim_tape_detach,
385 &mt_dib, DEV_DIS|DEV_DEBUG
386 },
387 {
388 "MTD", mtd_unit, mtd_reg, mt_mod,
389 MT_NUMDR + 1, 10, 31, 1, 8, 8,
390 NULL, NULL, &mt_reset,
391 NULL, &mt_attach, &sim_tape_detach,
392 &mt_dib, DEV_DIS|DEV_DEBUG
393 },
394 {
395 "MTE", mte_unit, mte_reg, mt_mod,
396 MT_NUMDR + 1, 10, 31, 1, 8, 8,
397 NULL, NULL, &mt_reset,
398 NULL, &mt_attach, &sim_tape_detach,
399 &mt_dib, DEV_DIS|DEV_DEBUG
400 },
401 {
402 "MTF", mtf_unit, mtf_reg, mt_mod,
403 MT_NUMDR + 1, 10, 31, 1, 8, 8,
404 NULL, NULL, &mt_reset,
405 NULL, &mt_attach, &sim_tape_detach,
406 &mt_dib, DEV_DIS|DEV_DEBUG
407 },
408 {
409 "MTG", mtg_unit, mtg_reg, mt_mod,
410 MT_NUMDR + 1, 10, 31, 1, 8, 8,
411 NULL, NULL, &mt_reset,
412 NULL, &mt_attach, &sim_tape_detach,
413 &mt_dib, DEV_DIS|DEV_DEBUG
414 },
415 {
416 "MTH", mth_unit, mth_reg, mt_mod,
417 MT_NUMDR + 1, 10, 31, 1, 8, 8,
418 NULL, NULL, &mt_reset,
419 NULL, &mt_attach, &sim_tape_detach,
420 &mt_dib, DEV_DIS|DEV_DEBUG
421 }
422 };
423
424 /* Select controller
425
426 Inputs:
427 ch = channel
428 cmd = select command
429 unit = unit
430 Outputs:
431 status = SCPE_OK if ok
432 STOP_STALL if busy
433 error code if error
434 */
435
436 static const int mt_must_att[CHSL_NUM] = {
437 0, 1, 1, 0, 1, 1, 0, 0,
438 1, 1, 1, 1, 1, 1, 0, 0
439 };
440
441 static const int mt_will_wrt[CHSL_NUM] = {
442 0, 0, 1, 0, 0, 1, 0, 0,
443 1, 1, 0, 0, 0, 0, 0, 0
444 };
445
mt_chsel(uint32 ch,uint32 cmd,uint32 unit)446 t_stat mt_chsel (uint32 ch, uint32 cmd, uint32 unit)
447 {
448 UNIT *uptr;
449 uint32 u = unit & 017;
450
451 if ((ch >= NUM_CHAN) || (cmd == 0) || (cmd >= CHSL_NUM))
452 return SCPE_IERR; /* invalid arg? */
453 if (mt_dev[ch].flags & DEV_DIS) /* disabled? */
454 return STOP_NXDEV;
455 if ((u == 0) || (u > MT_NUMDR)) /* valid unit? */
456 return STOP_NXDEV;
457 uptr = mt_dev[ch].units + u; /* get unit ptr */
458 if (uptr->flags & UNIT_DIS) /* disabled? */
459 return STOP_NXDEV;
460 if (mt_unit[ch] || sim_is_active (uptr)) /* ctrl or unit busy? */
461 return ERR_STALL; /* stall */
462 if (QCHRONO (ch, u)) { /* Chronolog clock? */
463 if (cmd != CHSL_RDS) /* only reads */
464 return STOP_ILLIOP;
465 sim_activate (uptr, mt_tword); /* responds quickly */
466 }
467 else { /* real tape */
468 if (!(uptr->flags & UNIT_ATT) && mt_must_att[cmd]) /* unit unatt? */
469 return SCPE_UNATT;
470 if (sim_tape_wrp (uptr) && mt_will_wrt[cmd]) /* unit wrp && write? */
471 return STOP_WRP;
472 if (DEBUG_PRS (mt_dev[ch]))
473 fprintf (sim_deb, ">>%s%d %s, pos = %d\n",
474 mt_dev[ch].name, u, sel_name[cmd], uptr->pos);
475
476 switch (cmd) { /* case on cmd */
477
478 case CHSL_RDS:
479 case CHSL_WRS:
480 sim_activate (uptr, mt_tstart); /* schedule op */
481 break;
482
483 case CHSL_WEF: /* write eof? */
484 sim_activate (uptr, mt_twef); /* schedule op */
485 break;
486
487 case CHSL_BSR:
488 case CHSL_BSF: /* backspace */
489 case CHSL_REW:
490 case CHSL_RUN:
491 case CHSL_SDN: /* rew, rew/unl, set det */
492 sim_activate (uptr, mt_tshort); /* schedule quick event */
493 break;
494
495 default:
496 return SCPE_IERR;
497 } /* end switch */
498 } /* end else */
499
500 uptr->UST = cmd; /* set cmd */
501 mt_unit[ch] = unit & 0777; /* save unit */
502 return SCPE_OK;
503 }
504
505 /* Channel write routine */
506
mt_chwr(uint32 ch,t_uint64 val,uint32 eorfl)507 t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 eorfl)
508 {
509 int32 k, u;
510 uint8 by, *xb;
511 UNIT *uptr;
512
513 if (ch >= NUM_CHAN) /* invalid chan? */
514 return SCPE_IERR;
515 xb = mtxb[ch]; /* get xfer buf */
516 u = mt_unit[ch] & 017;
517 if ((xb == NULL) || (u > MT_NUMDR)) /* invalid args? */
518 return SCPE_IERR;
519 uptr = mt_dev[ch].units + u; /* get unit */
520 mt_chob[ch] = val & DMASK; /* save word from chan */
521 mt_chob_v[ch] = 1; /* set valid */
522
523 if (uptr->UST == (CHSL_WRS|CHSL_2ND)) { /* data write? */
524 for (k = 30; /* proc 6 bytes */
525 (k >= 0) && (mt_bptr[ch] < MT_MAXFR);
526 k = k - 6) {
527 by = (uint8) ((val >> k) & 077); /* get byte */
528 if ((mt_unit[ch] & 020) == 0) { /* BCD? */
529 if (by == 0) /* cvt bin 0 */
530 by = BCD_ZERO;
531 else if (by & 020) /* invert zones */
532 by = by ^ 040;
533 if (!odd_par[by]) /* even parity */
534 by = by | 0100;
535 }
536 else if (odd_par[by]) /* bin, odd par */
537 by = by | 0100;
538 xb[mt_bptr[ch]++] = by; /* put in buffer */
539 }
540 if (eorfl)
541 return mt_rec_end (uptr); /* EOR? write rec */
542 return SCPE_OK;
543 }
544 return SCPE_IERR;
545 }
546
547 /* Unit timeout */
548
mt_svc(UNIT * uptr)549 t_stat mt_svc (UNIT *uptr)
550 {
551 uint32 i, u, ch = uptr->UCH; /* get channel number */
552 uint8 by, *xb = mtxb[ch]; /* get xfer buffer */
553 t_uint64 dat;
554 t_mtrlnt bc;
555 t_stat r;
556
557 if (xb == NULL) /* valid buffer? */
558 return SCPE_IERR;
559 u = uptr - mt_dev[ch].units;
560 switch (uptr->UST) { /* case on state */
561
562 case CHSL_RDS: /* read start */
563 if (QCHRONO (ch, mt_unit[ch] & 017)) /* Chronolog clock? */
564 bc = chrono_rd (xb, MT_MAXFR); /* read clock */
565 else { /* real tape */
566 r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */
567 if ((r = mt_map_err (uptr, r))) /* map status */
568 return r;
569 if (mt_unit[ch] == 0) /* disconnected? */
570 return SCPE_OK;
571 } /* end else Chrono */
572 if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
573 mt_unit[ch] = 0; /* clr ctrl busy */
574 return SCPE_OK;
575 }
576 for (i = bc; i < (bc + 6); i++) /* extra 0's */
577 xb[i] = 0;
578 mt_bptr[ch] = 0; /* set ptr, lnt */
579 mt_blnt[ch] = bc;
580 uptr->UST = CHSL_RDS|CHSL_2ND; /* next state */
581 sim_activate (uptr, mt_tword);
582 break;
583
584 case CHSL_RDS|CHSL_2ND: /* read word */
585 for (i = 0, dat = 0; i < 6; i++) { /* proc 6 bytes */
586 by = xb[mt_bptr[ch]++] & 077; /* get next byte */
587 if ((mt_unit[ch] & 020) == 0) { /* BCD? */
588 if (by == BCD_ZERO) /* cvt BCD 0 */
589 by = 0;
590 else if (by & 020) /* invert zones */
591 by = by ^ 040;
592 }
593 dat = (dat << 6) | ((t_uint64) by);
594 }
595 if (mt_bptr[ch] >= mt_blnt[ch]) { /* end of record? */
596 ch6_req_rd (ch, mt_unit[ch], dat, CH6DF_EOR);
597 uptr->UST = CHSL_RDS|CHSL_3RD; /* next state */
598 sim_activate (uptr, mt_tstop); /* long timing */
599 }
600 else {
601 ch6_req_rd (ch, mt_unit[ch], dat, 0); /* send to channel */
602 sim_activate (uptr, mt_tword); /* next word */
603 }
604 break;
605
606 case CHSL_RDS|CHSL_3RD: /* end record */
607 if (ch6_qconn (ch, mt_unit[ch])) { /* ch still conn? */
608 uptr->UST = CHSL_RDS; /* initial state */
609 sim_activate (uptr, mt_tshort); /* sched next record */
610 }
611 else mt_unit[ch] = 0; /* clr ctrl busy */
612 if (DEBUG_PRS (mt_dev[ch]))
613 fprintf (sim_deb, ">>%s%d RDS complete, pos = %d, %s\n",
614 mt_dev[ch].name, u, uptr->pos,
615 mt_unit[ch]? "continuing": "disconnecting");
616 return SCPE_OK;
617
618 case CHSL_WRS: /* write start */
619 if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */
620 mt_unit[ch] = 0; /* clr ctrl busy */
621 return SCPE_OK; /* (writes blank tape) */
622 }
623 mt_bptr[ch] = 0; /* init buffer */
624 uptr->UST = CHSL_WRS|CHSL_2ND; /* next state */
625 ch6_req_wr (ch, mt_unit[ch]); /* request channel */
626 mt_chob[ch] = 0; /* clr, inval buffer */
627 mt_chob_v[ch] = 0;
628 sim_activate (uptr, mt_tword); /* wait for word */
629 break;
630
631 case CHSL_WRS|CHSL_2ND: /* write word */
632 if (!ch6_qconn (ch, mt_unit[ch])) /* disconnected? */
633 return mt_rec_end (uptr); /* write record */
634 if (mt_chob_v[ch]) /* valid? clear */
635 mt_chob_v[ch] = 0;
636 else ind_ioc = 1; /* no, io check */
637 ch6_req_wr (ch, mt_unit[ch]); /* request channel */
638 sim_activate (uptr, mt_tword); /* next word */
639 break;
640
641 case CHSL_WRS|CHSL_3RD: /* write stop */
642 if (ch6_qconn (ch, mt_unit[ch])) { /* chan active? */
643 uptr->UST = CHSL_WRS; /* initial state */
644 sim_activate (uptr, mt_tshort); /* sched next record */
645 }
646 else mt_unit[ch] = 0; /* clr ctrl busy */
647 if (DEBUG_PRS (mt_dev[ch]))
648 fprintf (sim_deb, ">>%s%d WRS complete, pos = %d, %s\n",
649 mt_dev[ch].name, u, uptr->pos,
650 mt_unit[ch]? "continuing": "disconnecting");
651 return SCPE_OK;
652
653 case CHSL_BSR: case CHSL_BSF: /* backspace */
654 uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */
655 sim_activate (uptr, mt_tstart); /* reactivate */
656 ch6_end_nds (ch); /* disconnect */
657 return SCPE_OK;
658
659 case CHSL_BSR|CHSL_2ND: /* backspace rec */
660 r = sim_tape_sprecr (uptr, &bc); /* space backwards */
661 mt_unit[ch] = 0; /* clr ctrl busy */
662 if (DEBUG_PRS (mt_dev[ch]))
663 fprintf (sim_deb, ">>%s%d BSR complete, pos = %d\n",
664 mt_dev[ch].name, u, uptr->pos);
665 if (r == MTSE_TMK) /* allow tape mark */
666 return SCPE_OK;
667 return mt_map_err (uptr, r);
668
669 case CHSL_BSF|CHSL_2ND: /* backspace file */
670 while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ;
671 mt_unit[ch] = 0; /* clr ctrl busy */
672 if (DEBUG_PRS (mt_dev[ch]))
673 fprintf (sim_deb, ">>%s%d BSF complete, pos = %d\n",
674 mt_dev[ch].name, u, uptr->pos);
675 if (r == MTSE_TMK) /* allow tape mark */
676 return SCPE_OK;
677 return mt_map_err (uptr, r); /* map others */
678
679 case CHSL_WEF: /* write eof */
680 r = sim_tape_wrtmk (uptr); /* write tape mark */
681 mt_unit[ch] = 0; /* clr ctrl busy */
682 ch6_end_nds (ch); /* disconnect */
683 if (DEBUG_PRS (mt_dev[ch]))
684 fprintf (sim_deb, ">>%s%d WEF complete, pos = %d\n",
685 mt_dev[ch].name, u, uptr->pos);
686 return mt_map_err (uptr, r);
687
688 case CHSL_REW: case CHSL_RUN: /* rewind, unload */
689 uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */
690 sim_activate (uptr, mt_tstart); /* reactivate */
691 mt_unit[ch] = 0; /* clr ctrl busy */
692 ch6_end_nds (ch); /* disconnect */
693 return SCPE_OK;
694
695 case CHSL_REW | CHSL_2ND:
696 sim_tape_rewind (uptr);
697 if (DEBUG_PRS (mt_dev[ch]))
698 fprintf (sim_deb, ">>%s%d REW complete, pos = %d\n",
699 mt_dev[ch].name, u, uptr->pos);
700 return SCPE_OK;
701
702 case CHSL_RUN | CHSL_2ND:
703 sim_tape_detach (uptr);
704 if (DEBUG_PRS (mt_dev[ch]))
705 fprintf (sim_deb, ">>%s%d RUN complete, pos = %d\n",
706 mt_dev[ch].name, u, uptr->pos);
707 return SCPE_OK;
708
709 case CHSL_SDN:
710 if (mt_unit[ch] & 020) /* set density flag */
711 uptr->flags = uptr-> flags & ~MTUF_LDN;
712 else uptr->flags = uptr->flags | MTUF_LDN;
713 mt_unit[ch] = 0; /* clr ctrl busy */
714 ch6_end_nds (ch); /* disconnect */
715 if (DEBUG_PRS (mt_dev[ch]))
716 fprintf (sim_deb, ">>%s%d SDN complete, pos = %d\n",
717 mt_dev[ch].name, u, uptr->pos);
718 return SCPE_OK;
719
720 default:
721 return SCPE_IERR;
722 }
723
724 return SCPE_OK;
725 }
726
727 /* End record routine */
728
mt_rec_end(UNIT * uptr)729 t_stat mt_rec_end (UNIT *uptr)
730 {
731 uint32 ch = uptr->UCH;
732 uint8 *xb = mtxb[ch];
733 t_stat r;
734
735 if (mt_bptr[ch]) { /* any data? */
736 if (xb == NULL)
737 return SCPE_IERR;
738 r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */
739 if ((r = mt_map_err (uptr, r))) /* map error */
740 return r;
741 }
742 uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */
743 sim_cancel (uptr); /* cancel current */
744 sim_activate (uptr, mt_tstop); /* long timing */
745 return SCPE_OK;
746 }
747
748 /* Map tape error status */
749
mt_map_err(UNIT * uptr,t_stat st)750 t_stat mt_map_err (UNIT *uptr, t_stat st)
751 {
752 uint32 ch = uptr->UCH;
753 uint32 u = mt_unit[ch];
754 uint32 up = uptr - mt_dev[ch].units;
755
756 if ((st != MTSE_OK) && DEBUG_PRS (mt_dev[ch]))
757 fprintf (sim_deb, ">>%s%d status = %s, pos = %d\n",
758 mt_dev[ch].name, up, tape_stat[st], uptr->pos);
759
760 switch (st) {
761
762 case MTSE_FMT: /* illegal fmt */
763 case MTSE_UNATT: /* not attached */
764 ch6_err_disc (ch, u, CHF_TRC);
765 mt_unit[ch] = 0; /* disconnect */
766 return SCPE_IERR;
767
768 case MTSE_IOERR: /* IO error */
769 ch6_err_disc (ch, u, CHF_TRC);
770 mt_unit[ch] = 0; /* disconnect */
771 return SCPE_IOERR;
772
773 case MTSE_INVRL: /* invalid rec lnt */
774 ch6_err_disc (ch, u, CHF_TRC);
775 mt_unit[ch] = 0; /* disconnect */
776 return SCPE_MTRLNT;
777
778 case MTSE_WRP: /* write protect */
779 ch6_err_disc (ch, u, 0);
780 mt_unit[ch] = 0; /* disconnect */
781 return STOP_WRP;
782
783 case MTSE_EOM: /* end of medium */
784 case MTSE_TMK: /* tape mark */
785 ch6_err_disc (ch, u, CHF_EOF);
786 mt_unit[ch] = 0; /* disconnect */
787 break;
788
789 case MTSE_RECE: /* record in error */
790 ch6_set_flags (ch, u, CHF_TRC);
791 break;
792
793 case MTSE_BOT: /* reverse into BOT */
794 ch6_set_flags (ch, u, CHF_BOT);
795 break;
796
797 case MTSE_OK: /* no error */
798 break;
799 }
800
801 return SCPE_OK;
802 }
803
804 /* Magtape reset */
805
mt_reset(DEVICE * dptr)806 t_stat mt_reset (DEVICE *dptr)
807 {
808 uint32 ch = dptr - &mt_dev[0];
809 uint32 j;
810 REG *rptr;
811 UNIT *uptr;
812
813 if (mtxb[ch] == NULL)
814 mtxb[ch] = (uint8 *) calloc (MT_MAXFR + 6, sizeof (uint8));
815 if (mtxb[ch] == NULL) /* allocate buffer */
816 return SCPE_MEM;
817 rptr = find_reg ("BUF", NULL, dptr); /* update reg ptr */
818 if (rptr == NULL)
819 return SCPE_IERR;
820 rptr->loc = (void *) mtxb[ch];
821 mt_unit[ch] = 0; /* clear busy */
822 mt_bptr[ch] = 0; /* clear buf ptrs */
823 mt_blnt[ch] = 0;
824 mt_chob[ch] = 0;
825 mt_chob_v[ch] = 0;
826 for (j = 1; j <= MT_NUMDR; j++) { /* for all units */
827 uptr = dptr->units + j;
828 uptr->UST = 0; /* clear state */
829 uptr->UCH = ch;
830 sim_cancel (uptr); /* stop activity */
831 } /* end for */
832 return SCPE_OK; /* done */
833 }
834
835 /* Magtape attach */
836
mt_attach(UNIT * uptr,char * cptr)837 t_stat mt_attach (UNIT *uptr, char *cptr)
838 {
839 uptr->flags = uptr->flags & ~MTUF_LDN; /* start as hi den */
840 return sim_tape_attach (uptr, cptr);
841 }
842
843 /* Magtape boot */
844
845 #define BOOT_START 01000
846
847 static const t_uint64 boot_rom[5] = {
848 0076200000000 + U_MTBIN - 1, /* RDS MT_binary */
849 0054000000000 + BOOT_START + 4, /* RCHA *+3 */
850 0054400000000, /* LCHA 0 */
851 0002100000001, /* TTR 1 */
852 0500003000000, /* IOCT 0,,3 */
853 };
854
mt_boot(int32 unitno,DEVICE * dptr)855 t_stat mt_boot (int32 unitno, DEVICE *dptr)
856 {
857 uint32 i, chan;
858 extern t_uint64 *M;
859
860 chan = dptr - &mt_dev[0] + 1;
861 WriteP (BOOT_START, boot_rom[0] + unitno + (chan << 9));
862 for (i = 1; i < 5; i++)
863 WriteP (BOOT_START + i, boot_rom[i]);
864 PC = BOOT_START;
865 return SCPE_OK;
866 }
867