Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* id_mt.c: Interdata magnetic tape simulator\r |
2 | \r | |
3 | Copyright (c) 2001-2006, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | mt M46-494 dual density 9-track magtape controller\r | |
27 | \r | |
28 | 16-Feb-06 RMS Added tape capacity checking\r | |
29 | 18-Mar-05 RMS Added attached test to detach routine\r | |
30 | 07-Dec-04 RMS Added read-only file support\r | |
31 | 25-Apr-03 RMS Revised for extended file support\r | |
32 | 28-Mar-03 RMS Added multiformat support\r | |
33 | 28-Feb-03 RMS Revised for magtape library\r | |
34 | 20-Feb-03 RMS Fixed read to stop selch on error\r | |
35 | \r | |
36 | Magnetic tapes are represented as a series of variable 8b records\r | |
37 | of the form:\r | |
38 | \r | |
39 | 32b record length in bytes - exact number\r | |
40 | byte 0\r | |
41 | byte 1\r | |
42 | :\r | |
43 | byte n-2\r | |
44 | byte n-1\r | |
45 | 32b record length in bytes - exact number\r | |
46 | \r | |
47 | If the byte count is odd, the record is padded with an extra byte\r | |
48 | of junk. File marks are represented by a single record length of 0.\r | |
49 | End of tape is two consecutive end of file marks.\r | |
50 | */\r | |
51 | \r | |
52 | #include "id_defs.h"\r | |
53 | #include "sim_tape.h"\r | |
54 | \r | |
55 | #define UST u3 /* unit status */\r | |
56 | #define UCMD u4 /* unit command */\r | |
57 | #define MT_MAXFR (1 << 24) /* max transfer */\r | |
58 | \r | |
59 | /* Command - in UCMD */\r | |
60 | \r | |
61 | #define MTC_SPCR 0x11 /* backspace */\r | |
62 | #define MTC_SKFR 0x13 /* space file rev */\r | |
63 | #define MTC_CLR 0x20 /* clear */\r | |
64 | #define MTC_RD 0x21 /* read */\r | |
65 | #define MTC_WR 0x22 /* write */\r | |
66 | #define MTC_SKFF 0x23 /* space file fwd */\r | |
67 | #define MTC_WEOF 0x30 /* write eof */\r | |
68 | #define MTC_REW 0x38 /* rewind */\r | |
69 | #define MTC_MASK 0x3F\r | |
70 | #define MTC_STOP1 0x40 /* stop, set EOM */\r | |
71 | #define MTC_STOP2 0x80 /* stop, set NMTN */\r | |
72 | \r | |
73 | /* Status byte, * = in UST */\r | |
74 | \r | |
75 | #define STA_ERR 0x80 /* error */\r | |
76 | #define STA_EOF 0x40 /* end of file */\r | |
77 | #define STA_EOT 0x20 /* *end of tape */\r | |
78 | #define STA_NMTN 0x10 /* *no motion */\r | |
79 | #define STA_UFLGS (STA_EOT|STA_NMTN) /* unit flags */\r | |
80 | #define STA_MASK (STA_ERR|STA_EOF|STA_BSY|STA_EOM)\r | |
81 | #define SET_EX (STA_ERR|STA_EOF|STA_NMTN)\r | |
82 | \r | |
83 | extern uint32 int_req[INTSZ], int_enb[INTSZ];\r | |
84 | \r | |
85 | uint8 mtxb[MT_MAXFR]; /* xfer buffer */\r | |
86 | uint32 mt_bptr = 0; /* pointer */\r | |
87 | uint32 mt_blnt = 0; /* length */\r | |
88 | uint32 mt_sta = 0; /* status byte */\r | |
89 | uint32 mt_db = 0; /* data buffer */\r | |
90 | uint32 mt_xfr = 0; /* data xfr in prog */\r | |
91 | uint32 mt_arm[MT_NUMDR] = { 0 }; /* intr armed */\r | |
92 | int32 mt_wtime = 10; /* byte latency */\r | |
93 | int32 mt_rtime = 1000; /* record latency */\r | |
94 | int32 mt_stopioe = 1; /* stop on error */\r | |
95 | uint8 mt_tplte[] = { 0, o_MT0, o_MT0*2, o_MT0*3, TPL_END };\r | |
96 | \r | |
97 | static const uint8 bad_cmd[64] = {\r | |
98 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r | |
99 | 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r | |
100 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\r | |
101 | 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1\r | |
102 | };\r | |
103 | \r | |
104 | DEVICE mt_dev;\r | |
105 | uint32 mt (uint32 dev, uint32 op, uint32 dat);\r | |
106 | t_stat mt_svc (UNIT *uptr);\r | |
107 | t_stat mt_reset (DEVICE *dptr);\r | |
108 | t_stat mt_attach (UNIT *uptr, char *cptr);\r | |
109 | t_stat mt_detach (UNIT *uptr);\r | |
110 | t_stat mt_boot (int32 unitno, DEVICE *dptr);\r | |
111 | t_stat mt_map_err (UNIT *uptr, t_stat st);\r | |
112 | \r | |
113 | /* MT data structures\r | |
114 | \r | |
115 | mt_dev MT device descriptor\r | |
116 | mt_unit MT unit list\r | |
117 | mt_reg MT register list\r | |
118 | mt_mod MT modifier list\r | |
119 | */\r | |
120 | \r | |
121 | DIB mt_dib = { d_MT, 0, v_MT, mt_tplte, &mt, NULL };\r | |
122 | \r | |
123 | UNIT mt_unit[] = {\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 | { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }\r | |
128 | };\r | |
129 | \r | |
130 | REG mt_reg[] = {\r | |
131 | { HRDATA (STA, mt_sta, 8) },\r | |
132 | { HRDATA (BUF, mt_db, 8) },\r | |
133 | { BRDATA (DBUF, mtxb, 16, 8, MT_MAXFR) },\r | |
134 | { HRDATA (DBPTR, mt_bptr, 16) },\r | |
135 | { HRDATA (DBLNT, mt_blnt, 17), REG_RO },\r | |
136 | { FLDATA (XFR, mt_xfr, 0) },\r | |
137 | { GRDATA (IREQ, int_req[l_MT], 16, MT_NUMDR, i_MT) },\r | |
138 | { GRDATA (IENB, int_enb[l_MT], 16, MT_NUMDR, i_MT) },\r | |
139 | { BRDATA (IARM, mt_arm, 16, 1, MT_NUMDR) },\r | |
140 | { FLDATA (STOP_IOE, mt_stopioe, 0) },\r | |
141 | { DRDATA (WTIME, mt_wtime, 24), PV_LEFT + REG_NZ },\r | |
142 | { DRDATA (RTIME, mt_rtime, 24), PV_LEFT + REG_NZ },\r | |
143 | { URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) },\r | |
144 | { URDATA (CMD, mt_unit[0].UCMD, 16, 8, 0, MT_NUMDR, 0) },\r | |
145 | { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,\r | |
146 | MT_NUMDR, PV_LEFT | REG_RO) },\r | |
147 | { HRDATA (DEVNO, mt_dib.dno, 8), REG_HRO },\r | |
148 | { HRDATA (SELCH, mt_dib.sch, 1), REG_HRO },\r | |
149 | { NULL }\r | |
150 | };\r | |
151 | \r | |
152 | MTAB mt_mod[] = {\r | |
153 | { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
154 | { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r | |
155 | { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r | |
156 | &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r | |
157 | { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",\r | |
158 | &sim_tape_set_capac, &sim_tape_show_capac, NULL },\r | |
159 | { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r | |
160 | &set_dev, &show_dev, NULL },\r | |
161 | { MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH",\r | |
162 | &set_sch, &show_sch, NULL },\r | |
163 | { 0 }\r | |
164 | };\r | |
165 | \r | |
166 | DEVICE mt_dev = {\r | |
167 | "MT", mt_unit, mt_reg, mt_mod,\r | |
168 | MT_NUMDR, 10, 31, 1, 16, 8,\r | |
169 | NULL, NULL, &mt_reset,\r | |
170 | &mt_boot, &mt_attach, &mt_detach,\r | |
171 | &mt_dib, DEV_DISABLE\r | |
172 | };\r | |
173 | \r | |
174 | /* Magtape: IO routine */\r | |
175 | \r | |
176 | uint32 mt (uint32 dev, uint32 op, uint32 dat)\r | |
177 | {\r | |
178 | uint32 i, f, t;\r | |
179 | uint32 u = (dev - mt_dib.dno) / o_MT0;\r | |
180 | UNIT *uptr = mt_dev.units + u;\r | |
181 | \r | |
182 | switch (op) { /* case IO op */\r | |
183 | \r | |
184 | case IO_ADR: /* select */\r | |
185 | sch_adr (mt_dib.sch, dev); /* inform sel ch */\r | |
186 | return BY; /* byte only */\r | |
187 | \r | |
188 | case IO_RD: /* read data */\r | |
189 | if (mt_xfr) mt_sta = mt_sta | STA_BSY; /* xfr? set busy */\r | |
190 | return mt_db; /* return data */\r | |
191 | \r | |
192 | case IO_WD: /* write data */\r | |
193 | if (mt_xfr) { /* transfer? */\r | |
194 | mt_sta = mt_sta | STA_BSY; /* set busy */\r | |
195 | if ((uptr->UCMD & (MTC_STOP1 | MTC_STOP2)) &&\r | |
196 | ((uptr->UCMD & MTC_MASK) == MTC_WR)) /* while stopping? */\r | |
197 | mt_sta = mt_sta | STA_ERR; /* write overrun */\r | |
198 | }\r | |
199 | mt_db = dat & DMASK8; /* store data */\r | |
200 | break;\r | |
201 | \r | |
202 | case IO_SS: /* status */\r | |
203 | mt_sta = mt_sta & STA_MASK; /* ctrl status */\r | |
204 | if (uptr->flags & UNIT_ATT) /* attached? */\r | |
205 | t = mt_sta | (uptr->UST & STA_UFLGS); /* yes, unit status */\r | |
206 | else t = mt_sta | STA_DU; /* no, dev unavail */\r | |
207 | if (t & SET_EX) t = t | STA_EX; /* test for ex */\r | |
208 | return t;\r | |
209 | \r | |
210 | case IO_OC: /* command */\r | |
211 | mt_arm[u] = int_chg (v_MT + u, dat, mt_arm[u]);\r | |
212 | f = dat & MTC_MASK; /* get cmd */\r | |
213 | if (f == MTC_CLR) { /* clear? */\r | |
214 | mt_reset (&mt_dev); /* reset world */\r | |
215 | break;\r | |
216 | }\r | |
217 | if (((uptr->flags & UNIT_ATT) == 0) || /* ignore if unatt */\r | |
218 | bad_cmd[f] || /* or bad cmd */\r | |
219 | (((f == MTC_WR) || (f == MTC_WEOF)) && /* or write */\r | |
220 | sim_tape_wrp (uptr))) break; /* and protected */\r | |
221 | for (i = 0; i < MT_NUMDR; i++) { /* check other drvs */\r | |
222 | if (sim_is_active (&mt_unit[i]) && /* active? */\r | |
223 | (mt_unit[i].UCMD != MTC_REW)) { /* not rewind? */\r | |
224 | sim_cancel (&mt_unit[i]); /* stop */\r | |
225 | mt_unit[i].UCMD = 0;\r | |
226 | }\r | |
227 | }\r | |
228 | if (sim_is_active (uptr) && /* unit active? */\r | |
229 | !(uptr->UCMD & (MTC_STOP1 | MTC_STOP2))) /* not stopping? */\r | |
230 | break; /* ignore */\r | |
231 | if ((f == MTC_WR) || (f == MTC_REW)) mt_sta = 0;/* write, rew: bsy=0 */\r | |
232 | else mt_sta = STA_BSY; /* bsy=1,nmtn,eom,err=0 */\r | |
233 | mt_bptr = mt_blnt = 0; /* not yet started */\r | |
234 | if ((f == MTC_RD) || (f == MTC_WR)) /* data xfr? */\r | |
235 | mt_xfr = 1; /* set xfr flag */\r | |
236 | else mt_xfr = 0;\r | |
237 | uptr->UCMD = f; /* save cmd */\r | |
238 | uptr->UST = 0; /* clr tape stat */\r | |
239 | sim_activate (uptr, mt_rtime); /* start op */\r | |
240 | break;\r | |
241 | }\r | |
242 | \r | |
243 | return 0;\r | |
244 | }\r | |
245 | \r | |
246 | /* Unit service\r | |
247 | \r | |
248 | A given operation can generate up to three interrupts\r | |
249 | \r | |
250 | - EOF generates an interrupt when set (read, space, wreof)\r | |
251 | BUSY will still be set, EOM and NMTN will be clear\r | |
252 | - After operation complete + delay, EOM generates an interrupt\r | |
253 | BUSY will be clear, EOM will be set, NMTN will be clear\r | |
254 | - After a further delay, NMTN generates an interrupt\r | |
255 | BUSY will be clear, EOM and NMTN will be set\r | |
256 | \r | |
257 | Rewind generates an interrupt when NMTN sets\r | |
258 | */\r | |
259 | \r | |
260 | t_stat mt_svc (UNIT *uptr)\r | |
261 | {\r | |
262 | uint32 i;\r | |
263 | int32 u = uptr - mt_dev.units;\r | |
264 | uint32 dev = mt_dib.dno + (u * o_MT0);\r | |
265 | t_mtrlnt tbc;\r | |
266 | t_bool passed_eot;\r | |
267 | t_stat st, r = SCPE_OK;\r | |
268 | \r | |
269 | if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r | |
270 | uptr->UCMD = 0; /* clr cmd */\r | |
271 | uptr->UST = 0; /* set status */\r | |
272 | mt_xfr = 0; /* clr op flags */\r | |
273 | mt_sta = STA_ERR | STA_EOM; /* set status */\r | |
274 | if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */\r | |
275 | return IORETURN (mt_stopioe, SCPE_UNATT);\r | |
276 | }\r | |
277 | \r | |
278 | if (uptr->UCMD & MTC_STOP2) { /* stop, gen NMTN? */\r | |
279 | uptr->UCMD = 0; /* clr cmd */\r | |
280 | uptr->UST = uptr->UST | STA_NMTN; /* set nmtn */\r | |
281 | mt_xfr = 0; /* clr xfr */\r | |
282 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
283 | return SCPE_OK;\r | |
284 | }\r | |
285 | \r | |
286 | if (uptr->UCMD & MTC_STOP1) { /* stop, gen EOM? */\r | |
287 | uptr->UCMD = uptr->UCMD | MTC_STOP2; /* clr cmd */\r | |
288 | mt_sta = (mt_sta & ~STA_BSY) | STA_EOM; /* clr busy, set eom */\r | |
289 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
290 | sim_activate (uptr, mt_rtime); /* schedule */\r | |
291 | return SCPE_OK;\r | |
292 | }\r | |
293 | \r | |
294 | passed_eot = sim_tape_eot (uptr); /* passed EOT? */\r | |
295 | switch (uptr->UCMD) { /* case on function */\r | |
296 | \r | |
297 | case MTC_REW: /* rewind */\r | |
298 | sim_tape_rewind (uptr); /* reposition */\r | |
299 | uptr->UCMD = 0; /* clr cmd */\r | |
300 | uptr->UST = STA_NMTN | STA_EOT; /* update status */\r | |
301 | mt_sta = mt_sta & ~STA_BSY; /* don't set EOM */\r | |
302 | if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */\r | |
303 | return SCPE_OK;\r | |
304 | \r | |
305 | /* For read, busy = 1 => buffer empty\r | |
306 | For write, busy = 1 => buffer full\r | |
307 | For read, data transfers continue for the full length of the\r | |
308 | record, or the maximum size of the transfer buffer\r | |
309 | For write, data transfers continue until a write is attempted\r | |
310 | and the buffer is empty\r | |
311 | */\r | |
312 | \r | |
313 | case MTC_RD: /* read */\r | |
314 | if (mt_blnt == 0) { /* first time? */\r | |
315 | st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */\r | |
316 | if (st == MTSE_RECE) mt_sta = mt_sta | STA_ERR; /* rec in err? */\r | |
317 | else if (st != SCPE_OK) { /* other error? */\r | |
318 | r = mt_map_err (uptr, st); /* map error */\r | |
319 | if (sch_actv (mt_dib.sch, dev)) /* if sch, stop */\r | |
320 | sch_stop (mt_dib.sch);\r | |
321 | break;\r | |
322 | }\r | |
323 | mt_blnt = tbc; /* set buf lnt */\r | |
324 | }\r | |
325 | \r | |
326 | if (sch_actv (mt_dib.sch, dev)) { /* sch active? */\r | |
327 | i = sch_wrmem (mt_dib.sch, mtxb, mt_blnt); /* store rec in mem */\r | |
328 | if (sch_actv (mt_dib.sch, dev)) /* sch still active? */\r | |
329 | sch_stop (mt_dib.sch); /* stop chan, long rd */\r | |
330 | else if (i < mt_blnt) /* process entire rec? */\r | |
331 | mt_sta = mt_sta | STA_ERR; /* no, overrun error */\r | |
332 | }\r | |
333 | else if (mt_bptr < mt_blnt) { /* no, if !eor */\r | |
334 | if (!(mt_sta & STA_BSY)) /* busy still clr? */\r | |
335 | mt_sta = mt_sta | STA_ERR; /* read overrun */\r | |
336 | mt_db = mtxb[mt_bptr++]; /* get next byte */\r | |
337 | mt_sta = mt_sta & ~STA_BSY; /* !busy = buf full */\r | |
338 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
339 | sim_activate (uptr, mt_wtime); /* reschedule */\r | |
340 | return SCPE_OK;\r | |
341 | }\r | |
342 | break; /* record done */\r | |
343 | \r | |
344 | case MTC_WR: /* write */\r | |
345 | if (sch_actv (mt_dib.sch, dev)) { /* sch active? */\r | |
346 | mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */\r | |
347 | if (sch_actv (mt_dib.sch, dev)) /* not done? */\r | |
348 | sch_stop (mt_dib.sch); /* stop chan */\r | |
349 | }\r | |
350 | else if (mt_sta & STA_BSY) { /* no, if !eor */\r | |
351 | if (mt_bptr < MT_MAXFR) /* if room */\r | |
352 | mtxb[mt_bptr++] = mt_db; /* store in buf */\r | |
353 | mt_sta = mt_sta & ~STA_BSY; /* !busy = buf emp */\r | |
354 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
355 | sim_activate (uptr, mt_wtime); /* reschedule */\r | |
356 | return SCPE_OK;\r | |
357 | }\r | |
358 | \r | |
359 | if (mt_bptr) { /* any chars? */\r | |
360 | if (st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)) /* write, err? */\r | |
361 | r = mt_map_err (uptr, st); /* map error */\r | |
362 | }\r | |
363 | break; /* record done */\r | |
364 | \r | |
365 | case MTC_WEOF: /* write eof */\r | |
366 | if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r | |
367 | r = mt_map_err (uptr, st); /* map error */\r | |
368 | mt_sta = mt_sta | STA_EOF; /* set eof */\r | |
369 | if (mt_arm[u]) SET_INT (v_MT + u); /* interrupt */\r | |
370 | break;\r | |
371 | \r | |
372 | case MTC_SKFF: /* skip file fwd */\r | |
373 | while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;\r | |
374 | if (st == MTSE_TMK) { /* stopped by tmk? */\r | |
375 | mt_sta = mt_sta | STA_EOF; /* set eof */\r | |
376 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
377 | }\r | |
378 | else r = mt_map_err (uptr, st); /* map error */\r | |
379 | break;\r | |
380 | \r | |
381 | case MTC_SKFR: /* skip file rev */\r | |
382 | while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;\r | |
383 | if (st == MTSE_TMK) { /* stopped by tmk? */\r | |
384 | mt_sta = mt_sta | STA_EOF; /* set eof */\r | |
385 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
386 | }\r | |
387 | else r = mt_map_err (uptr, st); /* map error */\r | |
388 | break;\r | |
389 | \r | |
390 | case MTC_SPCR: /* backspace */\r | |
391 | if (st = sim_tape_sprecr (uptr, &tbc)) /* skip rec rev, err? */\r | |
392 | r = mt_map_err (uptr, st); /* map error */\r | |
393 | break;\r | |
394 | } /* end case */\r | |
395 | \r | |
396 | if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */\r | |
397 | uptr->UST = uptr->UST | STA_EOT;\r | |
398 | uptr->UCMD = uptr->UCMD | MTC_STOP1; /* set stop stage 1 */\r | |
399 | sim_activate (uptr, mt_rtime); /* schedule */\r | |
400 | return r;\r | |
401 | }\r | |
402 | \r | |
403 | /* Map tape error status */\r | |
404 | \r | |
405 | t_stat mt_map_err (UNIT *uptr, t_stat st)\r | |
406 | {\r | |
407 | int32 u = uptr - mt_dev.units;\r | |
408 | \r | |
409 | switch (st) {\r | |
410 | \r | |
411 | case MTSE_FMT: /* illegal fmt */\r | |
412 | case MTSE_UNATT: /* not attached */\r | |
413 | mt_sta = mt_sta | STA_ERR;\r | |
414 | case MTSE_OK: /* no error */\r | |
415 | return SCPE_IERR;\r | |
416 | \r | |
417 | case MTSE_TMK: /* end of file */\r | |
418 | mt_sta = mt_sta | STA_EOF; /* set eof */\r | |
419 | if (mt_arm[u]) SET_INT (v_MT + u); /* set intr */\r | |
420 | break;\r | |
421 | \r | |
422 | case MTSE_IOERR: /* IO error */\r | |
423 | mt_sta = mt_sta | STA_ERR; /* set err */\r | |
424 | if (mt_stopioe) return SCPE_IOERR;\r | |
425 | break;\r | |
426 | \r | |
427 | case MTSE_INVRL: /* invalid rec lnt */\r | |
428 | mt_sta = mt_sta | STA_ERR;\r | |
429 | return SCPE_MTRLNT;\r | |
430 | \r | |
431 | case MTSE_WRP: /* write protect */\r | |
432 | case MTSE_RECE: /* record in error */\r | |
433 | case MTSE_EOM: /* end of medium */\r | |
434 | mt_sta = mt_sta | STA_ERR; /* set err */\r | |
435 | break;\r | |
436 | \r | |
437 | case MTSE_BOT: /* reverse into BOT */\r | |
438 | uptr->UST = uptr->UST | STA_EOT; /* set err */\r | |
439 | break;\r | |
440 | } /* end switch */\r | |
441 | \r | |
442 | return SCPE_OK;\r | |
443 | }\r | |
444 | \r | |
445 | /* Reset routine */\r | |
446 | \r | |
447 | t_stat mt_reset (DEVICE *dptr)\r | |
448 | {\r | |
449 | uint32 u;\r | |
450 | UNIT *uptr;\r | |
451 | \r | |
452 | mt_bptr = mt_blnt = 0; /* clr buf */\r | |
453 | mt_sta = STA_BSY; /* clr flags */\r | |
454 | mt_xfr = 0; /* clr controls */\r | |
455 | for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */\r | |
456 | CLR_INT (v_MT + u); /* clear int */\r | |
457 | CLR_ENB (v_MT + u); /* disable int */\r | |
458 | mt_arm[u] = 0; /* disarm int */\r | |
459 | uptr = mt_dev.units + u;\r | |
460 | sim_tape_reset (uptr); /* clear pos flag */\r | |
461 | sim_cancel (uptr); /* cancel activity */\r | |
462 | uptr->UST = (uptr->UST & STA_UFLGS) | STA_NMTN; /* init status */\r | |
463 | uptr->UCMD = 0; /* init cmd */\r | |
464 | }\r | |
465 | return SCPE_OK;\r | |
466 | }\r | |
467 | \r | |
468 | /* Attach routine */\r | |
469 | \r | |
470 | t_stat mt_attach (UNIT *uptr, char *cptr)\r | |
471 | {\r | |
472 | int32 u = uptr - mt_dev.units;\r | |
473 | t_stat r;\r | |
474 | \r | |
475 | r = sim_tape_attach (uptr, cptr);\r | |
476 | if (r != SCPE_OK) return r;\r | |
477 | uptr->UST = STA_EOT;\r | |
478 | if (mt_arm[u]) SET_INT (v_MT + u);\r | |
479 | return r;\r | |
480 | }\r | |
481 | \r | |
482 | /* Detach routine */\r | |
483 | \r | |
484 | t_stat mt_detach (UNIT* uptr)\r | |
485 | {\r | |
486 | int32 u = uptr - mt_dev.units;\r | |
487 | t_stat r;\r | |
488 | \r | |
489 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;\r | |
490 | r = sim_tape_detach (uptr);\r | |
491 | if (r != SCPE_OK) return r;\r | |
492 | if (mt_arm[u]) SET_INT (v_MT + u);\r | |
493 | uptr->UST = 0;\r | |
494 | return SCPE_OK;\r | |
495 | }\r | |
496 | \r | |
497 | /* Bootstrap routine */\r | |
498 | \r | |
499 | #define BOOT_START 0x50\r | |
500 | #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))\r | |
501 | \r | |
502 | static uint8 boot_rom[] = {\r | |
503 | 0xD5, 0x00, 0x00, 0xCF, /* ST: AL CF */\r | |
504 | 0x43, 0x00, 0x00, 0x80 /* BR 80 */\r | |
505 | };\r | |
506 | \r | |
507 | t_stat mt_boot (int32 unitno, DEVICE *dptr)\r | |
508 | {\r | |
509 | extern uint32 PC, dec_flgs;\r | |
510 | extern uint16 decrom[];\r | |
511 | extern DIB sch_dib;\r | |
512 | uint32 sch_dev;\r | |
513 | \r | |
514 | if (decrom[0xD5] & dec_flgs) return SCPE_NOFNC; /* AL defined? */\r | |
515 | sim_tape_rewind (&mt_unit[unitno]); /* rewind */\r | |
516 | sch_dev = sch_dib.dno + mt_dib.sch; /* sch dev # */\r | |
517 | IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */\r | |
518 | IOWriteB (AL_DEV, mt_dib.dno + (unitno * o_MT0)); /* set dev no for unit */\r | |
519 | IOWriteB (AL_IOC, 0xA1); /* set dev cmd */\r | |
520 | IOWriteB (AL_SCH, sch_dev); /* set dev no for chan */\r | |
521 | PC = BOOT_START;\r | |
522 | return SCPE_OK;\r | |
523 | }\r |