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