Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* h316_mt.c: H316/516 magnetic tape simulator\r |
2 | \r | |
3 | Copyright (c) 2003-2007, 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 | mt 516-4100 seven track magnetic tape\r | |
27 | \r | |
28 | 09-Jun-07 RMS Fixed bug in write without stop (from Theo Engel)\r | |
29 | 16-Feb-06 RMS Added tape capacity checking\r | |
30 | 26-Aug-05 RMS Revised to use API for write lock check\r | |
31 | 08-Feb-05 RMS Fixed error reporting from OCP (found by Philipp Hachtmann)\r | |
32 | 01-Dec-04 RMS Fixed bug in DMA/DMC support\r | |
33 | \r | |
34 | Magnetic tapes are represented as a series of variable records\r | |
35 | of the form:\r | |
36 | \r | |
37 | 32b byte count\r | |
38 | byte 0\r | |
39 | byte 1\r | |
40 | :\r | |
41 | byte n-2\r | |
42 | byte n-1\r | |
43 | 32b byte count\r | |
44 | \r | |
45 | If the byte count is odd, the record is padded with an extra byte\r | |
46 | of junk. File marks are represented by a byte count of 0.\r | |
47 | */\r | |
48 | \r | |
49 | #include "h316_defs.h"\r | |
50 | #include "sim_tape.h"\r | |
51 | \r | |
52 | #define MT_NUMDR 4 /* number of drives */\r | |
53 | #define DB_N_SIZE 16 /* max data buf */\r | |
54 | #define DBSIZE (1 << DB_N_SIZE) /* max data cmd */\r | |
55 | #define FNC u3 /* function */\r | |
56 | #define UST u4 /* unit status */\r | |
57 | \r | |
58 | /* Function codes */\r | |
59 | \r | |
60 | #define FNC_RBCD2 000\r | |
61 | #define FNC_RBIN2 001\r | |
62 | #define FNC_RBIN3 002\r | |
63 | #define FNC_DMANM 003\r | |
64 | #define FNC_WBCD2 004\r | |
65 | #define FNC_WBIN2 005\r | |
66 | #define FNC_WEOF 006\r | |
67 | #define FNC_IOBUS 007\r | |
68 | #define FNC_WBIN3 010\r | |
69 | #define FNC_FSR 011\r | |
70 | #define FNC_FSF 012\r | |
71 | #define FNC_DMAAU 013\r | |
72 | #define FNC_REW 014\r | |
73 | #define FNC_BSR 015\r | |
74 | #define FNC_BSF 016\r | |
75 | #define FNC_STOPW 017\r | |
76 | #define FNC_2ND 020 /* second state */\r | |
77 | #define FNC_NOP (FNC_STOPW|FNC_2ND)\r | |
78 | #define FNC_EOM 040 /* end of motion */\r | |
79 | \r | |
80 | /* Status - unit.UST */\r | |
81 | \r | |
82 | #define STA_BOT 0000002 /* beg of tape */\r | |
83 | #define STA_EOT 0000001 /* end of tape */\r | |
84 | \r | |
85 | extern int32 dev_int, dev_enb, chan_req;\r | |
86 | extern int32 stop_inst;\r | |
87 | \r | |
88 | uint32 mt_buf = 0; /* data buffer */\r | |
89 | uint32 mt_usel = 0; /* unit select */\r | |
90 | uint32 mt_busy = 0; /* ctlr busy */\r | |
91 | uint32 mt_mdirq = 0; /* motion done int req */\r | |
92 | uint32 mt_rdy = 0; /* transfer ready (int) */\r | |
93 | uint32 mt_err = 0; /* error */\r | |
94 | uint32 mt_eof = 0; /* end of file */\r | |
95 | uint32 mt_eor = 0; /* transfer done */\r | |
96 | uint32 mt_dma = 0; /* DMA/DMC */\r | |
97 | uint32 mt_xtime = 16; /* transfer time */\r | |
98 | uint32 mt_ctime = 3000; /* start/stop time */\r | |
99 | uint32 mt_stopioe = 1; /* stop on I/O error */\r | |
100 | uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */\r | |
101 | t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */\r | |
102 | \r | |
103 | int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev);\r | |
104 | void mt_updint (uint32 rdy, uint32 mdone);\r | |
105 | t_stat mt_svc (UNIT *uptr);\r | |
106 | t_stat mt_reset (DEVICE *dptr);\r | |
107 | t_stat mt_attach (UNIT *uptr, char *cptr);\r | |
108 | t_stat mt_detach (UNIT *uptr);\r | |
109 | t_stat mt_map_err (UNIT *uptr, t_stat st);\r | |
110 | void mt_wrwd (UNIT *uptr, uint32 dat);\r | |
111 | \r | |
112 | /* MT data structures\r | |
113 | \r | |
114 | mt_dev MT device descriptor\r | |
115 | mt_unit MT unit list\r | |
116 | mt_reg MT register list\r | |
117 | mt_mod MT modifier list\r | |
118 | */\r | |
119 | \r | |
120 | DIB mt_dib = { MT, IOBUS, MT_NUMDR, &mtio };\r | |
121 | \r | |
122 | UNIT mt_unit[] = {\r | |
123 | { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },\r | |
124 | { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },\r | |
125 | { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },\r | |
126 | { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }\r | |
127 | };\r | |
128 | \r | |
129 | REG mt_reg[] = {\r | |
130 | { ORDATA (BUF, mt_buf, 16) },\r | |
131 | { ORDATA (USEL, mt_usel, 2) },\r | |
132 | { FLDATA (BUSY, mt_busy, 0) },\r | |
133 | { FLDATA (RDY, mt_rdy, 0) },\r | |
134 | { FLDATA (ERR, mt_err, 0) },\r | |
135 | { FLDATA (EOF, mt_eof, 0) },\r | |
136 | { FLDATA (EOR, mt_eor, 0) },\r | |
137 | { FLDATA (MDIRQ, mt_mdirq, 0) },\r | |
138 | { FLDATA (DMA, mt_dma, 0) },\r | |
139 | { FLDATA (INTREQ, dev_int, INT_V_MT) },\r | |
140 | { FLDATA (ENABLE, dev_enb, INT_V_MT) },\r | |
141 | { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },\r | |
142 | { DRDATA (BPTR, mt_ptr, DB_N_SIZE + 1) },\r | |
143 | { DRDATA (BMAX, mt_max, DB_N_SIZE + 1) },\r | |
144 | { DRDATA (CTIME, mt_ctime, 24), REG_NZ + PV_LEFT },\r | |
145 | { DRDATA (XTIME, mt_xtime, 24), REG_NZ + PV_LEFT },\r | |
146 | { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, MT_NUMDR, PV_LEFT) },\r | |
147 | { URDATA (FNC, mt_unit[0].FNC, 8, 8, 0, MT_NUMDR, REG_HRO) },\r | |
148 | { URDATA (UST, mt_unit[0].UST, 8, 2, 0, MT_NUMDR, REG_HRO) },\r | |
149 | { ORDATA (CHAN, mt_dib.chan, 5), REG_HRO },\r | |
150 | { FLDATA (STOP_IOE, mt_stopioe, 0) },\r | |
151 | { NULL }\r | |
152 | };\r | |
153 | \r | |
154 | MTAB mt_mod[] = {\r | |
155 | { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
156 | { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, \r | |
157 | { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r | |
158 | &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r | |
159 | { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",\r | |
160 | &sim_tape_set_capac, &sim_tape_show_capac, NULL },\r | |
161 | { MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS",\r | |
162 | &io_set_iobus, NULL, NULL },\r | |
163 | { MTAB_XTD|MTAB_VDV, 0, NULL, "DMC",\r | |
164 | &io_set_dmc, NULL, NULL },\r | |
165 | { MTAB_XTD|MTAB_VDV, 0, NULL, "DMA",\r | |
166 | &io_set_dma, NULL, NULL },\r | |
167 | { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL,\r | |
168 | NULL, &io_show_chan, NULL },\r | |
169 | { 0 }\r | |
170 | };\r | |
171 | \r | |
172 | DEVICE mt_dev = {\r | |
173 | "MT", mt_unit, mt_reg, mt_mod,\r | |
174 | MT_NUMDR, 10, 31, 1, 8, 8,\r | |
175 | NULL, NULL, &mt_reset,\r | |
176 | NULL, &mt_attach, &mt_detach,\r | |
177 | &mt_dib, DEV_DISABLE\r | |
178 | };\r | |
179 | \r | |
180 | /* IO routine */\r | |
181 | \r | |
182 | int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev)\r | |
183 | {\r | |
184 | uint32 i, u = dev & 03;\r | |
185 | UNIT *uptr = mt_dev.units + u;\r | |
186 | static uint8 wrt_fnc[16] = { /* >0 = wr, 1 = chan op */\r | |
187 | 0, 0, 0, 0, 1, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0\r | |
188 | };\r | |
189 | \r | |
190 | switch (inst) { /* case on opcode */\r | |
191 | \r | |
192 | case ioOCP:\r | |
193 | mt_updint (mt_rdy, 0); /* clear motion intr */\r | |
194 | mt_eof = 0; /* clear eof */\r | |
195 | switch (fnc) { /* case on function */\r | |
196 | \r | |
197 | case FNC_DMANM: /* set DMA/DMC */\r | |
198 | case FNC_DMAAU:\r | |
199 | mt_usel = u; /* save unit select */\r | |
200 | if (mt_dib.chan) mt_dma = 1; /* set DMA if configured */\r | |
201 | else mt_dma = 0;\r | |
202 | break;\r | |
203 | \r | |
204 | case FNC_IOBUS: /* set IOBUS */\r | |
205 | mt_usel = u; /* save unit select */\r | |
206 | mt_dma = 0;\r | |
207 | break;\r | |
208 | \r | |
209 | case FNC_STOPW: /* stop write */\r | |
210 | mt_usel = u; /* save unit select */\r | |
211 | mt_updint (0, mt_mdirq); /* clear ready */\r | |
212 | if (wrt_fnc[uptr->FNC & 017] == 1) /* writing? */\r | |
213 | mt_eor = 1; /* set transfer done */\r | |
214 | break; \r | |
215 | \r | |
216 | default: /* motion command */\r | |
217 | if (mt_busy) return dat; /* nop if ctlr busy */\r | |
218 | mt_eor = 0; /* clr transfer done */\r | |
219 | mt_err = 0; /* clr error */\r | |
220 | mt_usel = u; /* save unit select */\r | |
221 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r | |
222 | return (((mt_stopioe? SCPE_UNATT: SCPE_OK) << IOT_V_REASON) | dat);\r | |
223 | if (sim_is_active (uptr)) return dat; /* nop if busy */\r | |
224 | if (wrt_fnc[fnc] && sim_tape_wrp (uptr))\r | |
225 | return ((STOP_MTWRP << IOT_V_REASON) | dat);\r | |
226 | uptr->FNC = fnc;\r | |
227 | uptr->UST = 0;\r | |
228 | mt_busy = 1;\r | |
229 | for (i = 0; i < MT_NUMDR; i++) /* clear all EOT flags */\r | |
230 | mt_unit[i].UST = mt_unit[i].UST & ~STA_EOT;\r | |
231 | sim_activate (uptr, mt_ctime); /* schedule */\r | |
232 | break;\r | |
233 | }\r | |
234 | break;\r | |
235 | \r | |
236 | case ioINA: /* INA */\r | |
237 | if (fnc) return IOBADFNC (dat); /* fnc 0 only */\r | |
238 | if (mt_rdy) { /* ready? */\r | |
239 | mt_rdy = 0; /* clear ready */\r | |
240 | return IOSKIP (dat | mt_buf); /* ret buf, skip */\r | |
241 | }\r | |
242 | break;\r | |
243 | \r | |
244 | case ioOTA: /* OTA */\r | |
245 | if (fnc) return IOBADFNC (dat); /* fnc 0 only */\r | |
246 | if (mt_rdy) { /* ready? */\r | |
247 | mt_rdy = 0; /* clear ready */\r | |
248 | mt_buf = dat; /* store buf */\r | |
249 | return IOSKIP (dat); /* skip */\r | |
250 | }\r | |
251 | break;\r | |
252 | \r | |
253 | case ioSKS:\r | |
254 | uptr = mt_dev.units + mt_usel; /* use saved unit sel */\r | |
255 | switch (fnc) {\r | |
256 | \r | |
257 | case 000: /* ready */\r | |
258 | if (mt_rdy) return IOSKIP (dat);\r | |
259 | break;\r | |
260 | \r | |
261 | case 001: /* !busy */\r | |
262 | if (!mt_busy) return IOSKIP (dat);\r | |
263 | break;\r | |
264 | \r | |
265 | case 002: /* !error */\r | |
266 | if (!mt_err) return IOSKIP (dat);\r | |
267 | break;\r | |
268 | \r | |
269 | case 003: /* !BOT */\r | |
270 | if (!(uptr->UST & STA_BOT)) return IOSKIP (dat);\r | |
271 | break;\r | |
272 | \r | |
273 | case 004: /* !interrupting */\r | |
274 | if (!TST_INTREQ (INT_MT)) return IOSKIP (dat);\r | |
275 | break;\r | |
276 | \r | |
277 | case 005: /* !EOT */\r | |
278 | if (!(uptr->UST & STA_EOT)) return IOSKIP (dat);\r | |
279 | break;\r | |
280 | \r | |
281 | case 006: /* !EOF */\r | |
282 | if (!mt_eof) return IOSKIP (dat);\r | |
283 | break;\r | |
284 | \r | |
285 | case 007: /* !write prot */\r | |
286 | if (!sim_tape_wrp (uptr)) return IOSKIP (dat);\r | |
287 | break;\r | |
288 | \r | |
289 | case 011: /* operational */\r | |
290 | if ((uptr->flags & UNIT_ATT) &&\r | |
291 | ((uptr->FNC & 017) != FNC_REW)) return IOSKIP (dat);\r | |
292 | break;\r | |
293 | \r | |
294 | case 012: /* skip if !chan 2 */\r | |
295 | return IOSKIP (dat);\r | |
296 | \r | |
297 | case 013: /* skip if !auto */\r | |
298 | return IOSKIP (dat);\r | |
299 | \r | |
300 | case 014: /* !rewinding */\r | |
301 | uptr = mt_dev.units + (dev & 03); /* use specified unit */\r | |
302 | if ((uptr->FNC & 017) != FNC_REW) return IOSKIP (dat);\r | |
303 | break;\r | |
304 | }\r | |
305 | break;\r | |
306 | \r | |
307 | case ioEND: /* end of range */\r | |
308 | mt_eor = 1; /* transfer done */\r | |
309 | break;\r | |
310 | }\r | |
311 | \r | |
312 | return dat;\r | |
313 | }\r | |
314 | \r | |
315 | /* Unit service\r | |
316 | \r | |
317 | If rewind done, reposition to start of tape, set status\r | |
318 | else, do operation, set done, interrupt\r | |
319 | \r | |
320 | Can't be write locked, can only write lock detached unit\r | |
321 | */\r | |
322 | \r | |
323 | t_stat mt_svc (UNIT *uptr)\r | |
324 | {\r | |
325 | int32 ch = mt_dib.chan - 1; /* DMA/DMC ch */\r | |
326 | uint32 i, c1, c2, c3;\r | |
327 | t_mtrlnt tbc;\r | |
328 | t_bool passed_eot;\r | |
329 | t_stat st, r = SCPE_OK;\r | |
330 | \r | |
331 | if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */\r | |
332 | mt_err = 1;\r | |
333 | mt_busy = 0;\r | |
334 | mt_updint (0, 1); /* cmd done */\r | |
335 | return IORETURN (mt_stopioe, SCPE_UNATT);\r | |
336 | }\r | |
337 | \r | |
338 | passed_eot = sim_tape_eot (uptr); /* passed EOT? */\r | |
339 | switch (uptr->FNC) { /* case on function */\r | |
340 | \r | |
341 | case FNC_REW: /* rewind (initial) */\r | |
342 | mt_busy = 0; /* ctlr not busy */\r | |
343 | uptr->FNC = uptr->FNC | FNC_2ND;\r | |
344 | sim_activate (uptr, mt_ctime);\r | |
345 | return SCPE_OK; /* continue */\r | |
346 | \r | |
347 | case FNC_REW | FNC_2ND: /* rewind done */\r | |
348 | uptr->pos = 0; /* reposition file */\r | |
349 | uptr->UST = STA_BOT; /* set BOT */\r | |
350 | uptr->FNC = FNC_NOP; /* nop function */\r | |
351 | for (i = 0; i < MT_NUMDR; i++) { /* last rewind? */\r | |
352 | if ((mt_unit[i].FNC & 017) == FNC_REW) return SCPE_OK;\r | |
353 | }\r | |
354 | mt_updint (mt_rdy, 1); /* yes, motion done */\r | |
355 | return SCPE_OK;\r | |
356 | \r | |
357 | case FNC_WEOF: /* write file mark */\r | |
358 | if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r | |
359 | r = mt_map_err (uptr, st); /* map error */\r | |
360 | break; /* sched end motion */\r | |
361 | \r | |
362 | case FNC_FSR: /* space fwd rec */\r | |
363 | if (st = sim_tape_sprecf (uptr, &tbc)) /* space fwd, err? */\r | |
364 | r = mt_map_err (uptr, st); /* map error */\r | |
365 | break; /* sched end motion */\r | |
366 | \r | |
367 | case FNC_BSR: /* space rev rec */\r | |
368 | if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */\r | |
369 | r = mt_map_err (uptr, st); /* map error */\r | |
370 | break; /* sched end motion */\r | |
371 | \r | |
372 | case FNC_FSF: /* space fwd file */\r | |
373 | while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;\r | |
374 | r = mt_map_err (uptr, st); /* map error */\r | |
375 | break; /* sched end motion */\r | |
376 | \r | |
377 | case FNC_BSF: /* space rev file */\r | |
378 | while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;\r | |
379 | r = mt_map_err (uptr, st); /* map error */\r | |
380 | break; /* sched end motion */\r | |
381 | \r | |
382 | case FNC_EOM: /* end of motion */\r | |
383 | uptr->FNC = FNC_NOP; /* nop function */\r | |
384 | mt_busy = 0; /* not busy */\r | |
385 | mt_updint (mt_rdy, 1); /* end of motion */\r | |
386 | return SCPE_OK; /* done! */\r | |
387 | \r | |
388 | case FNC_RBCD2: case FNC_RBIN2: case FNC_RBIN3: /* read first */\r | |
389 | mt_ptr = 0; /* clr buf ptr */\r | |
390 | st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */\r | |
391 | if (st != MTSE_OK) { /* error? */\r | |
392 | r = mt_map_err (uptr, st); /* map error */\r | |
393 | break; /* sched end motion */\r | |
394 | }\r | |
395 | uptr->FNC = uptr->FNC | FNC_2ND; /* next state */\r | |
396 | sim_activate (uptr, mt_xtime); /* sched xfer */\r | |
397 | return SCPE_OK;\r | |
398 | \r | |
399 | case FNC_RBCD2 | FNC_2ND: /* read, word */\r | |
400 | case FNC_RBIN2 | FNC_2ND:\r | |
401 | case FNC_RBIN3 | FNC_2ND:\r | |
402 | if (mt_ptr >= mt_max) break; /* record done? */\r | |
403 | c1 = mtxb[mt_ptr++] & 077; /* get 2 chars */\r | |
404 | c2 = mtxb[mt_ptr++] & 077;\r | |
405 | if (uptr->FNC == (FNC_RBCD2 | FNC_2ND)) { /* BCD? */\r | |
406 | if (c1 == 012) c1 = 0; /* change 12 to 0 */\r | |
407 | if (c2 == 012) c2 = 0;\r | |
408 | }\r | |
409 | if (uptr->FNC == (FNC_RBIN3 | FNC_2ND)) { /* read 3? */\r | |
410 | if (mt_ptr >= mt_max) break; /* lose wd if not enuf */\r | |
411 | c3 = mtxb[mt_ptr++] & 017; /* get 3rd char */\r | |
412 | }\r | |
413 | else c3 = 0;\r | |
414 | sim_activate (uptr, mt_xtime); /* no, sched word */\r | |
415 | if (mt_eor) return SCPE_OK; /* xfer done? */\r | |
416 | mt_buf = (c1 << 10) | (c2 << 4) | c3; /* pack chars */\r | |
417 | if (mt_rdy) mt_err = 1; /* buf full? err */\r | |
418 | mt_updint (1, mt_mdirq); /* set ready */\r | |
419 | if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */\r | |
420 | return SCPE_OK; /* continue */\r | |
421 | \r | |
422 | case FNC_WBCD2: case FNC_WBIN2: case FNC_WBIN3: /* write first */\r | |
423 | mt_ptr = 0; /* clear buf ptr */\r | |
424 | mt_updint (1, mt_mdirq); /* set ready */\r | |
425 | if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */\r | |
426 | uptr->FNC = uptr->FNC | FNC_2ND; /* next state */\r | |
427 | sim_activate (uptr, mt_xtime); /* sched xfer */\r | |
428 | return SCPE_OK; /* continue */\r | |
429 | \r | |
430 | case FNC_WBCD2 | FNC_2ND: /* write, word */\r | |
431 | case FNC_WBIN2 | FNC_2ND:\r | |
432 | case FNC_WBIN3 | FNC_2ND:\r | |
433 | if (mt_eor || mt_rdy) { /* done or no data? */\r | |
434 | if (!mt_rdy) mt_wrwd (uptr, mt_buf); /* write last word */\r | |
435 | else mt_rdy = 0; /* rdy must be clr */\r | |
436 | if (mt_ptr) { /* any data? */\r | |
437 | if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) /* write, err? */\r | |
438 | r = mt_map_err (uptr, st); /* map error */\r | |
439 | }\r | |
440 | break; /* sched end motion */\r | |
441 | }\r | |
442 | mt_wrwd (uptr, mt_buf); /* write word */\r | |
443 | sim_activate (uptr, mt_xtime); /* no, sched word */\r | |
444 | mt_updint (1, mt_mdirq); /* set ready */\r | |
445 | if (mt_dma) SET_CH_REQ (ch); /* DMC/DMA? req chan */\r | |
446 | return SCPE_OK; /* continue */\r | |
447 | \r | |
448 | default: /* unknown */\r | |
449 | break;\r | |
450 | }\r | |
451 | \r | |
452 | /* End of command, process error or schedule end of motion */\r | |
453 | \r | |
454 | if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */\r | |
455 | uptr->UST = uptr->UST | STA_EOT;\r | |
456 | if (r != SCPE_OK) {\r | |
457 | uptr->FNC = FNC_NOP; /* nop function */\r | |
458 | mt_busy = 0; /* not busy */\r | |
459 | mt_updint (mt_rdy, 1); /* end of motion */\r | |
460 | return r;\r | |
461 | }\r | |
462 | uptr->FNC = FNC_EOM; /* sched end motion */\r | |
463 | sim_activate (uptr, mt_ctime);\r | |
464 | return SCPE_OK;\r | |
465 | }\r | |
466 | \r | |
467 | /* Write word to buffer */\r | |
468 | \r | |
469 | void mt_wrwd (UNIT *uptr, uint32 dat)\r | |
470 | {\r | |
471 | uint32 c1, c2;\r | |
472 | \r | |
473 | c1 = (dat >> 10) & 077; /* get 2 chars */\r | |
474 | c2 = (dat >> 4) & 077;\r | |
475 | if (uptr->FNC == (FNC_WBCD2 | FNC_2ND)) { /* BCD? */\r | |
476 | if (c1 == 0) c1 = 012; /* change 0 to 12 */\r | |
477 | if (c2 == 0) c2 = 012;\r | |
478 | }\r | |
479 | if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c1; /* store 2 char */\r | |
480 | if (mt_ptr < DBSIZE) mtxb[mt_ptr++] = c2;\r | |
481 | if ((uptr->FNC == (FNC_WBIN3 | FNC_2ND)) && /* write 3? */\r | |
482 | (mt_ptr < DBSIZE)) mtxb[mt_ptr++] = mt_buf & 017;\r | |
483 | return;\r | |
484 | }\r | |
485 | \r | |
486 | /* Map tape error status */\r | |
487 | \r | |
488 | t_stat mt_map_err (UNIT *uptr, t_stat st)\r | |
489 | {\r | |
490 | switch (st) {\r | |
491 | \r | |
492 | case MTSE_FMT: /* illegal fmt */\r | |
493 | case MTSE_UNATT: /* unattached */\r | |
494 | mt_err = 1; /* reject */\r | |
495 | case MTSE_OK: /* no error */\r | |
496 | return SCPE_IERR; /* never get here! */\r | |
497 | \r | |
498 | case MTSE_TMK: /* end of file */\r | |
499 | mt_eof = 1; /* eof */\r | |
500 | break;\r | |
501 | \r | |
502 | case MTSE_INVRL: /* invalid rec lnt */\r | |
503 | mt_err = 1;\r | |
504 | return SCPE_MTRLNT;\r | |
505 | \r | |
506 | case MTSE_IOERR: /* IO error */\r | |
507 | mt_err = 1; /* error */\r | |
508 | if (mt_stopioe) return SCPE_IOERR;\r | |
509 | break;\r | |
510 | \r | |
511 | case MTSE_RECE: /* record in error */\r | |
512 | case MTSE_EOM: /* end of medium */\r | |
513 | mt_err = 1; /* error */\r | |
514 | break;\r | |
515 | \r | |
516 | case MTSE_BOT: /* reverse into BOT */\r | |
517 | uptr->UST = STA_BOT; /* set status */\r | |
518 | break;\r | |
519 | \r | |
520 | case MTSE_WRP: /* write protect */\r | |
521 | mt_err = 1; /* error */\r | |
522 | return STOP_MTWRP;\r | |
523 | }\r | |
524 | \r | |
525 | return SCPE_OK;\r | |
526 | }\r | |
527 | \r | |
528 | /* Update interrupts */\r | |
529 | \r | |
530 | void mt_updint (uint32 rdy, uint32 mdirq)\r | |
531 | {\r | |
532 | mt_rdy = rdy; /* store new ready */\r | |
533 | mt_mdirq = mdirq; /* store new motion irq */\r | |
534 | if ((mt_rdy && !mt_dma) || mt_mdirq) SET_INT (INT_MT); /* update int request */\r | |
535 | else CLR_INT (INT_MT);\r | |
536 | return;\r | |
537 | }\r | |
538 | \r | |
539 | /* Reset routine */\r | |
540 | \r | |
541 | t_stat mt_reset (DEVICE *dptr)\r | |
542 | {\r | |
543 | int32 i;\r | |
544 | UNIT *uptr;\r | |
545 | \r | |
546 | mt_buf = 0; /* clear state */\r | |
547 | mt_usel = 0;\r | |
548 | mt_mdirq = 0;\r | |
549 | mt_eor = 0;\r | |
550 | mt_busy = 0;\r | |
551 | mt_rdy = 0;\r | |
552 | mt_eof = 0;\r | |
553 | mt_err = 0;\r | |
554 | mt_dma = 0;\r | |
555 | CLR_INT (INT_MT); /* clear int, enb */\r | |
556 | CLR_ENB (INT_MT);\r | |
557 | for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */\r | |
558 | uptr = mt_dev.units + i;\r | |
559 | sim_tape_reset (uptr); /* reset tape */\r | |
560 | sim_cancel (uptr); /* cancel op */\r | |
561 | uptr->UST = uptr->pos? 0: STA_BOT; /* update status */\r | |
562 | uptr->FNC = FNC_NOP;\r | |
563 | }\r | |
564 | return SCPE_OK;\r | |
565 | }\r | |
566 | \r | |
567 | /* Attach routine */\r | |
568 | \r | |
569 | t_stat mt_attach (UNIT *uptr, char *cptr)\r | |
570 | {\r | |
571 | t_stat r;\r | |
572 | \r | |
573 | r = sim_tape_attach (uptr, cptr); /* attach unit */\r | |
574 | if (r != SCPE_OK) return r; /* update status */\r | |
575 | uptr->UST = STA_BOT;\r | |
576 | return r;\r | |
577 | }\r | |
578 | \r | |
579 | /* Detach routine */\r | |
580 | \r | |
581 | t_stat mt_detach (UNIT* uptr)\r | |
582 | {\r | |
583 | uptr->UST = 0; /* update status */\r | |
584 | uptr->FNC = FNC_NOP; /* nop function */\r | |
585 | return sim_tape_detach (uptr); /* detach unit */\r | |
586 | }\r |