Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp11_ts.c: TS11/TSV05 magnetic tape simulator\r |
2 | \r | |
3 | Copyright (c) 1993-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 | ts TS11/TSV05 magtape\r | |
27 | \r | |
28 | 16-Feb-06 RMS Added tape capacity checking\r | |
29 | 31-Oct-05 RMS Fixed address width for large files\r | |
30 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r | |
31 | 07-Jul-05 RMS Removed extraneous externs\r | |
32 | 18-Mar-05 RMS Added attached test to detach routine\r | |
33 | 07-Dec-04 RMS Added read-only file support\r | |
34 | 30-Sep-04 RMS Revised Unibus interface\r | |
35 | 25-Jan-04 RMS Revised for device debug support\r | |
36 | 19-May-03 RMS Revised for new conditional compilation scheme\r | |
37 | 25-Apr-03 RMS Revised for extended file support\r | |
38 | 28-Mar-03 RMS Added multiformat support\r | |
39 | 28-Feb-03 RMS Revised to use magtape library\r | |
40 | 30-Sep-02 RMS Added variable address support to bootstrap\r | |
41 | Added vector change/display support\r | |
42 | Fixed CTL unload/clean decode\r | |
43 | Implemented XS0_MOT in extended status\r | |
44 | New data structures, revamped error recovery\r | |
45 | 28-Aug-02 RMS Added end of medium support\r | |
46 | 30-May-02 RMS Widened POS to 32b\r | |
47 | 22-Apr-02 RMS Added maximum record length protection\r | |
48 | 04-Apr-02 RMS Fixed bug in residual frame count after space operation\r | |
49 | 16-Feb-02 RMS Fixed bug in message header logic\r | |
50 | 26-Jan-02 RMS Revised bootstrap to conform to M9312\r | |
51 | 06-Jan-02 RMS Revised enable/disable support\r | |
52 | 30-Nov-01 RMS Added read only unit, extended SET/SHOW support\r | |
53 | 09-Nov-01 RMS Added bus map, VAX support\r | |
54 | 15-Oct-01 RMS Integrated debug logging across simulator\r | |
55 | 27-Sep-01 RMS Implemented extended characteristics and status\r | |
56 | Fixed bug in write characteristics status return\r | |
57 | 19-Sep-01 RMS Fixed bug in bootstrap\r | |
58 | 15-Sep-01 RMS Fixed bug in NXM test\r | |
59 | 07-Sep-01 RMS Revised device disable and interrupt mechanism\r | |
60 | 13-Jul-01 RMS Fixed bug in space reverse (found by Peter Schorn)\r | |
61 | \r | |
62 | Magnetic tapes are represented as a series of variable 8b records\r | |
63 | of the form:\r | |
64 | \r | |
65 | 32b record length in bytes - exact number\r | |
66 | byte 0\r | |
67 | byte 1\r | |
68 | :\r | |
69 | byte n-2\r | |
70 | byte n-1\r | |
71 | 32b record length in bytes - exact number\r | |
72 | \r | |
73 | If the byte count is odd, the record is padded with an extra byte\r | |
74 | of junk. File marks are represented by a single record length of 0.\r | |
75 | End of tape is two consecutive end of file marks.\r | |
76 | \r | |
77 | The TS11 functions in three environments:\r | |
78 | \r | |
79 | - PDP-11 Q22 systems - the I/O map is one for one, so it's safe to\r | |
80 | go through the I/O map\r | |
81 | - PDP-11 Unibus 22b systems - the TS11 behaves as an 18b Unibus\r | |
82 | peripheral and must go through the I/O map\r | |
83 | - VAX Q22 systems - the TS11 must go through the I/O map\r | |
84 | */\r | |
85 | \r | |
86 | #if defined (VM_PDP10) /* PDP10 version */\r | |
87 | #error "TS11 not supported on PDP10!"\r | |
88 | \r | |
89 | #elif defined (VM_VAX) /* VAX version */\r | |
90 | #include "vax_defs.h"\r | |
91 | #define TS_DIS 0 /* on by default */\r | |
92 | #define DMASK 0xFFFF\r | |
93 | \r | |
94 | #else /* PDP-11 version */\r | |
95 | #include "pdp11_defs.h"\r | |
96 | #define TS_DIS DEV_DIS /* off by default */\r | |
97 | extern int32 cpu_opt;\r | |
98 | #endif\r | |
99 | \r | |
100 | #include "sim_tape.h"\r | |
101 | #define ADDRTEST (UNIBUS? 0177774: 0177700)\r | |
102 | \r | |
103 | /* TSBA/TSDB - 17772520: base address/data buffer register\r | |
104 | \r | |
105 | read: most recent memory address\r | |
106 | write word: initiate command\r | |
107 | write byte: diagnostic use\r | |
108 | */\r | |
109 | \r | |
110 | /* TSSR - 17772522: subsystem status register\r | |
111 | TSDBX - 17772523: extended address register\r | |
112 | \r | |
113 | read: return status\r | |
114 | write word: initialize\r | |
115 | write byte: if odd, set extended packet address register\r | |
116 | */\r | |
117 | \r | |
118 | #define TSSR_SC 0100000 /* special condition */\r | |
119 | #define TSSR_RMR 0010000 /* reg mod refused */\r | |
120 | #define TSSR_NXM 0004000 /* nxm */\r | |
121 | #define TSSR_NBA 0002000 /* need buf addr */\r | |
122 | #define TSSR_V_EMA 8 /* mem addr<17:16> */\r | |
123 | #define TSSR_EMA 0001400\r | |
124 | #define TSSR_SSR 0000200 /* subsystem ready */\r | |
125 | #define TSSR_OFL 0000100 /* offline */\r | |
126 | #define TSSR_V_TC 1 /* term class */\r | |
127 | #define TSSR_M_TC 07\r | |
128 | #define TSSR_TC (TSSR_M_TC << TSSR_V_TC)\r | |
129 | #define TC0 (0 << TSSR_V_TC) /* ok */\r | |
130 | #define TC1 (1 << TSSR_V_TC) /* attention */\r | |
131 | #define TC2 (2 << TSSR_V_TC) /* status alert */\r | |
132 | #define TC3 (3 << TSSR_V_TC) /* func reject */\r | |
133 | #define TC4 (4 << TSSR_V_TC) /* retry, moved */\r | |
134 | #define TC5 (5 << TSSR_V_TC) /* retry */\r | |
135 | #define TC6 (6 << TSSR_V_TC) /* pos lost */\r | |
136 | #define TC7 (7 << TSSR_V_TC) /* fatal err */\r | |
137 | #define TSSR_MBZ 0060060\r | |
138 | #define GET_TC(x) (((x) >> TSSR_V_TC) & TSSR_M_TC) \r | |
139 | \r | |
140 | #define TSDBX_M_XA 017 /* ext addr */\r | |
141 | #define TSDBX_BOOT 0000200 /* boot */\r | |
142 | \r | |
143 | /* Command packet offsets */\r | |
144 | \r | |
145 | #define CMD_PLNT 4 /* cmd pkt length */\r | |
146 | #define cmdhdr tscmdp[0] /* header */\r | |
147 | #define cmdadl tscmdp[1] /* address low */\r | |
148 | #define cmdadh tscmdp[2] /* address high */\r | |
149 | #define cmdlnt tscmdp[3] /* length */\r | |
150 | \r | |
151 | /* Command packet header */\r | |
152 | \r | |
153 | #define CMD_ACK 0100000 /* acknowledge */\r | |
154 | #define CMD_CVC 0040000 /* clear vol chk */\r | |
155 | #define CMD_OPP 0020000 /* opposite */\r | |
156 | #define CMD_SWP 0010000 /* swap bytes */\r | |
157 | #define CMD_V_MODE 8 /* mode */\r | |
158 | #define CMD_M_MODE 017\r | |
159 | #define CMD_IE 0000200 /* int enable */\r | |
160 | #define CMD_V_FNC 0 /* function */\r | |
161 | #define CMD_M_FNC 037 /* function */\r | |
162 | #define CMD_N_FNC (CMD_M_FNC + 1)\r | |
163 | #define FNC_READ 001 /* read */\r | |
164 | #define FNC_WCHR 004 /* write char */\r | |
165 | #define FNC_WRIT 005 /* write */\r | |
166 | #define FNC_WSSM 006 /* write mem */\r | |
167 | #define FNC_POS 010 /* position */\r | |
168 | #define FNC_FMT 011 /* format */\r | |
169 | #define FNC_CTL 012 /* control */\r | |
170 | #define FNC_INIT 013 /* init */\r | |
171 | #define FNC_GSTA 017 /* get status */\r | |
172 | #define CMD_MBZ 0000140\r | |
173 | #define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC)\r | |
174 | #define GET_MOD(x) (((x) >> CMD_V_MODE) & CMD_M_MODE)\r | |
175 | \r | |
176 | /* Function test flags */\r | |
177 | \r | |
178 | #define FLG_MO 001 /* motion */\r | |
179 | #define FLG_WR 002 /* write */\r | |
180 | #define FLG_AD 004 /* addr mem */\r | |
181 | \r | |
182 | /* Message packet offsets */\r | |
183 | \r | |
184 | #define MSG_PLNT 8 /* packet length */\r | |
185 | #define msghdr tsmsgp[0] /* header */\r | |
186 | #define msglnt tsmsgp[1] /* length */\r | |
187 | #define msgrfc tsmsgp[2] /* residual frame */\r | |
188 | #define msgxs0 tsmsgp[3] /* ext status 0 */\r | |
189 | #define msgxs1 tsmsgp[4] /* ext status 1 */\r | |
190 | #define msgxs2 tsmsgp[5] /* ext status 2 */\r | |
191 | #define msgxs3 tsmsgp[6] /* ext status 3 */\r | |
192 | #define msgxs4 tsmsgp[7] /* ext status 4 */\r | |
193 | \r | |
194 | /* Message packet header */\r | |
195 | \r | |
196 | #define MSG_ACK 0100000 /* acknowledge */\r | |
197 | #define MSG_MATN 0000000 /* attention */\r | |
198 | #define MSG_MILL 0000400 /* illegal */\r | |
199 | #define MSG_MNEF 0001000 /* non exec fnc */\r | |
200 | #define MSG_CEND 0000020 /* end */\r | |
201 | #define MSG_CFAIL 0000021 /* fail */\r | |
202 | #define MSG_CERR 0000022 /* error */\r | |
203 | #define MSG_CATN 0000023 /* attention */\r | |
204 | \r | |
205 | /* Extended status register 0 */\r | |
206 | \r | |
207 | #define XS0_TMK 0100000 /* tape mark */\r | |
208 | #define XS0_RLS 0040000 /* rec lnt short */\r | |
209 | #define XS0_LET 0020000 /* log end tape */\r | |
210 | #define XS0_RLL 0010000 /* rec lnt long */\r | |
211 | #define XS0_WLE 0004000 /* write lock err */\r | |
212 | #define XS0_NEF 0002000 /* non exec fnc */\r | |
213 | #define XS0_ILC 0001000 /* illegal cmd */\r | |
214 | #define XS0_ILA 0000400 /* illegal addr */\r | |
215 | #define XS0_MOT 0000200 /* tape has moved */\r | |
216 | #define XS0_ONL 0000100 /* online */\r | |
217 | #define XS0_IE 0000040 /* int enb */\r | |
218 | #define XS0_VCK 0000020 /* volume check */\r | |
219 | #define XS0_PET 0000010 /* 1600 bpi */\r | |
220 | #define XS0_WLK 0000004 /* write lock */\r | |
221 | #define XS0_BOT 0000002 /* BOT */\r | |
222 | #define XS0_EOT 0000001 /* EOT */\r | |
223 | #define XS0_ALLCLR 0177600 /* clear at start */\r | |
224 | \r | |
225 | /* Extended status register 1 */\r | |
226 | \r | |
227 | #define XS1_UCOR 0000002 /* uncorrectable */\r | |
228 | \r | |
229 | /* Extended status register 2 */\r | |
230 | \r | |
231 | #define XS2_XTF 0000200 /* ext features */\r | |
232 | \r | |
233 | /* Extended status register 3 */\r | |
234 | \r | |
235 | #define XS3_OPI 0000100 /* op incomplete */\r | |
236 | #define XS3_REV 0000040 /* reverse */\r | |
237 | #define XS3_RIB 0000001 /* reverse to BOT */\r | |
238 | \r | |
239 | /* Extended status register 4 */\r | |
240 | \r | |
241 | #define XS4_HDS 0100000 /* high density */\r | |
242 | \r | |
243 | /* Write characteristics packet offsets */\r | |
244 | \r | |
245 | #define WCH_PLNT 5 /* packet length */\r | |
246 | #define wchadl tswchp[0] /* address low */\r | |
247 | #define wchadh tswchp[1] /* address high */\r | |
248 | #define wchlnt tswchp[2] /* length */\r | |
249 | #define wchopt tswchp[3] /* options */\r | |
250 | #define wchxopt tswchp[4] /* ext options */\r | |
251 | \r | |
252 | /* Write characteristics options */\r | |
253 | \r | |
254 | #define WCH_ESS 0000200 /* stop dbl tmk */\r | |
255 | #define WCH_ENB 0000100 /* BOT = tmk */\r | |
256 | #define WCH_EAI 0000040 /* enb attn int */\r | |
257 | #define WCH_ERI 0000020 /* enb mrls int */\r | |
258 | \r | |
259 | /* Write characteristics extended options */\r | |
260 | \r | |
261 | #define WCHX_HDS 0000040 /* high density */\r | |
262 | \r | |
263 | #define MAX(a,b) (((a) >= (b))? (a): (b))\r | |
264 | #define MAX_PLNT 8 /* max pkt length */\r | |
265 | \r | |
266 | extern int32 int_req[IPL_HLVL];\r | |
267 | extern UNIT cpu_unit;\r | |
268 | extern FILE *sim_deb;\r | |
269 | \r | |
270 | uint8 *tsxb = NULL; /* xfer buffer */\r | |
271 | int32 tssr = 0; /* status register */\r | |
272 | int32 tsba = 0; /* mem addr */\r | |
273 | int32 tsdbx = 0; /* data buf ext */\r | |
274 | int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */\r | |
275 | int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */\r | |
276 | int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */\r | |
277 | int32 ts_ownc = 0; /* tape owns cmd */\r | |
278 | int32 ts_ownm = 0; /* tape owns msg */\r | |
279 | int32 ts_qatn = 0; /* queued attn */\r | |
280 | int32 ts_bcmd = 0; /* boot cmd */\r | |
281 | int32 ts_time = 10; /* record latency */\r | |
282 | static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */\r | |
283 | \r | |
284 | DEVICE ts_dev;\r | |
285 | t_stat ts_rd (int32 *data, int32 PA, int32 access);\r | |
286 | t_stat ts_wr (int32 data, int32 PA, int32 access);\r | |
287 | t_stat ts_svc (UNIT *uptr);\r | |
288 | t_stat ts_reset (DEVICE *dptr);\r | |
289 | t_stat ts_attach (UNIT *uptr, char *cptr);\r | |
290 | t_stat ts_detach (UNIT *uptr);\r | |
291 | t_stat ts_boot (int32 unitno, DEVICE *dptr);\r | |
292 | int32 ts_updtssr (int32 t);\r | |
293 | int32 ts_updxs0 (int32 t);\r | |
294 | void ts_cmpendcmd (int32 s0, int32 s1);\r | |
295 | void ts_endcmd (int32 ssf, int32 xs0f, int32 msg);\r | |
296 | int32 ts_map_status (t_stat st);\r | |
297 | \r | |
298 | /* TS data structures\r | |
299 | \r | |
300 | ts_dev TS device descriptor\r | |
301 | ts_unit TS unit list\r | |
302 | ts_reg TS register list\r | |
303 | ts_mod TS modifier list\r | |
304 | */\r | |
305 | \r | |
306 | DIB ts_dib = {\r | |
307 | IOBA_TS, IOLN_TS, &ts_rd, &ts_wr,\r | |
308 | 1, IVCL (TS), VEC_TS, { NULL }\r | |
309 | };\r | |
310 | \r | |
311 | UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) };\r | |
312 | \r | |
313 | REG ts_reg[] = {\r | |
314 | { GRDATA (TSSR, tssr, DEV_RDX, 16, 0) },\r | |
315 | { GRDATA (TSBA, tsba, DEV_RDX, 22, 0) },\r | |
316 | { GRDATA (TSDBX, tsdbx, DEV_RDX, 8, 0) },\r | |
317 | { GRDATA (CHDR, cmdhdr, DEV_RDX, 16, 0) },\r | |
318 | { GRDATA (CADL, cmdadl, DEV_RDX, 16, 0) },\r | |
319 | { GRDATA (CADH, cmdadh, DEV_RDX, 16, 0) },\r | |
320 | { GRDATA (CLNT, cmdlnt, DEV_RDX, 16, 0) },\r | |
321 | { GRDATA (MHDR, msghdr, DEV_RDX, 16, 0) },\r | |
322 | { GRDATA (MRFC, msgrfc, DEV_RDX, 16, 0) },\r | |
323 | { GRDATA (MXS0, msgxs0, DEV_RDX, 16, 0) },\r | |
324 | { GRDATA (MXS1, msgxs1, DEV_RDX, 16, 0) },\r | |
325 | { GRDATA (MXS2, msgxs2, DEV_RDX, 16, 0) },\r | |
326 | { GRDATA (MXS3, msgxs3, DEV_RDX, 16, 0) },\r | |
327 | { GRDATA (MSX4, msgxs4, DEV_RDX, 16, 0) },\r | |
328 | { GRDATA (WADL, wchadl, DEV_RDX, 16, 0) },\r | |
329 | { GRDATA (WADH, wchadh, DEV_RDX, 16, 0) },\r | |
330 | { GRDATA (WLNT, wchlnt, DEV_RDX, 16, 0) },\r | |
331 | { GRDATA (WOPT, wchopt, DEV_RDX, 16, 0) },\r | |
332 | { GRDATA (WXOPT, wchxopt, DEV_RDX, 16, 0) },\r | |
333 | { FLDATA (INT, IREQ (TS), INT_V_TS) },\r | |
334 | { FLDATA (ATTN, ts_qatn, 0) },\r | |
335 | { FLDATA (BOOT, ts_bcmd, 0) },\r | |
336 | { FLDATA (OWNC, ts_ownc, 0) },\r | |
337 | { FLDATA (OWNM, ts_ownm, 0) },\r | |
338 | { DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ },\r | |
339 | { DRDATA (POS, ts_unit.pos, T_ADDR_W), PV_LEFT + REG_RO },\r | |
340 | { GRDATA (DEVADDR, ts_dib.ba, DEV_RDX, 32, 0), REG_HRO },\r | |
341 | { GRDATA (DEVVEC, ts_dib.vec, DEV_RDX, 16, 0), REG_HRO },\r | |
342 | { NULL }\r | |
343 | };\r | |
344 | \r | |
345 | MTAB ts_mod[] = {\r | |
346 | { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
347 | { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r | |
348 | { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r | |
349 | &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r | |
350 | { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",\r | |
351 | &sim_tape_set_capac, &sim_tape_show_capac, NULL },\r | |
352 | { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",\r | |
353 | &set_addr, &show_addr, NULL },\r | |
354 | { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r | |
355 | &set_vec, &show_vec, NULL },\r | |
356 | { 0 }\r | |
357 | };\r | |
358 | \r | |
359 | DEVICE ts_dev = {\r | |
360 | "TS", &ts_unit, ts_reg, ts_mod,\r | |
361 | 1, 10, T_ADDR_W, 1, DEV_RDX, 8,\r | |
362 | NULL, NULL, &ts_reset,\r | |
363 | &ts_boot, &ts_attach, &ts_detach,\r | |
364 | &ts_dib, DEV_DISABLE | TS_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG\r | |
365 | };\r | |
366 | \r | |
367 | /* I/O dispatch routines, I/O addresses 17772520 - 17772522\r | |
368 | \r | |
369 | 17772520 TSBA read/write\r | |
370 | 17772522 TSSR read/write\r | |
371 | */\r | |
372 | \r | |
373 | t_stat ts_rd (int32 *data, int32 PA, int32 access)\r | |
374 | {\r | |
375 | switch ((PA >> 1) & 01) { /* decode PA<1> */\r | |
376 | \r | |
377 | case 0: /* TSBA */\r | |
378 | *data = tsba & DMASK; /* low 16b of ba */\r | |
379 | break;\r | |
380 | case 1: /* TSSR */\r | |
381 | *data = tssr = ts_updtssr (tssr); /* update tssr */\r | |
382 | break;\r | |
383 | }\r | |
384 | \r | |
385 | return SCPE_OK;\r | |
386 | }\r | |
387 | \r | |
388 | t_stat ts_wr (int32 data, int32 PA, int32 access)\r | |
389 | {\r | |
390 | int32 i, t;\r | |
391 | \r | |
392 | switch ((PA >> 1) & 01) { /* decode PA<1> */\r | |
393 | \r | |
394 | case 0: /* TSDB */\r | |
395 | if ((tssr & TSSR_SSR) == 0) { /* ready? */\r | |
396 | tssr = tssr | TSSR_RMR; /* no, refuse */\r | |
397 | break;\r | |
398 | }\r | |
399 | tsba = ((tsdbx & TSDBX_M_XA) << 18) | /* form pkt addr */\r | |
400 | ((data & 03) << 16) | (data & 0177774);\r | |
401 | tsdbx = 0; /* clr tsdbx */\r | |
402 | tssr = ts_updtssr (tssr & TSSR_NBA); /* clr ssr, err */\r | |
403 | msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLCLR); /* clr, upd xs0 */\r | |
404 | msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */\r | |
405 | CLR_INT (TS); /* clr int req */\r | |
406 | t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */\r | |
407 | tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */\r | |
408 | if (t) { /* nxm? */\r | |
409 | ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);\r | |
410 | return SCPE_OK;\r | |
411 | }\r | |
412 | for (i = 0; i < CMD_PLNT; i++) /* copy packet */\r | |
413 | tscmdp[i] = cpy_buf[i];\r | |
414 | ts_ownc = ts_ownm = 1; /* tape owns all */\r | |
415 | sim_activate (&ts_unit, ts_time); /* activate */\r | |
416 | break;\r | |
417 | \r | |
418 | case 1: /* TSSR */\r | |
419 | if (PA & 1) { /* TSDBX */\r | |
420 | if (UNIBUS) return SCPE_OK; /* not in TS11 */\r | |
421 | if (tssr & TSSR_SSR) { /* ready? */\r | |
422 | tsdbx = data; /* save */\r | |
423 | if (data & TSDBX_BOOT) {\r | |
424 | ts_bcmd = 1;\r | |
425 | sim_activate (&ts_unit, ts_time);\r | |
426 | }\r | |
427 | }\r | |
428 | else tssr = tssr | TSSR_RMR; /* no, err */\r | |
429 | }\r | |
430 | else if (access == WRITE) ts_reset (&ts_dev); /* reset */\r | |
431 | break;\r | |
432 | }\r | |
433 | \r | |
434 | return SCPE_OK;\r | |
435 | }\r | |
436 | \r | |
437 | /* Tape motion routines */\r | |
438 | \r | |
439 | #define XTC(x,t) (((unsigned) (x) << 16) | (t))\r | |
440 | #define GET_X(x) (((x) >> 16) & 0177777)\r | |
441 | #define GET_T(x) ((x) & 0177777)\r | |
442 | \r | |
443 | int32 ts_map_status (t_stat st)\r | |
444 | {\r | |
445 | switch (st) {\r | |
446 | \r | |
447 | case MTSE_OK:\r | |
448 | break;\r | |
449 | \r | |
450 | case MTSE_TMK:\r | |
451 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
452 | return (XTC (XS0_TMK | XS0_RLS, TC2));\r | |
453 | \r | |
454 | case MTSE_RECE: /* record in error */\r | |
455 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
456 | case MTSE_INVRL: /* invalid rec lnt */\r | |
457 | case MTSE_IOERR: /* IO error */\r | |
458 | msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */\r | |
459 | return (XTC (XS0_RLS, TC6)); /* pos lost */\r | |
460 | \r | |
461 | case MTSE_FMT:\r | |
462 | case MTSE_UNATT:\r | |
463 | case MTSE_EOM: /* end of medium */\r | |
464 | msgxs3 = msgxs3 | XS3_OPI; /* incomplete */\r | |
465 | return (XTC (XS0_RLS, TC6)); /* pos lost */\r | |
466 | \r | |
467 | case MTSE_BOT: /* reverse into BOT */\r | |
468 | msgxs3 = msgxs3 | XS3_RIB; /* set status */\r | |
469 | return (XTC (XS0_BOT | XS0_RLS, TC2)); /* tape alert */\r | |
470 | \r | |
471 | case MTSE_WRP: /* write protect */\r | |
472 | msgxs0 = msgxs0 | XS0_WLE | XS0_NEF; /* can't execute */\r | |
473 | return (XTC (XS0_WLE | XS0_NEF, TC3));\r | |
474 | }\r | |
475 | \r | |
476 | return 0;\r | |
477 | }\r | |
478 | \r | |
479 | int32 ts_spacef (UNIT *uptr, int32 fc, t_bool upd)\r | |
480 | {\r | |
481 | t_stat st;\r | |
482 | t_mtrlnt tbc;\r | |
483 | \r | |
484 | do {\r | |
485 | fc = (fc - 1) & DMASK; /* decr wc */\r | |
486 | if (upd) msgrfc = fc;\r | |
487 | if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */\r | |
488 | return ts_map_status (st); /* map status */\r | |
489 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
490 | } while (fc != 0);\r | |
491 | return 0;\r | |
492 | }\r | |
493 | \r | |
494 | int32 ts_skipf (UNIT *uptr, int32 fc)\r | |
495 | {\r | |
496 | t_stat st;\r | |
497 | t_mtrlnt tbc;\r | |
498 | t_bool tmkprv = FALSE;\r | |
499 | \r | |
500 | msgrfc = fc;\r | |
501 | if (sim_tape_bot (uptr) && (wchopt & WCH_ENB)) tmkprv = TRUE;\r | |
502 | do {\r | |
503 | st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */\r | |
504 | if (st == MTSE_TMK) { /* tape mark? */\r | |
505 | msgrfc = (msgrfc - 1) & DMASK; /* decr count */\r | |
506 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
507 | if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */\r | |
508 | return (XTC ((msgrfc? XS0_RLS: 0) |\r | |
509 | XS0_TMK | XS0_LET, TC2));\r | |
510 | tmkprv = TRUE; /* flag tmk */\r | |
511 | }\r | |
512 | else if (st != MTSE_OK) return ts_map_status (st);\r | |
513 | else tmkprv = FALSE; /* not a tmk */\r | |
514 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
515 | } while (msgrfc != 0);\r | |
516 | return 0;\r | |
517 | }\r | |
518 | \r | |
519 | int32 ts_spacer (UNIT *uptr, int32 fc, t_bool upd)\r | |
520 | {\r | |
521 | int32 st;\r | |
522 | t_mtrlnt tbc;\r | |
523 | \r | |
524 | do {\r | |
525 | fc = (fc - 1) & DMASK; /* decr wc */\r | |
526 | if (upd) msgrfc = fc;\r | |
527 | if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */\r | |
528 | return ts_map_status (st); /* map status */\r | |
529 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
530 | } while (fc != 0);\r | |
531 | return 0;\r | |
532 | }\r | |
533 | \r | |
534 | int32 ts_skipr (UNIT *uptr, int32 fc)\r | |
535 | {\r | |
536 | t_stat st;\r | |
537 | t_mtrlnt tbc;\r | |
538 | t_bool tmkprv = FALSE;\r | |
539 | \r | |
540 | msgrfc = fc;\r | |
541 | do {\r | |
542 | st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */\r | |
543 | if (st == MTSE_TMK) { /* tape mark? */\r | |
544 | msgrfc = (msgrfc - 1) & DMASK; /* decr count */\r | |
545 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
546 | if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */\r | |
547 | return (XTC ((msgrfc? XS0_RLS: 0) |\r | |
548 | XS0_TMK | XS0_LET, TC2));\r | |
549 | tmkprv = TRUE; /* flag tmk */\r | |
550 | }\r | |
551 | else if (st != MTSE_OK) return ts_map_status (st);\r | |
552 | else tmkprv = FALSE; /* not a tmk */\r | |
553 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
554 | } while (msgrfc != 0);\r | |
555 | return 0;\r | |
556 | }\r | |
557 | \r | |
558 | int32 ts_readf (UNIT *uptr, uint32 fc)\r | |
559 | {\r | |
560 | t_stat st;\r | |
561 | t_mtrlnt i, t, tbc, wbc;\r | |
562 | int32 wa;\r | |
563 | \r | |
564 | msgrfc = fc;\r | |
565 | st = sim_tape_rdrecf (uptr, tsxb, &tbc, MT_MAXFR); /* read rec fwd */\r | |
566 | if (st != MTSE_OK) return ts_map_status (st); /* error? */\r | |
567 | if (fc == 0) fc = 0200000; /* byte count */\r | |
568 | tsba = (cmdadh << 16) | cmdadl; /* buf addr */\r | |
569 | wbc = (tbc > fc)? fc: tbc; /* cap buf size */\r | |
570 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
571 | if (cmdhdr & CMD_SWP) { /* swapped? */\r | |
572 | for (i = 0; i < wbc; i++) { /* copy buffer */\r | |
573 | wa = tsba ^ 1; /* apply OPP */\r | |
574 | if (Map_WriteB (tsba, 1, &tsxb[i])) { /* store byte, nxm? */\r | |
575 | tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */\r | |
576 | return (XTC (XS0_RLS, TC4));\r | |
577 | }\r | |
578 | tsba = tsba + 1;\r | |
579 | msgrfc = (msgrfc - 1) & DMASK;\r | |
580 | }\r | |
581 | }\r | |
582 | else {\r | |
583 | t = Map_WriteB (tsba, wbc, tsxb); /* store record */\r | |
584 | tsba = tsba + (wbc - t); /* update tsba */\r | |
585 | if (t) { /* nxm? */\r | |
586 | tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */\r | |
587 | return (XTC (XS0_RLS, TC4));\r | |
588 | }\r | |
589 | msgrfc = (msgrfc - (wbc - t)) & DMASK; /* update fc */\r | |
590 | }\r | |
591 | if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */\r | |
592 | if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */\r | |
593 | return 0;\r | |
594 | }\r | |
595 | \r | |
596 | int32 ts_readr (UNIT *uptr, uint32 fc)\r | |
597 | {\r | |
598 | t_stat st;\r | |
599 | t_mtrlnt i, tbc, wbc;\r | |
600 | int32 wa;\r | |
601 | \r | |
602 | msgrfc = fc;\r | |
603 | st = sim_tape_rdrecr (uptr, tsxb, &tbc, MT_MAXFR); /* read rec rev */\r | |
604 | if (st != MTSE_OK) return ts_map_status (st); /* error? */\r | |
605 | if (fc == 0) fc = 0200000; /* byte count */\r | |
606 | tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */\r | |
607 | wbc = (tbc > fc)? fc: tbc; /* cap buf size */\r | |
608 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
609 | for (i = wbc; i > 0; i--) { /* copy buffer */\r | |
610 | tsba = tsba - 1;\r | |
611 | wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */\r | |
612 | if (Map_WriteB (wa, 1, &tsxb[i - 1])) { /* store byte, nxm? */\r | |
613 | tssr = ts_updtssr (tssr | TSSR_NXM);\r | |
614 | return (XTC (XS0_RLS, TC4));\r | |
615 | }\r | |
616 | msgrfc = (msgrfc - 1) & DMASK;\r | |
617 | }\r | |
618 | if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */\r | |
619 | if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */\r | |
620 | return 0;\r | |
621 | }\r | |
622 | \r | |
623 | int32 ts_write (UNIT *uptr, int32 fc)\r | |
624 | {\r | |
625 | int32 i, t;\r | |
626 | uint32 wa;\r | |
627 | t_stat st;\r | |
628 | \r | |
629 | msgrfc = fc;\r | |
630 | if (fc == 0) fc = 0200000; /* byte count */\r | |
631 | tsba = (cmdadh << 16) | cmdadl; /* buf addr */\r | |
632 | if (cmdhdr & CMD_SWP) { /* swapped? */\r | |
633 | for (i = 0; i < fc; i++) { /* copy mem to buf */\r | |
634 | wa = tsba ^ 1; /* apply OPP */\r | |
635 | if (Map_ReadB (wa, 1, &tsxb[i])) { /* fetch byte, nxm? */\r | |
636 | tssr = ts_updtssr (tssr | TSSR_NXM);\r | |
637 | return TC5;\r | |
638 | }\r | |
639 | tsba = tsba + 1;\r | |
640 | }\r | |
641 | }\r | |
642 | else {\r | |
643 | t = Map_ReadB (tsba, fc, tsxb); /* fetch record */\r | |
644 | tsba = tsba + (fc - t); /* update tsba */\r | |
645 | if (t) { /* nxm? */\r | |
646 | tssr = ts_updtssr (tssr | TSSR_NXM);\r | |
647 | return TC5;\r | |
648 | }\r | |
649 | }\r | |
650 | if (st = sim_tape_wrrecf (uptr, tsxb, fc)) /* write rec, err? */\r | |
651 | return ts_map_status (st); /* return status */\r | |
652 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
653 | msgrfc = 0;\r | |
654 | if (sim_tape_eot (&ts_unit)) /* EOT on write? */\r | |
655 | return XTC (XS0_EOT, TC2);\r | |
656 | return 0;\r | |
657 | }\r | |
658 | \r | |
659 | int32 ts_wtmk (UNIT *uptr)\r | |
660 | {\r | |
661 | t_stat st;\r | |
662 | \r | |
663 | if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */\r | |
664 | return ts_map_status (st); /* return status */\r | |
665 | msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */\r | |
666 | if (sim_tape_eot (&ts_unit)) /* EOT on write? */\r | |
667 | return XTC (XS0_EOT, TC2);\r | |
668 | return XTC (XS0_TMK, TC0);\r | |
669 | }\r | |
670 | \r | |
671 | /* Unit service */\r | |
672 | \r | |
673 | t_stat ts_svc (UNIT *uptr)\r | |
674 | {\r | |
675 | int32 i, t, bc, fnc, mod, st0, st1;\r | |
676 | \r | |
677 | static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */\r | |
678 | 0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */\r | |
679 | 5, 3, 5, 1, 0, 0, 0, 1, /* 10 - 17 */\r | |
680 | 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */\r | |
681 | 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */\r | |
682 | };\r | |
683 | static const int32 fnc_flg[CMD_N_FNC] = {\r | |
684 | 0, FLG_MO+FLG_AD, 0, 0, 0, FLG_MO+FLG_WR+FLG_AD, FLG_AD, 0,\r | |
685 | FLG_MO, FLG_MO+FLG_WR, FLG_MO, 0, 0, 0, 0, 0,\r | |
686 | 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */\r | |
687 | 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */\r | |
688 | };\r | |
689 | static const char *fnc_name[CMD_N_FNC] = {\r | |
690 | "0", "READ", "2", "3", "WCHR", "WRITE", "WSSM", "7",\r | |
691 | "POS", "FMT", "CTL", "INIT", "14", "15", "16", "GSTA",\r | |
692 | "20", "21", "22", "23", "24", "25", "26", "27",\r | |
693 | "30", "31", "32", "33", "34", "35", "36", "37"\r | |
694 | };\r | |
695 | \r | |
696 | if (ts_bcmd) { /* boot? */\r | |
697 | ts_bcmd = 0; /* clear flag */\r | |
698 | sim_tape_rewind (uptr); /* rewind */\r | |
699 | if (uptr->flags & UNIT_ATT) { /* attached? */\r | |
700 | cmdlnt = cmdadh = cmdadl = 0; /* defang rd */\r | |
701 | ts_spacef (uptr, 1, FALSE); /* space fwd */\r | |
702 | ts_readf (uptr, 512); /* read blk */\r | |
703 | tssr = ts_updtssr (tssr | TSSR_SSR);\r | |
704 | }\r | |
705 | else tssr = ts_updtssr (tssr | TSSR_SSR | TC3);\r | |
706 | if (cmdhdr & CMD_IE) SET_INT (TS);\r | |
707 | return SCPE_OK;\r | |
708 | }\r | |
709 | \r | |
710 | if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */\r | |
711 | tssr = ts_updtssr (tssr | TSSR_SSR); /* set rdy, int */\r | |
712 | if (cmdhdr & CMD_IE) SET_INT (TS);\r | |
713 | ts_ownc = ts_ownm = 0; /* CPU owns all */\r | |
714 | return SCPE_OK;\r | |
715 | }\r | |
716 | fnc = GET_FNC (cmdhdr); /* get fnc+mode */\r | |
717 | mod = GET_MOD (cmdhdr);\r | |
718 | if (DEBUG_PRS (ts_dev))\r | |
719 | fprintf (sim_deb, ">>TS: cmd=%s, mod=%o, buf=%o, lnt=%d, pos=%d\n",\r | |
720 | fnc_name[fnc], mod, cmdadl, cmdlnt, ts_unit.pos);\r | |
721 | if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */\r | |
722 | ts_endcmd (TC3, 0, 0); /* error */\r | |
723 | return SCPE_OK;\r | |
724 | }\r | |
725 | if (ts_qatn && (wchopt & WCH_EAI)) { /* attn pending? */\r | |
726 | ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn msg */\r | |
727 | SET_INT (TS); /* set interrupt */\r | |
728 | ts_qatn = 0; /* not pending */\r | |
729 | return SCPE_OK;\r | |
730 | }\r | |
731 | if (cmdhdr & CMD_CVC) /* cvc? clr vck */\r | |
732 | msgxs0 = msgxs0 & ~XS0_VCK;\r | |
733 | if ((cmdhdr & CMD_MBZ) || (mod >= fnc_mod[fnc])) { /* test mbz */\r | |
734 | ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);\r | |
735 | return SCPE_OK;\r | |
736 | }\r | |
737 | if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */\r | |
738 | ((msgxs0 & XS0_VCK) || !(uptr->flags & UNIT_ATT))) {\r | |
739 | ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);\r | |
740 | return SCPE_OK;\r | |
741 | }\r | |
742 | if ((fnc_flg[fnc] & FLG_WR) && /* write? */\r | |
743 | sim_tape_wrp (uptr)) { /* write lck? */\r | |
744 | ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);\r | |
745 | return SCPE_OK;\r | |
746 | }\r | |
747 | if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */\r | |
748 | ((fnc == FNC_POS) && (mod & 1))) && /* space rev */\r | |
749 | sim_tape_bot (uptr)) { /* BOT? */\r | |
750 | ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);\r | |
751 | return SCPE_OK;\r | |
752 | }\r | |
753 | if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */\r | |
754 | ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL);\r | |
755 | return SCPE_OK;\r | |
756 | }\r | |
757 | \r | |
758 | st0 = st1 = 0;\r | |
759 | switch (fnc) { /* case on func */\r | |
760 | \r | |
761 | case FNC_INIT: /* init */\r | |
762 | if (!sim_tape_bot (uptr)) msgxs0 = msgxs0 | XS0_MOT; /* set if tape moves */\r | |
763 | sim_tape_rewind (uptr); /* rewind */\r | |
764 | case FNC_WSSM: /* write mem */\r | |
765 | case FNC_GSTA: /* get status */\r | |
766 | ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */\r | |
767 | return SCPE_OK;\r | |
768 | \r | |
769 | case FNC_WCHR: /* write char */\r | |
770 | if ((cmdadh & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) {\r | |
771 | ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);\r | |
772 | break;\r | |
773 | }\r | |
774 | tsba = (cmdadh << 16) | cmdadl;\r | |
775 | bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1;\r | |
776 | t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */\r | |
777 | tsba = tsba + (bc - t); /* inc tsba */\r | |
778 | if (t) { /* nxm? */\r | |
779 | ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);\r | |
780 | return SCPE_OK;\r | |
781 | }\r | |
782 | for (i = 0; i < (bc / 2); i++) /* copy packet */\r | |
783 | tswchp[i] = cpy_buf[i];\r | |
784 | if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) ||\r | |
785 | (wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0);\r | |
786 | else {\r | |
787 | msgxs2 = msgxs2 | XS2_XTF | 1;\r | |
788 | tssr = ts_updtssr (tssr & ~TSSR_NBA);\r | |
789 | ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);\r | |
790 | }\r | |
791 | return SCPE_OK;\r | |
792 | \r | |
793 | case FNC_CTL: /* control */\r | |
794 | switch (mod) { /* case mode */\r | |
795 | \r | |
796 | case 00: /* msg buf rls */\r | |
797 | tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */\r | |
798 | if (wchopt & WCH_ERI) SET_INT (TS);\r | |
799 | ts_ownc = 0; ts_ownm = 1; /* keep msg */\r | |
800 | break;\r | |
801 | \r | |
802 | case 01: /* rewind and unload */\r | |
803 | if (!sim_tape_bot (uptr)) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */\r | |
804 | sim_tape_detach (uptr); /* unload */\r | |
805 | ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);\r | |
806 | break;\r | |
807 | \r | |
808 | case 02: /* clean */\r | |
809 | ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */\r | |
810 | break;\r | |
811 | \r | |
812 | case 03: /* undefined */\r | |
813 | ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);\r | |
814 | return SCPE_OK;\r | |
815 | \r | |
816 | case 04: /* rewind */\r | |
817 | if (!sim_tape_bot (uptr)) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */\r | |
818 | sim_tape_rewind (uptr);\r | |
819 | ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND);\r | |
820 | break;\r | |
821 | }\r | |
822 | break;\r | |
823 | \r | |
824 | case FNC_READ: /* read */\r | |
825 | switch (mod) { /* case mode */\r | |
826 | \r | |
827 | case 00: /* fwd */\r | |
828 | st0 = ts_readf (uptr, cmdlnt); /* read */\r | |
829 | break; \r | |
830 | \r | |
831 | case 01: /* back */\r | |
832 | st0 = ts_readr (uptr, cmdlnt); /* read */\r | |
833 | break;\r | |
834 | \r | |
835 | case 02: /* reread fwd */\r | |
836 | if (cmdhdr & CMD_OPP) { /* opposite? */\r | |
837 | st0 = ts_readr (uptr, cmdlnt);\r | |
838 | st1 = ts_spacef (uptr, 1, FALSE);\r | |
839 | }\r | |
840 | else {\r | |
841 | st0 = ts_spacer (uptr, 1, FALSE);\r | |
842 | st1 = ts_readf (uptr, cmdlnt);\r | |
843 | }\r | |
844 | break;\r | |
845 | \r | |
846 | case 03: /* reread back */\r | |
847 | if (cmdhdr & CMD_OPP) { /* opposite */\r | |
848 | st0 = ts_readf (uptr, cmdlnt);\r | |
849 | st1 = ts_spacer (uptr, 1, FALSE);\r | |
850 | }\r | |
851 | else {\r | |
852 | st0 = ts_spacef (uptr, 1, FALSE);\r | |
853 | st1 = ts_readr (uptr, cmdlnt);\r | |
854 | }\r | |
855 | break;\r | |
856 | }\r | |
857 | ts_cmpendcmd (st0, st1);\r | |
858 | break;\r | |
859 | \r | |
860 | case FNC_WRIT: /* write */\r | |
861 | switch (mod) { /* case mode */\r | |
862 | \r | |
863 | case 00: /* write */\r | |
864 | st0 = ts_write (uptr, cmdlnt);\r | |
865 | break;\r | |
866 | \r | |
867 | case 01: /* rewrite */\r | |
868 | st0 = ts_spacer (uptr, 1, FALSE);\r | |
869 | st1 = ts_write (uptr, cmdlnt);\r | |
870 | break;\r | |
871 | }\r | |
872 | ts_cmpendcmd (st0, st1);\r | |
873 | break;\r | |
874 | \r | |
875 | case FNC_FMT: /* format */\r | |
876 | switch (mod) { /* case mode */\r | |
877 | \r | |
878 | case 00: /* write tmk */\r | |
879 | st0 = ts_wtmk (uptr);\r | |
880 | break;\r | |
881 | \r | |
882 | case 01: /* erase */\r | |
883 | break;\r | |
884 | \r | |
885 | case 02: /* retry tmk */\r | |
886 | st0 = ts_spacer (uptr, 1, FALSE);\r | |
887 | st1 = ts_wtmk (uptr);\r | |
888 | break;\r | |
889 | }\r | |
890 | ts_cmpendcmd (st0, st1);\r | |
891 | break;\r | |
892 | \r | |
893 | case FNC_POS: /* position */\r | |
894 | switch (mod) { /* case mode */\r | |
895 | \r | |
896 | case 00: /* space fwd */\r | |
897 | st0 = ts_spacef (uptr, cmdadl, TRUE);\r | |
898 | break;\r | |
899 | \r | |
900 | case 01: /* space rev */\r | |
901 | st0 = ts_spacer (uptr, cmdadl, TRUE);\r | |
902 | break;\r | |
903 | \r | |
904 | case 02: /* space ffwd */\r | |
905 | st0 = ts_skipf (uptr, cmdadl);\r | |
906 | break;\r | |
907 | \r | |
908 | case 03: /* space frev */\r | |
909 | st0 = ts_skipr (uptr, cmdadl);\r | |
910 | break;\r | |
911 | \r | |
912 | case 04: /* rewind */\r | |
913 | if (!sim_tape_bot (uptr)) /* if tape moves */\r | |
914 | msgxs0 = msgxs0 | XS0_MOT;\r | |
915 | sim_tape_rewind (uptr);\r | |
916 | break;\r | |
917 | }\r | |
918 | ts_cmpendcmd (st0, 0);\r | |
919 | break;\r | |
920 | }\r | |
921 | \r | |
922 | return SCPE_OK;\r | |
923 | }\r | |
924 | \r | |
925 | /* Utility routines */\r | |
926 | \r | |
927 | int32 ts_updtssr (int32 t)\r | |
928 | {\r | |
929 | t = (t & ~TSSR_EMA) | ((tsba >> (16 - TSSR_V_EMA)) & TSSR_EMA);\r | |
930 | if (ts_unit.flags & UNIT_ATT) t = t & ~TSSR_OFL;\r | |
931 | else t = t | TSSR_OFL;\r | |
932 | return (t & ~TSSR_MBZ);\r | |
933 | }\r | |
934 | \r | |
935 | int32 ts_updxs0 (int32 t)\r | |
936 | {\r | |
937 | t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET;\r | |
938 | if (ts_unit.flags & UNIT_ATT) {\r | |
939 | t = t | XS0_ONL;\r | |
940 | if (sim_tape_wrp (&ts_unit)) t = t | XS0_WLK;\r | |
941 | if (sim_tape_bot (&ts_unit))\r | |
942 | t = (t | XS0_BOT) & ~XS0_EOT;\r | |
943 | if (sim_tape_eot (&ts_unit))\r | |
944 | t = (t | XS0_EOT) & ~XS0_BOT;\r | |
945 | }\r | |
946 | else t = t & ~XS0_EOT;\r | |
947 | if (cmdhdr & CMD_IE) t = t | XS0_IE;\r | |
948 | return t;\r | |
949 | }\r | |
950 | \r | |
951 | void ts_cmpendcmd (int32 s0, int32 s1)\r | |
952 | {\r | |
953 | int32 xs0, ssr, tc;\r | |
954 | static const int32 msg[8] = {\r | |
955 | MSG_ACK | MSG_CEND, MSG_ACK | MSG_MATN | MSG_CATN,\r | |
956 | MSG_ACK | MSG_CEND, MSG_ACK | MSG_CFAIL,\r | |
957 | MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR,\r | |
958 | MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR\r | |
959 | };\r | |
960 | \r | |
961 | xs0 = GET_X (s0) | GET_X (s1); /* or XS0 errs */\r | |
962 | s0 = GET_T (s0); /* get SSR errs */\r | |
963 | s1 = GET_T (s1);\r | |
964 | ssr = (s0 | s1) & ~TSSR_TC; /* or SSR errs */\r | |
965 | tc = MAX (GET_TC (s0), GET_TC (s1)); /* max term code */\r | |
966 | ts_endcmd (ssr | (tc << TSSR_V_TC), xs0, msg[tc]); /* end cmd */\r | |
967 | return;\r | |
968 | }\r | |
969 | \r | |
970 | void ts_endcmd (int32 tc, int32 xs0, int32 msg)\r | |
971 | {\r | |
972 | int32 i, t;\r | |
973 | \r | |
974 | msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */\r | |
975 | if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */\r | |
976 | if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */\r | |
977 | msghdr = msg;\r | |
978 | msglnt = wchlnt - 4; /* exclude hdr, bc */\r | |
979 | tsba = (wchadh << 16) | wchadl;\r | |
980 | for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++)\r | |
981 | cpy_buf[i] = (uint16) tsmsgp[i]; /* copy buffer */\r | |
982 | t = Map_WriteW (tsba, i << 1, cpy_buf); /* write to mem */\r | |
983 | tsba = tsba + ((i << 1) - t); /* incr tsba */\r | |
984 | if (t) { /* nxm? */\r | |
985 | tssr = tssr | TSSR_NXM;\r | |
986 | tc = (tc & ~TSSR_TC) | TC4;\r | |
987 | }\r | |
988 | }\r | |
989 | tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0));\r | |
990 | if (cmdhdr & CMD_IE) SET_INT (TS);\r | |
991 | ts_ownm = 0; ts_ownc = 0;\r | |
992 | if (DEBUG_PRS (ts_dev))\r | |
993 | fprintf (sim_deb, ">>TS: sta=%o, tc=%o, rfc=%d, pos=%d\n",\r | |
994 | msgxs0, GET_TC (tssr), msgrfc, ts_unit.pos);\r | |
995 | return;\r | |
996 | }\r | |
997 | \r | |
998 | /* Device reset */\r | |
999 | \r | |
1000 | t_stat ts_reset (DEVICE *dptr)\r | |
1001 | {\r | |
1002 | int32 i;\r | |
1003 | \r | |
1004 | sim_tape_rewind (&ts_unit);\r | |
1005 | tsba = tsdbx = 0;\r | |
1006 | ts_ownc = ts_ownm = 0;\r | |
1007 | ts_bcmd = 0;\r | |
1008 | ts_qatn = 0;\r | |
1009 | tssr = ts_updtssr (TSSR_NBA | TSSR_SSR);\r | |
1010 | for (i = 0; i < CMD_PLNT; i++) tscmdp[i] = 0;\r | |
1011 | for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0;\r | |
1012 | for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0;\r | |
1013 | msgxs0 = ts_updxs0 (XS0_VCK);\r | |
1014 | CLR_INT (TS);\r | |
1015 | if (tsxb == NULL) tsxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8));\r | |
1016 | if (tsxb == NULL) return SCPE_MEM;\r | |
1017 | return SCPE_OK;\r | |
1018 | }\r | |
1019 | \r | |
1020 | /* Attach */\r | |
1021 | \r | |
1022 | t_stat ts_attach (UNIT *uptr, char *cptr)\r | |
1023 | {\r | |
1024 | t_stat r;\r | |
1025 | \r | |
1026 | r = sim_tape_attach (uptr, cptr); /* attach unit */\r | |
1027 | if (r != SCPE_OK) return r; /* error? */\r | |
1028 | tssr = tssr & ~TSSR_OFL; /* clr offline */\r | |
1029 | if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */\r | |
1030 | if (ts_ownm) { /* own msg buf? */\r | |
1031 | ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */\r | |
1032 | SET_INT (TS); /* set interrupt */\r | |
1033 | ts_qatn = 0; /* don't queue */\r | |
1034 | }\r | |
1035 | else ts_qatn = 1; /* else queue */\r | |
1036 | return r;\r | |
1037 | }\r | |
1038 | \r | |
1039 | /* Detach routine */\r | |
1040 | \r | |
1041 | t_stat ts_detach (UNIT* uptr)\r | |
1042 | {\r | |
1043 | t_stat r;\r | |
1044 | \r | |
1045 | if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */\r | |
1046 | r = sim_tape_detach (uptr); /* detach unit */\r | |
1047 | if (r != SCPE_OK) return r; /* error? */\r | |
1048 | tssr = tssr | TSSR_OFL; /* set offline */\r | |
1049 | if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */\r | |
1050 | if (ts_ownm) { /* own msg buf? */\r | |
1051 | ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */\r | |
1052 | SET_INT (TS); /* set interrupt */\r | |
1053 | ts_qatn = 0; /* don't queue */\r | |
1054 | }\r | |
1055 | else ts_qatn = 1; /* else queue */\r | |
1056 | return r;\r | |
1057 | }\r | |
1058 | \r | |
1059 | /* Boot */\r | |
1060 | \r | |
1061 | #if defined (VM_PDP11)\r | |
1062 | #define BOOT_START 01000\r | |
1063 | #define BOOT_CSR0 (BOOT_START + 006)\r | |
1064 | #define BOOT_CSR1 (BOOT_START + 012)\r | |
1065 | #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))\r | |
1066 | \r | |
1067 | static const uint16 boot_rom[] = {\r | |
1068 | 0012706, 0001000, /* mov #boot_start, sp */\r | |
1069 | 0012700, 0172520, /* mov #tsba, r0 */\r | |
1070 | 0012701, 0172522, /* mov #tssr, r1 */\r | |
1071 | 0005011, /* clr (r1) ; init, rew */\r | |
1072 | 0105711, /* tstb (r1) ; wait */\r | |
1073 | 0100376, /* bpl .-2 */\r | |
1074 | 0012710, 0001070, /* mov #pkt1, (r0) ; set char */\r | |
1075 | 0105711, /* tstb (r1) ; wait */\r | |
1076 | 0100376, /* bpl .-2 */\r | |
1077 | 0012710, 0001110, /* mov #pkt2, (r0) ; read, skip */\r | |
1078 | 0105711, /* tstb (r1) ; wait */\r | |
1079 | 0100376, /* bpl .-2 */\r | |
1080 | 0012710, 0001110, /* mov #pkt2, (r0) ; read */\r | |
1081 | 0105711, /* tstb (r1) ; wait */\r | |
1082 | 0100376, /* bpl .-2 */\r | |
1083 | 0005711, /* tst (r1) ; err? */\r | |
1084 | 0100421, /* bmi hlt */\r | |
1085 | 0005000, /* clr r0 */\r | |
1086 | 0012704, 0001066+020, /* mov #sgnt+20, r4 */\r | |
1087 | 0005007, /* clr r7 */\r | |
1088 | 0046523, /* sgnt: "SM" */\r | |
1089 | 0140004, /* pkt1: 140004, wcpk, 0, 8. */\r | |
1090 | 0001100,\r | |
1091 | 0000000,\r | |
1092 | 0000010,\r | |
1093 | 0001122, /* wcpk: msg, 0, 14., 0 */\r | |
1094 | 0000000,\r | |
1095 | 0000016,\r | |
1096 | 0000000,\r | |
1097 | 0140001, /* pkt2: 140001, 0, 0, 512. */\r | |
1098 | 0000000,\r | |
1099 | 0000000,\r | |
1100 | 0001000,\r | |
1101 | 0000000 /* hlt: halt */\r | |
1102 | /* msg: .blk 4 */\r | |
1103 | };\r | |
1104 | \r | |
1105 | t_stat ts_boot (int32 unitno, DEVICE *dptr)\r | |
1106 | {\r | |
1107 | int32 i;\r | |
1108 | extern int32 saved_PC;\r | |
1109 | extern uint16 *M;\r | |
1110 | \r | |
1111 | sim_tape_rewind (&ts_unit);\r | |
1112 | for (i = 0; i < BOOT_LEN; i++)\r | |
1113 | M[(BOOT_START >> 1) + i] = boot_rom[i];\r | |
1114 | M[BOOT_CSR0 >> 1] = ts_dib.ba & DMASK;\r | |
1115 | M[BOOT_CSR1 >> 1] = (ts_dib.ba & DMASK) + 02;\r | |
1116 | saved_PC = BOOT_START;\r | |
1117 | return SCPE_OK;\r | |
1118 | }\r | |
1119 | \r | |
1120 | #else\r | |
1121 | \r | |
1122 | t_stat ts_boot (int32 unitno, DEVICE *dptr)\r | |
1123 | {\r | |
1124 | return SCPE_NOFNC;\r | |
1125 | }\r | |
1126 | #endif\r |