6c0d2ce87fd397038dfbd5762319bb6676ea0835
1 /* i7094_mt.c: IBM 7094 magnetic tape simulator
3 Copyright (c) 2003-2006, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
29 #include "i7094_defs.h"
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)
38 #define QCHRONO(c,u) ((cpu_model & I_CT) && \
39 ((c) == CHRONO_CH) && ((u) == CHRONO_UNIT))
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
];
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 */
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
64 static const char *tape_stat
[] = {
65 "OK", "TMK", "UNATT", "IOERR", "INVRECLNT",
66 "FMT", "BOT", "EOM", "RECERR", "WRPROT"
70 extern uint32 cpu_model
;
71 extern uint32 ind_ioc
;
73 extern char *sel_name
[];
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
);
84 extern uint32
chrono_rd (uint8
*buf
, uint32 bufsiz
);
88 mt_dev MT device descriptor
90 mt_reg MT register list
91 mt_mod MT modifier list
94 DIB mt_dib
= { &mt_chsel
, &mt_chwr
};
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
},
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) }
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
) },
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) }
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
) },
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) }
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
) },
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) }
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
) },
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) }
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
) },
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) }
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
) },
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) }
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
) },
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) }
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
) },
362 DEVICE mt_dev
[NUM_CHAN
] = {
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
,
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
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
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
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
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
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
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
428 status = SCPE_OK if ok
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
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
443 t_stat
mt_chsel (uint32 ch
, uint32 cmd
, uint32 unit
)
446 uint32 u
= unit
& 017;
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 */
460 else { /* real tape */
461 if (!(uptr
->flags
& UNIT_ATT
) && mt_must_att
[cmd
]) /* unit unatt? */
463 if (sim_tape_wrp (uptr
) && mt_will_wrt
[cmd
]) /* unit wrp && write? */
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
);
468 switch (cmd
) { /* case on cmd */
473 case CHSL_BSF
: /* rd, wr, backspace */
474 sim_activate (uptr
, mt_tstart
); /* schedule op */
477 case CHSL_WEF
: /* write eof? */
478 sim_activate (uptr
, mt_twef
); /* schedule op */
482 sim_activate (uptr
, mt_tshort
); /* schedule quick event */
485 case CHSL_SDN
: /* rew, rew/unl, set det */
486 sim_activate (uptr
, mt_tshort
); /* schedule quick event */
494 uptr
->UST
= cmd
; /* set cmd */
495 mt_unit
[ch
] = unit
& 0777; /* save unit */
499 /* Channel write routine */
501 t_stat
mt_chwr (uint32 ch
, t_uint64 val
, uint32 eorfl
)
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 */
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
);
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 */
525 else if (odd_par
[by
]) by
= by
| 0100; /* bin, odd par */
526 xb
[mt_bptr
[ch
]++] = by
; /* put in buffer */
528 if (eorfl
) return mt_rec_end (uptr
); /* EOR? write rec */
536 t_stat
mt_svc (UNIT
*uptr
)
538 uint32 i
, u
, ch
= uptr
->UCH
; /* get channel number */
539 uint8 by
, *xb
= mtxb
[ch
]; /* get xfer buffer */
544 if (xb
== NULL
) return SCPE_IERR
; /* valid buffer? */
545 u
= uptr
- mt_dev
[ch
].units
;
546 switch (uptr
->UST
) { /* case on state */
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 */
560 for (i
= bc
; i
< (bc
+ 6); i
++) xb
[i
] = 0; /* extra 0's */
561 mt_bptr
[ch
] = 0; /* set ptr, lnt */
563 uptr
->UST
= CHSL_RDS
|CHSL_2ND
; /* next state */
564 sim_activate (uptr
, mt_tword
);
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 */
574 dat
= (dat
<< 6) | ((t_uint64
) by
);
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 */
582 ch6_req_rd (ch
, mt_unit
[ch
], dat
, 0); /* send to channel */
583 sim_activate (uptr
, mt_tword
); /* next word */
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 */
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");
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) */
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 */
608 sim_activate (uptr
, mt_tword
); /* wait for word */
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 */
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 */
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");
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
);
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 */
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
);
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 */
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
);
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
);
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
);
693 /* End record routine */
695 t_stat
mt_rec_end (UNIT
*uptr
)
697 uint32 ch
= uptr
->UCH
;
698 uint8
*xb
= mtxb
[ch
];
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 */
706 uptr
->UST
= CHSL_WRS
|CHSL_3RD
; /* next state */
707 sim_cancel (uptr
); /* cancel current */
708 sim_activate (uptr
, mt_tstop
); /* long timing */
712 /* Map tape error status */
714 t_stat
mt_map_err (UNIT
*uptr
, t_stat st
)
716 uint32 ch
= uptr
->UCH
;
717 uint32 u
= mt_unit
[ch
];
718 uint32 up
= uptr
- mt_dev
[ch
].units
;
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
);
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 */
731 case MTSE_IOERR
: /* IO error */
732 ch6_err_disc (ch
, u
, CHF_TRC
);
733 mt_unit
[ch
] = 0; /* disconnect */
736 case MTSE_INVRL
: /* invalid rec lnt */
737 ch6_err_disc (ch
, u
, CHF_TRC
);
738 mt_unit
[ch
] = 0; /* disconnect */
741 case MTSE_WRP
: /* write protect */
742 ch6_err_disc (ch
, u
, 0);
743 mt_unit
[ch
] = 0; /* disconnect */
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 */
752 case MTSE_RECE
: /* record in error */
753 ch6_set_flags (ch
, u
, CHF_TRC
);
756 case MTSE_BOT
: /* reverse into BOT */
757 ch6_set_flags (ch
, u
, CHF_BOT
);
760 case MTSE_OK
: /* no error */
769 t_stat
mt_reset (DEVICE
*dptr
)
771 uint32 ch
= dptr
- &mt_dev
[0];
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 */
786 for (j
= 1; j
<= MT_NUMDR
; j
++) { /* for all units */
787 uptr
= dptr
->units
+ j
;
788 uptr
->UST
= 0; /* clear state */
790 sim_cancel (uptr
); /* stop activity */
792 return SCPE_OK
; /* done */
797 t_stat
mt_attach (UNIT
*uptr
, char *cptr
)
799 uptr
->flags
= uptr
->flags
& ~MTUF_LDN
; /* start as hi den */
800 return sim_tape_attach (uptr
, cptr
);
805 #define BOOT_START 01000
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 */
815 t_stat
mt_boot (int32 unitno
, DEVICE
*dptr
)
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
]);