Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* pdp11_tq.c: TMSCP tape controller simulator\r |
2 | \r | |
3 | Copyright (c) 2002-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 | tq TQK50 tape controller\r | |
27 | \r | |
28 | 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread\r | |
29 | 16-Feb-06 RMS Revised for new magtape capacity checking\r | |
30 | 31-Oct-05 RMS Fixed address width for large files\r | |
31 | 16-Aug-05 RMS Fixed C++ declaration and cast problems\r | |
32 | 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)\r | |
33 | 30-Sep-04 RMS Revised Unibus interface\r | |
34 | 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley)\r | |
35 | 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath)\r | |
36 | 26-Mar-04 RMS Fixed warnings with -std=c99\r | |
37 | 25-Jan-04 RMS Revised for device debug support\r | |
38 | 19-May-03 RMS Revised for new conditional compilation scheme\r | |
39 | 25-Apr-03 RMS Revised for extended file support\r | |
40 | 28-Mar-03 RMS Added multiformat support\r | |
41 | 28-Feb-03 RMS Added variable controller, user-defined drive support\r | |
42 | 26-Feb-03 RMS Fixed bug in vector calculation for VAXen\r | |
43 | 22-Feb-03 RMS Fixed ordering bug in queue process\r | |
44 | Fixed flags table to allow MD_CSE everywhere\r | |
45 | 09-Jan-03 RMS Fixed bug in transfer end packet status\r | |
46 | 17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal)\r | |
47 | */\r | |
48 | \r | |
49 | #if defined (VM_PDP10) /* PDP10 version */\r | |
50 | #error "TQK50 not supported on PDP-10!"\r | |
51 | \r | |
52 | #elif defined (VM_VAX) /* VAX version */\r | |
53 | #include "vax_defs.h"\r | |
54 | #if (UNIBUS)\r | |
55 | #define INIT_TYPE TQ8_TYPE\r | |
56 | #define INIT_CAP TQ8_CAP\r | |
57 | #else\r | |
58 | #define INIT_TYPE TQ5_TYPE\r | |
59 | #define INIT_CAP TQ5_CAP\r | |
60 | #endif\r | |
61 | \r | |
62 | #else /* PDP-11 version */\r | |
63 | #include "pdp11_defs.h"\r | |
64 | #define INIT_TYPE TQ5_TYPE\r | |
65 | #define INIT_CAP TQ5_CAP\r | |
66 | extern int32 cpu_opt;\r | |
67 | #endif\r | |
68 | \r | |
69 | #include "pdp11_uqssp.h"\r | |
70 | #include "pdp11_mscp.h"\r | |
71 | #include "sim_tape.h"\r | |
72 | \r | |
73 | #define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */\r | |
74 | \r | |
75 | #define TQ_SH_MAX 24 /* max display wds */\r | |
76 | #define TQ_SH_PPL 8 /* wds per line */\r | |
77 | #define TQ_SH_DPL 4 /* desc per line */\r | |
78 | #define TQ_SH_RI 001 /* show rings */\r | |
79 | #define TQ_SH_FR 002 /* show free q */\r | |
80 | #define TQ_SH_RS 004 /* show resp q */\r | |
81 | #define TQ_SH_UN 010 /* show unit q's */\r | |
82 | #define TQ_SH_ALL 017 /* show all */\r | |
83 | \r | |
84 | #define TQ_CLASS 1 /* TQK50 class */\r | |
85 | #define TQ_DHTMO 0 /* def host timeout */\r | |
86 | #define TQ_DCTMO 120 /* def ctrl timeout */\r | |
87 | #define TQ_NUMDR 4 /* # drives */\r | |
88 | #define TQ_MAXFR (1 << 16) /* max xfer */\r | |
89 | \r | |
90 | #define UNIT_V_ONL (MTUF_V_UF + 0) /* online */\r | |
91 | #define UNIT_V_ATP (MTUF_V_UF + 1) /* attn pending */\r | |
92 | #define UNIT_V_SXC (MTUF_V_UF + 2) /* serious exc */\r | |
93 | #define UNIT_V_POL (MTUF_V_UF + 3) /* position lost */\r | |
94 | #define UNIT_V_TMK (MTUF_V_UF + 4) /* tape mark seen */\r | |
95 | #define UNIT_ONL (1 << UNIT_V_ONL)\r | |
96 | #define UNIT_ATP (1 << UNIT_V_ATP)\r | |
97 | #define UNIT_SXC (1 << UNIT_V_SXC)\r | |
98 | #define UNIT_POL (1 << UNIT_V_POL)\r | |
99 | #define UNIT_TMK (1 << UNIT_V_TMK)\r | |
100 | #define cpkt u3 /* current packet */\r | |
101 | #define pktq u4 /* packet queue */\r | |
102 | #define uf buf /* settable unit flags */\r | |
103 | #define objp wait /* object position */\r | |
104 | #define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0)\r | |
105 | \r | |
106 | #define CST_S1 0 /* init stage 1 */\r | |
107 | #define CST_S1_WR 1 /* stage 1 wrap */\r | |
108 | #define CST_S2 2 /* init stage 2 */\r | |
109 | #define CST_S3 3 /* init stage 3 */\r | |
110 | #define CST_S3_PPA 4 /* stage 3 sa wait */\r | |
111 | #define CST_S3_PPB 5 /* stage 3 ip wait */\r | |
112 | #define CST_S4 6 /* stage 4 */\r | |
113 | #define CST_UP 7 /* online */\r | |
114 | #define CST_DEAD 8 /* fatal error */\r | |
115 | \r | |
116 | #define tq_comm tq_rq.ba\r | |
117 | \r | |
118 | #define ERR 0 /* must be SCPE_OK! */\r | |
119 | #define OK 1\r | |
120 | \r | |
121 | #define CMF_IMM 0x10000 /* immediate */\r | |
122 | #define CMF_SEQ 0x20000 /* sequential */\r | |
123 | #define CMF_WR 0x40000 /* write */\r | |
124 | #define CMF_RW 0x80000 /* resp to GCS */\r | |
125 | \r | |
126 | /* Internal packet management */\r | |
127 | \r | |
128 | #define TQ_NPKTS 32 /* # packets (pwr of 2) */\r | |
129 | #define TQ_M_NPKTS (TQ_NPKTS - 1) /* mask */\r | |
130 | #define TQ_PKT_SIZE_W 32 /* payload size (wds) */\r | |
131 | #define TQ_PKT_SIZE (TQ_PKT_SIZE_W * sizeof (int16))\r | |
132 | \r | |
133 | struct tqpkt {\r | |
134 | int16 link; /* link to next */\r | |
135 | uint16 d[TQ_PKT_SIZE_W]; /* data */\r | |
136 | };\r | |
137 | \r | |
138 | /* Packet payload extraction and insertion */\r | |
139 | \r | |
140 | #define GETP(p,w,f) ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f)\r | |
141 | #define GETP32(p,w) (((uint32) tq_pkt[p].d[w]) | \\r | |
142 | (((uint32) tq_pkt[p].d[(w)+1]) << 16))\r | |
143 | #define PUTP32(p,w,x) tq_pkt[p].d[w] = (x) & 0xFFFF; \\r | |
144 | tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF\r | |
145 | \r | |
146 | /* Controller and device types - TQK50 must be swre rev 5 or later */\r | |
147 | \r | |
148 | #define TQ5_TYPE 0 /* TK50 */\r | |
149 | #define TQ5_UQPM 3 /* UQ port ID */\r | |
150 | #define TQ5_CMOD 9 /* ctrl ID */\r | |
151 | #define TQ5_UMOD 3 /* unit ID */\r | |
152 | #define TQ5_MED 0x6D68B032 /* media ID */\r | |
153 | #define TQ5_CREV ((1 << 8) | 5) /* ctrl revs */ \r | |
154 | #define TQ5_FREV 0 /* formatter revs */\r | |
155 | #define TQ5_UREV 0 /* unit revs */\r | |
156 | #define TQ5_CAP (94 * (1 << 20)) /* capacity */\r | |
157 | #define TQ5_FMT (TF_CTP|TF_CTP_LO) /* menu */\r | |
158 | \r | |
159 | #define TQ7_TYPE 1 /* TK70 */\r | |
160 | #define TQ7_UQPM 14 /* UQ port ID */\r | |
161 | #define TQ7_CMOD 14 /* ctrl ID */\r | |
162 | #define TQ7_UMOD 14 /* unit ID */\r | |
163 | #define TQ7_MED 0x6D68B046 /* media ID */\r | |
164 | #define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */ \r | |
165 | #define TQ7_FREV 0 /* formatter revs */\r | |
166 | #define TQ7_UREV 0 /* unit revs */\r | |
167 | #define TQ7_CAP (300 * (1 << 20)) /* capacity */\r | |
168 | #define TQ7_FMT (TF_CTP|TF_CTP_LO) /* menu */\r | |
169 | \r | |
170 | #define TQ8_TYPE 2 /* TU81 */\r | |
171 | #define TQ8_UQPM 5 /* UQ port ID */\r | |
172 | #define TQ8_CMOD 5 /* ctrl ID */\r | |
173 | #define TQ8_UMOD 2 /* unit ID */\r | |
174 | #define TQ8_MED 0x6D695051 /* media ID */\r | |
175 | #define TQ8_CREV ((1 << 8) | 5) /* ctrl revs */ \r | |
176 | #define TQ8_FREV 0 /* formatter revs */\r | |
177 | #define TQ8_UREV 0 /* unit revs */\r | |
178 | #define TQ8_CAP (180 * (1 << 20)) /* capacity */\r | |
179 | #define TQ8_FMT (TF_9TK|TF_9TK_GRP) /* menu */\r | |
180 | \r | |
181 | #define TQU_TYPE 3 /* TKuser defined */\r | |
182 | #define TQU_UQPM 3 /* UQ port ID */\r | |
183 | #define TQU_CMOD 9 /* ctrl ID */\r | |
184 | #define TQU_UMOD 3 /* unit ID */\r | |
185 | #define TQU_MED 0x6D68B032 /* media ID */\r | |
186 | #define TQU_CREV ((1 << 8) | 5) /* ctrl revs */ \r | |
187 | #define TQU_FREV 0 /* formatter revs */\r | |
188 | #define TQU_UREV 0 /* unit revs */\r | |
189 | #define TQU_CAP (94 * (1 << 20)) /* capacity */\r | |
190 | #define TQU_FMT (TF_CTP|TF_CTP_LO) /* menu */\r | |
191 | #define TQU_MINC 30 /* min cap MB */\r | |
192 | #define TQU_MAXC 2000 /* max cap MB */\r | |
193 | #define TQU_EMAXC 2000000000 /* ext max cap MB */\r | |
194 | \r | |
195 | #define TQ_DRV(d) \\r | |
196 | d##_UQPM, \\r | |
197 | d##_CMOD, d##_MED, d##_FMT, d##_CAP, \\r | |
198 | d##_UMOD, d##_CREV, d##_FREV, d##_UREV\r | |
199 | \r | |
200 | #define TEST_EOT(u) (sim_tape_eot (u))\r | |
201 | \r | |
202 | struct drvtyp {\r | |
203 | uint32 uqpm; /* UQ port model */\r | |
204 | uint32 cmod; /* ctrl model */\r | |
205 | uint32 med; /* MSCP media */\r | |
206 | uint32 fmt; /* flags */\r | |
207 | t_addr cap; /* capacity */\r | |
208 | uint32 umod; /* unit model */\r | |
209 | uint32 cver;\r | |
210 | uint32 fver;\r | |
211 | uint32 uver;\r | |
212 | char *name;\r | |
213 | };\r | |
214 | \r | |
215 | static struct drvtyp drv_tab[] = {\r | |
216 | { TQ_DRV (TQ5), "TK50" },\r | |
217 | { TQ_DRV (TQ7), "TK70" },\r | |
218 | { TQ_DRV (TQ8), "TU81" },\r | |
219 | { TQ_DRV (TQU), "TKUSER" },\r | |
220 | };\r | |
221 | \r | |
222 | /* Data */\r | |
223 | \r | |
224 | extern int32 int_req[IPL_HLVL];\r | |
225 | extern int32 tmr_poll, clk_tps;\r | |
226 | extern UNIT cpu_unit;\r | |
227 | extern FILE *sim_deb;\r | |
228 | extern uint32 sim_taddr_64;\r | |
229 | \r | |
230 | uint8 *tqxb = NULL; /* xfer buffer */\r | |
231 | uint32 tq_sa = 0; /* status, addr */\r | |
232 | uint32 tq_saw = 0; /* written data */\r | |
233 | uint32 tq_s1dat = 0; /* S1 data */\r | |
234 | uint32 tq_csta = 0; /* ctrl state */\r | |
235 | uint32 tq_perr = 0; /* last error */\r | |
236 | uint32 tq_cflgs = 0; /* ctrl flags */\r | |
237 | uint32 tq_prgi = 0; /* purge int */\r | |
238 | uint32 tq_pip = 0; /* poll in progress */\r | |
239 | struct uq_ring tq_cq = { 0 }; /* cmd ring */\r | |
240 | struct uq_ring tq_rq = { 0 }; /* rsp ring */\r | |
241 | struct tqpkt tq_pkt[TQ_NPKTS]; /* packet queue */\r | |
242 | int32 tq_freq = 0; /* free list */\r | |
243 | int32 tq_rspq = 0; /* resp list */\r | |
244 | uint32 tq_pbsy = 0; /* #busy pkts */\r | |
245 | uint32 tq_credits = 0; /* credits */\r | |
246 | uint32 tq_hat = 0; /* host timer */\r | |
247 | uint32 tq_htmo = TQ_DHTMO; /* host timeout */\r | |
248 | int32 tq_itime = 200; /* init time, except */\r | |
249 | int32 tq_itime4 = 10; /* stage 4 */\r | |
250 | int32 tq_qtime = 200; /* queue time */\r | |
251 | int32 tq_xtime = 500; /* transfer time */\r | |
252 | int32 tq_typ = INIT_TYPE; /* device type */\r | |
253 | \r | |
254 | /* Command table - legal modifiers (low 16b) and flags (high 16b) */\r | |
255 | \r | |
256 | static uint32 tq_cmf[64] = {\r | |
257 | 0, /* 0 */\r | |
258 | CMF_IMM, /* abort */\r | |
259 | CMF_IMM|MD_CSE, /* get cmd status */\r | |
260 | CMF_IMM|MD_CSE|MD_NXU, /* get unit status */\r | |
261 | CMF_IMM|MD_CSE, /* set ctrl char */\r | |
262 | 0, 0, 0, /* 5-7 */\r | |
263 | CMF_SEQ|MD_ACL|MD_CDL|MD_CSE|MD_EXA|MD_UNL, /* available */\r | |
264 | CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* online */\r | |
265 | CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* set unit char */\r | |
266 | CMF_IMM, /* define acc paths */\r | |
267 | 0, 0, 0, 0, /* 12-15 */\r | |
268 | CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* access */\r | |
269 | MD_SCH|MD_SEC|MD_SER,\r | |
270 | 0, /* 17 */\r | |
271 | CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase */\r | |
272 | CMF_SEQ|CMF_WR|MD_CDL|MD_CSE, /* flush */\r | |
273 | 0, 0, /* 20-21 */\r | |
274 | CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase gap */\r | |
275 | 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22-31 */\r | |
276 | CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* compare */\r | |
277 | MD_SCH|MD_SEC|MD_SER,\r | |
278 | CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|MD_CMP| /* read */\r | |
279 | MD_SCH|MD_SEC|MD_SER,\r | |
280 | CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */\r | |
281 | MD_CMP|MD_ERW|MD_SEC|MD_SER,\r | |
282 | 0, /* 35 */\r | |
283 | CMF_SEQ|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */\r | |
284 | CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */\r | |
285 | MD_REV|MD_RWD|MD_DLE|\r | |
286 | MD_SCH|MD_SEC|MD_SER,\r | |
287 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38-47 */\r | |
288 | 0, 0, 0, 0, 0, 0, 0, 0,\r | |
289 | 0, 0, 0, 0, 0, 0, 0, 0\r | |
290 | }; \r | |
291 | \r | |
292 | /* Forward references */\r | |
293 | \r | |
294 | DEVICE tq_dev;\r | |
295 | \r | |
296 | t_stat tq_rd (int32 *data, int32 PA, int32 access);\r | |
297 | t_stat tq_wr (int32 data, int32 PA, int32 access);\r | |
298 | t_stat tq_inta (void);\r | |
299 | t_stat tq_svc (UNIT *uptr);\r | |
300 | t_stat tq_tmrsvc (UNIT *uptr);\r | |
301 | t_stat tq_quesvc (UNIT *uptr);\r | |
302 | t_stat tq_reset (DEVICE *dptr);\r | |
303 | t_stat tq_attach (UNIT *uptr, char *cptr);\r | |
304 | t_stat tq_detach (UNIT *uptr);\r | |
305 | t_stat tq_boot (int32 unitno, DEVICE *dptr);\r | |
306 | t_stat tq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
307 | t_stat tq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
308 | t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
309 | t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
310 | t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
311 | t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
312 | \r | |
313 | t_bool tq_step4 (void);\r | |
314 | t_bool tq_mscp (int32 pkt, t_bool q);\r | |
315 | t_bool tq_abo (int32 pkt);\r | |
316 | t_bool tq_avl (int32 pkt);\r | |
317 | t_bool tq_erase (int32 pkt);\r | |
318 | t_bool tq_flu (int32 pkt);\r | |
319 | t_bool tq_gcs (int32 pkt);\r | |
320 | t_bool tq_gus (int32 pkt);\r | |
321 | t_bool tq_onl (int32 pkt);\r | |
322 | t_bool tq_pos (int32 pkt);\r | |
323 | t_bool tq_rw (int32 pkt);\r | |
324 | t_bool tq_scc (int32 pkt);\r | |
325 | t_bool tq_suc (int32 pkt);\r | |
326 | t_bool tq_wtm (int32 pkt);\r | |
327 | t_bool tq_plf (uint32 err);\r | |
328 | t_bool tq_dte (UNIT *uptr, uint32 err);\r | |
329 | t_bool tq_hbe (UNIT *uptr, uint32 ba);\r | |
330 | t_bool tq_una (UNIT *uptr);\r | |
331 | uint32 tq_map_status (UNIT *uptr, t_stat st);\r | |
332 | uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);\r | |
333 | uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped);\r | |
334 | uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc);\r | |
335 | uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec);\r | |
336 | uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped);\r | |
337 | uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc);\r | |
338 | t_bool tq_deqf (int32 *pkt);\r | |
339 | int32 tq_deqh (int32 *lh);\r | |
340 | void tq_enqh (int32 *lh, int32 pkt);\r | |
341 | void tq_enqt (int32 *lh, int32 pkt);\r | |
342 | t_bool tq_getpkt (int32 *pkt);\r | |
343 | t_bool tq_putpkt (int32 pkt, t_bool qt);\r | |
344 | t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc);\r | |
345 | t_bool tq_putdesc (struct uq_ring *ring, uint32 desc);\r | |
346 | int32 tq_mot_valid (UNIT *uptr, uint32 cmd);\r | |
347 | t_stat tq_mot_err (UNIT *uptr, uint32 rsiz);\r | |
348 | t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz);\r | |
349 | void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ);\r | |
350 | void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all);\r | |
351 | void tq_setf_unit (int32 pkt, UNIT *uptr);\r | |
352 | uint32 tq_efl (UNIT *uptr);\r | |
353 | void tq_init_int (void);\r | |
354 | void tq_ring_int (struct uq_ring *ring);\r | |
355 | t_bool tq_fatal (uint32 err);\r | |
356 | UNIT *tq_getucb (uint32 lu);\r | |
357 | \r | |
358 | /* TQ data structures\r | |
359 | \r | |
360 | tq_dev TQ device descriptor\r | |
361 | tq_unit TQ unit list\r | |
362 | tq_reg TQ register list\r | |
363 | tq_mod TQ modifier list\r | |
364 | */\r | |
365 | \r | |
366 | DIB tq_dib = {\r | |
367 | IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr,\r | |
368 | 1, IVCL (TQ), 0, { &tq_inta }\r | |
369 | };\r | |
370 | \r | |
371 | UNIT tq_unit[] = {\r | |
372 | { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r | |
373 | { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r | |
374 | { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r | |
375 | { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), INIT_CAP },\r | |
376 | { UDATA (&tq_tmrsvc, UNIT_DIS, 0) },\r | |
377 | { UDATA (&tq_quesvc, UNIT_DIS, 0) }\r | |
378 | };\r | |
379 | \r | |
380 | #define TQ_TIMER (TQ_NUMDR)\r | |
381 | #define TQ_QUEUE (TQ_TIMER + 1)\r | |
382 | \r | |
383 | REG tq_reg[] = {\r | |
384 | { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) },\r | |
385 | { GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) },\r | |
386 | { GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) },\r | |
387 | { GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) },\r | |
388 | { GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ },\r | |
389 | { GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) },\r | |
390 | { GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) },\r | |
391 | { GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ },\r | |
392 | { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) },\r | |
393 | { DRDATA (FREE, tq_freq, 5) },\r | |
394 | { DRDATA (RESP, tq_rspq, 5) },\r | |
395 | { DRDATA (PBSY, tq_pbsy, 5) },\r | |
396 | { GRDATA (CFLGS, tq_cflgs, DEV_RDX, 16, 0) },\r | |
397 | { GRDATA (CSTA, tq_csta, DEV_RDX, 4, 0) },\r | |
398 | { GRDATA (PERR, tq_perr, DEV_RDX, 9, 0) },\r | |
399 | { DRDATA (CRED, tq_credits, 5) },\r | |
400 | { DRDATA (HAT, tq_hat, 17) },\r | |
401 | { DRDATA (HTMO, tq_htmo, 17) },\r | |
402 | { URDATA (CPKT, tq_unit[0].cpkt, 10, 5, 0, TQ_NUMDR, 0) },\r | |
403 | { URDATA (PKTQ, tq_unit[0].pktq, 10, 5, 0, TQ_NUMDR, 0) },\r | |
404 | { URDATA (UFLG, tq_unit[0].uf, DEV_RDX, 16, 0, TQ_NUMDR, 0) },\r | |
405 | { URDATA (POS, tq_unit[0].pos, 10, T_ADDR_W, 0, TQ_NUMDR, 0) },\r | |
406 | { URDATA (OBJP, tq_unit[0].objp, 10, 32, 0, TQ_NUMDR, 0) },\r | |
407 | { FLDATA (PRGI, tq_prgi, 0), REG_HIDDEN },\r | |
408 | { FLDATA (PIP, tq_pip, 0), REG_HIDDEN },\r | |
409 | { FLDATA (INT, IREQ (TQ), INT_V_TQ) },\r | |
410 | { DRDATA (ITIME, tq_itime, 24), PV_LEFT + REG_NZ },\r | |
411 | { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ },\r | |
412 | { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ },\r | |
413 | { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ },\r | |
414 | { BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) },\r | |
415 | { DRDATA (DEVTYPE, tq_typ, 2), REG_HRO },\r | |
416 | { DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO },\r | |
417 | { GRDATA (DEVADDR, tq_dib.ba, DEV_RDX, 32, 0), REG_HRO },\r | |
418 | { GRDATA (DEVVEC, tq_dib.vec, DEV_RDX, 16, 0), REG_HRO },\r | |
419 | { NULL }\r | |
420 | };\r | |
421 | \r | |
422 | MTAB tq_mod[] = {\r | |
423 | { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r | |
424 | { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },\r | |
425 | { MTAB_XTD | MTAB_VDV, TQ5_TYPE, NULL, "TK50",\r | |
426 | &tq_set_type, NULL, NULL },\r | |
427 | { MTAB_XTD | MTAB_VDV, TQ7_TYPE, NULL, "TK70",\r | |
428 | &tq_set_type, NULL, NULL },\r | |
429 | { MTAB_XTD | MTAB_VDV, TQ8_TYPE, NULL, "TU81",\r | |
430 | &tq_set_type, NULL, NULL },\r | |
431 | { MTAB_XTD | MTAB_VDV, TQU_TYPE, NULL, "TKUSER",\r | |
432 | &tq_set_type, NULL, NULL },\r | |
433 | { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,\r | |
434 | NULL, &tq_show_type, NULL },\r | |
435 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RI, "RINGS", NULL,\r | |
436 | NULL, &tq_show_ctrl, NULL },\r | |
437 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_FR, "FREEQ", NULL,\r | |
438 | NULL, &tq_show_ctrl, NULL },\r | |
439 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RS, "RESPQ", NULL,\r | |
440 | NULL, &tq_show_ctrl, NULL },\r | |
441 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_UN, "UNITQ", NULL,\r | |
442 | NULL, &tq_show_ctrl, NULL },\r | |
443 | { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_ALL, "ALL", NULL,\r | |
444 | NULL, &tq_show_ctrl, NULL },\r | |
445 | { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL,\r | |
446 | NULL, &tq_show_unitq, NULL },\r | |
447 | { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",\r | |
448 | &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },\r | |
449 | #if defined (VM_PDP11)\r | |
450 | { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",\r | |
451 | &set_addr, &show_addr, NULL },\r | |
452 | #else\r | |
453 | { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,\r | |
454 | NULL, &show_addr, NULL },\r | |
455 | #endif\r | |
456 | { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,\r | |
457 | NULL, &show_vec, NULL },\r | |
458 | { 0 }\r | |
459 | };\r | |
460 | \r | |
461 | DEVICE tq_dev = {\r | |
462 | "TQ", tq_unit, tq_reg, tq_mod,\r | |
463 | TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8,\r | |
464 | NULL, NULL, &tq_reset,\r | |
465 | &tq_boot, &tq_attach, &tq_detach,\r | |
466 | &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG\r | |
467 | };\r | |
468 | \r | |
469 | /* I/O dispatch routines, I/O addresses 17772150 - 17772152\r | |
470 | \r | |
471 | 17772150 IP read/write\r | |
472 | 17772152 SA read/write\r | |
473 | */\r | |
474 | \r | |
475 | t_stat tq_rd (int32 *data, int32 PA, int32 access)\r | |
476 | {\r | |
477 | switch ((PA >> 1) & 01) { /* decode PA<1> */\r | |
478 | case 0: /* IP */\r | |
479 | *data = 0; /* reads zero */\r | |
480 | if (tq_csta == CST_S3_PPB) tq_step4 (); /* waiting for poll? */\r | |
481 | else if (tq_csta == CST_UP) { /* if up */\r | |
482 | tq_pip = 1; /* poll host */\r | |
483 | sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);\r | |
484 | }\r | |
485 | break;\r | |
486 | \r | |
487 | case 1: /* SA */\r | |
488 | *data = tq_sa;\r | |
489 | break;\r | |
490 | }\r | |
491 | \r | |
492 | return SCPE_OK;\r | |
493 | }\r | |
494 | \r | |
495 | t_stat tq_wr (int32 data, int32 PA, int32 access)\r | |
496 | {\r | |
497 | switch ((PA >> 1) & 01) { /* decode PA<1> */\r | |
498 | \r | |
499 | case 0: /* IP */\r | |
500 | tq_reset (&tq_dev); /* init device */\r | |
501 | if (DEBUG_PRS (tq_dev)) fprintf (sim_deb,\r | |
502 | ">>TQ: initialization started, time=%.0f\n", sim_gtime ());\r | |
503 | break;\r | |
504 | \r | |
505 | case 1: /* SA */\r | |
506 | tq_saw = data;\r | |
507 | if (tq_csta < CST_S4) /* stages 1-3 */\r | |
508 | sim_activate (&tq_unit[TQ_QUEUE], tq_itime);\r | |
509 | else if (tq_csta == CST_S4) /* stage 4 (fast) */\r | |
510 | sim_activate (&tq_unit[TQ_QUEUE], tq_itime4);\r | |
511 | break;\r | |
512 | }\r | |
513 | \r | |
514 | return SCPE_OK;\r | |
515 | }\r | |
516 | \r | |
517 | /* Transition to step 4 - init communications region */\r | |
518 | \r | |
519 | t_bool tq_step4 (void)\r | |
520 | {\r | |
521 | int32 i, lnt;\r | |
522 | uint32 base;\r | |
523 | uint16 zero[SA_COMM_MAX >> 1];\r | |
524 | \r | |
525 | tq_rq.ioff = SA_COMM_RI; /* set intr offset */\r | |
526 | tq_rq.ba = tq_comm; /* set rsp q base */\r | |
527 | tq_rq.lnt = SA_S1H_RQ (tq_s1dat) << 2; /* get resp q len */\r | |
528 | tq_cq.ioff = SA_COMM_CI; /* set intr offset */\r | |
529 | tq_cq.ba = tq_comm + tq_rq.lnt; /* set cmd q base */\r | |
530 | tq_cq.lnt = SA_S1H_CQ (tq_s1dat) << 2; /* get cmd q len */\r | |
531 | tq_cq.idx = tq_rq.idx = 0; /* clear q idx's */\r | |
532 | if (tq_prgi) base = tq_comm + SA_COMM_QQ;\r | |
533 | else base = tq_comm + SA_COMM_CI;\r | |
534 | lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */\r | |
535 | if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */\r | |
536 | for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */\r | |
537 | if (Map_WriteW (base, lnt, zero)) /* zero comm area */\r | |
538 | return tq_fatal (PE_QWE); /* error? */\r | |
539 | tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */\r | |
540 | ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER);\r | |
541 | tq_csta = CST_S4; /* set step 4 */\r | |
542 | tq_init_int (); /* poke host */\r | |
543 | return OK;\r | |
544 | }\r | |
545 | \r | |
546 | /* Queue service - invoked when any of the queues (host queue, unit\r | |
547 | queues, response queue) require servicing. Also invoked during\r | |
548 | initialization to provide some delay to the next step.\r | |
549 | \r | |
550 | Process at most one item off each unit queue\r | |
551 | If the unit queues were empty, process at most one item off the host queue\r | |
552 | Process at most one item off the response queue\r | |
553 | \r | |
554 | If all queues are idle, terminate thread\r | |
555 | */\r | |
556 | \r | |
557 | t_stat tq_quesvc (UNIT *uptr)\r | |
558 | {\r | |
559 | int32 i, cnid;\r | |
560 | int32 pkt = 0;\r | |
561 | UNIT *nuptr;\r | |
562 | \r | |
563 | if (tq_csta < CST_UP) { /* still init? */\r | |
564 | switch (tq_csta) { /* controller state? */\r | |
565 | \r | |
566 | case CST_S1: /* need S1 reply */\r | |
567 | if (tq_saw & SA_S1H_VL) { /* valid? */\r | |
568 | if (tq_saw & SA_S1H_WR) { /* wrap? */\r | |
569 | tq_sa = tq_saw; /* echo data */\r | |
570 | tq_csta = CST_S1_WR; /* endless loop */\r | |
571 | }\r | |
572 | else {\r | |
573 | tq_s1dat = tq_saw; /* save data */\r | |
574 | tq_dib.vec = (tq_s1dat & SA_S1H_VEC) << 2; /* get vector */\r | |
575 | if (tq_dib.vec) tq_dib.vec = tq_dib.vec + VEC_Q; /* if nz, bias */\r | |
576 | tq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (tq_s1dat);\r | |
577 | tq_csta = CST_S2; /* now in step 2 */\r | |
578 | tq_init_int (); /* intr if req */\r | |
579 | }\r | |
580 | } /* end if valid */\r | |
581 | break;\r | |
582 | \r | |
583 | case CST_S1_WR: /* wrap mode */\r | |
584 | tq_sa = tq_saw; /* echo data */\r | |
585 | break;\r | |
586 | \r | |
587 | case CST_S2: /* need S2 reply */\r | |
588 | tq_comm = tq_saw & SA_S2H_CLO; /* get low addr */\r | |
589 | tq_prgi = tq_saw & SA_S2H_PI; /* get purge int */\r | |
590 | tq_sa = SA_S3 | SA_S3C_EC (tq_s1dat);\r | |
591 | tq_csta = CST_S3; /* now in step 3 */\r | |
592 | tq_init_int (); /* intr if req */\r | |
593 | break;\r | |
594 | \r | |
595 | case CST_S3: /* need S3 reply */\r | |
596 | tq_comm = ((tq_saw & SA_S3H_CHI) << 16) | tq_comm;\r | |
597 | if (tq_saw & SA_S3H_PP) { /* purge/poll test? */\r | |
598 | tq_sa = 0; /* put 0 */\r | |
599 | tq_csta = CST_S3_PPA; /* wait for 0 write */\r | |
600 | }\r | |
601 | else tq_step4 (); /* send step 4 */\r | |
602 | break;\r | |
603 | \r | |
604 | case CST_S3_PPA: /* need purge test */\r | |
605 | if (tq_saw) tq_fatal (PE_PPF); /* data not zero? */\r | |
606 | else tq_csta = CST_S3_PPB; /* wait for poll */\r | |
607 | break;\r | |
608 | \r | |
609 | case CST_S4: /* need S4 reply */\r | |
610 | if (tq_saw & SA_S4H_GO) { /* go set? */\r | |
611 | if (DEBUG_PRS (tq_dev)) fprintf (sim_deb,\r | |
612 | ">>TQ: initialization complete\n");\r | |
613 | tq_csta = CST_UP; /* we're up */\r | |
614 | tq_sa = 0; /* clear SA */\r | |
615 | sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps);\r | |
616 | if ((tq_saw & SA_S4H_LF) && tq_perr) tq_plf (tq_perr);\r | |
617 | tq_perr = 0;\r | |
618 | }\r | |
619 | break;\r | |
620 | } /* end switch */ \r | |
621 | return SCPE_OK;\r | |
622 | } /* end if */\r | |
623 | \r | |
624 | for (i = 0; i < TQ_NUMDR; i++) { /* chk unit q's */\r | |
625 | nuptr = tq_dev.units + i; /* ptr to unit */\r | |
626 | if (nuptr->cpkt || (nuptr->pktq == 0)) continue;\r | |
627 | pkt = tq_deqh (&nuptr->pktq); /* get top of q */\r | |
628 | if (!tq_mscp (pkt, FALSE)) return SCPE_OK; /* process */\r | |
629 | }\r | |
630 | if ((pkt == 0) && tq_pip) { /* polling? */\r | |
631 | if (!tq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */\r | |
632 | if (pkt) { /* got one? */\r | |
633 | if (DEBUG_PRS (tq_dev)) {\r | |
634 | UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);\r | |
635 | fprintf (sim_deb, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ",\r | |
636 | tq_pkt[pkt].d[CMD_OPC], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]);\r | |
637 | fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X",\r | |
638 | tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],\r | |
639 | tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]);\r | |
640 | if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);\r | |
641 | else fprintf (sim_deb, "\n");\r | |
642 | fflush (sim_deb);\r | |
643 | }\r | |
644 | if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */\r | |
645 | return tq_fatal (PE_PIE); /* no, term thread */\r | |
646 | cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */\r | |
647 | if (cnid == UQ_CID_TMSCP) { /* TMSCP packet? */\r | |
648 | if (!tq_mscp (pkt, TRUE)) return SCPE_OK; /* proc, q non-seq */\r | |
649 | }\r | |
650 | else if (cnid == UQ_CID_DUP) { /* DUP packet? */\r | |
651 | tq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ);\r | |
652 | if (!tq_putpkt (pkt, TRUE)) return SCPE_OK; /* ill cmd */\r | |
653 | }\r | |
654 | else return tq_fatal (PE_ICI); /* no, term thread */\r | |
655 | } /* end if pkt */\r | |
656 | else tq_pip = 0; /* discontinue poll */\r | |
657 | } /* end if pip */\r | |
658 | if (tq_rspq) { /* resp q? */\r | |
659 | pkt = tq_deqh (&tq_rspq); /* get top of q */\r | |
660 | if (!tq_putpkt (pkt, FALSE)) return SCPE_OK; /* send to host */\r | |
661 | } /* end if resp q */\r | |
662 | if (pkt) sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* more to do? */\r | |
663 | return SCPE_OK; /* done */\r | |
664 | }\r | |
665 | \r | |
666 | /* Clock service (roughly once per second) */\r | |
667 | \r | |
668 | t_stat tq_tmrsvc (UNIT *uptr)\r | |
669 | {\r | |
670 | int32 i;\r | |
671 | UNIT *nuptr;\r | |
672 | \r | |
673 | sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */\r | |
674 | for (i = 0; i < TQ_NUMDR; i++) { /* poll */\r | |
675 | nuptr = tq_dev.units + i;\r | |
676 | if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */\r | |
677 | (nuptr->flags & UNIT_ATT) && /* still online? */\r | |
678 | (tq_cflgs & CF_ATN)) { /* wanted? */\r | |
679 | if (!tq_una (nuptr)) return SCPE_OK;\r | |
680 | }\r | |
681 | nuptr->flags = nuptr->flags & ~UNIT_ATP;\r | |
682 | }\r | |
683 | if ((tq_hat > 0) && (--tq_hat == 0)) /* host timeout? */\r | |
684 | tq_fatal (PE_HAT); /* fatal err */ \r | |
685 | return SCPE_OK;\r | |
686 | }\r | |
687 | \r | |
688 | /* MSCP packet handling */\r | |
689 | \r | |
690 | t_bool tq_mscp (int32 pkt, t_bool q)\r | |
691 | {\r | |
692 | uint32 sts;\r | |
693 | uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* command */\r | |
694 | uint32 flg = GETP (pkt, CMD_OPC, FLG); /* flags */\r | |
695 | uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */\r | |
696 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
697 | UNIT *uptr;\r | |
698 | \r | |
699 | if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */\r | |
700 | cmd = OP_END; /* set end op */\r | |
701 | sts = ST_CMD | I_OPCD; /* ill op */\r | |
702 | }\r | |
703 | else if (flg) { /* flags? */\r | |
704 | cmd = cmd | OP_END; /* set end flag */\r | |
705 | sts = ST_CMD | I_FLAG; /* ill flags */\r | |
706 | }\r | |
707 | else if (mdf & ~tq_cmf[cmd]) { /* invalid mod? */\r | |
708 | cmd = cmd | OP_END; /* set end flag */\r | |
709 | sts = ST_CMD | I_MODF; /* ill mods */\r | |
710 | }\r | |
711 | else { /* valid cmd */\r | |
712 | if (uptr = tq_getucb (lu)) { /* valid unit? */\r | |
713 | if (q && (tq_cmf[cmd] & CMF_SEQ) && /* queueing, seq, */\r | |
714 | (uptr->cpkt || uptr->pktq)) { /* and active? */\r | |
715 | tq_enqt (&uptr->pktq, pkt); /* do later */\r | |
716 | return OK;\r | |
717 | }\r | |
718 | /* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */\r | |
719 | /* uptr->flags = uptr->flags & ~UNIT_CDL; */\r | |
720 | if (tq_cmf[cmd] & MD_CSE) /* clr ser exc? */\r | |
721 | uptr->flags = uptr->flags & ~UNIT_SXC;\r | |
722 | }\r | |
723 | switch (cmd) {\r | |
724 | \r | |
725 | case OP_ABO: /* abort */\r | |
726 | return tq_abo (pkt);\r | |
727 | \r | |
728 | case OP_AVL: /* avail */\r | |
729 | return tq_avl (pkt);\r | |
730 | \r | |
731 | case OP_GCS: /* get cmd status */\r | |
732 | return tq_gcs (pkt);\r | |
733 | \r | |
734 | case OP_GUS: /* get unit status */\r | |
735 | return tq_gus (pkt);\r | |
736 | \r | |
737 | case OP_ONL: /* online */\r | |
738 | return tq_onl (pkt);\r | |
739 | \r | |
740 | case OP_SCC: /* set ctrl char */\r | |
741 | return tq_scc (pkt);\r | |
742 | \r | |
743 | case OP_SUC: /* set unit char */\r | |
744 | return tq_suc (pkt);\r | |
745 | \r | |
746 | case OP_ERS: /* erase */\r | |
747 | case OP_ERG: /* erase gap */\r | |
748 | return tq_erase (pkt);\r | |
749 | \r | |
750 | case OP_FLU: /* flush */\r | |
751 | return tq_flu (pkt);\r | |
752 | \r | |
753 | case OP_POS: /* position */\r | |
754 | return tq_pos (pkt);\r | |
755 | \r | |
756 | case OP_WTM: /* write tape mark */\r | |
757 | return tq_wtm (pkt);\r | |
758 | \r | |
759 | case OP_ACC: /* access */\r | |
760 | case OP_CMP: /* compare */\r | |
761 | case OP_RD: /* read */\r | |
762 | case OP_WR: /* write */\r | |
763 | return tq_rw (pkt);\r | |
764 | \r | |
765 | case OP_DAP:\r | |
766 | cmd = cmd | OP_END; /* set end flag */\r | |
767 | sts = ST_SUC; /* success */\r | |
768 | break;\r | |
769 | \r | |
770 | default:\r | |
771 | cmd = OP_END; /* set end op */\r | |
772 | sts = ST_CMD | I_OPCD; /* ill op */\r | |
773 | break;\r | |
774 | } /* end switch */\r | |
775 | } /* end else */\r | |
776 | tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ);\r | |
777 | return tq_putpkt (pkt, TRUE);\r | |
778 | }\r | |
779 | \r | |
780 | /* Abort a command - 1st parameter is ref # of cmd to abort */\r | |
781 | \r | |
782 | t_bool tq_abo (int32 pkt)\r | |
783 | {\r | |
784 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
785 | uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */\r | |
786 | int32 tpkt, prv;\r | |
787 | UNIT *uptr;\r | |
788 | \r | |
789 | tpkt = 0; /* set no mtch */\r | |
790 | if (uptr = tq_getucb (lu)) { /* get unit */\r | |
791 | if (uptr->cpkt && /* curr pkt? */\r | |
792 | (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */\r | |
793 | tpkt = uptr->cpkt; /* save match */\r | |
794 | uptr->cpkt = 0; /* gonzo */\r | |
795 | sim_cancel (uptr); /* cancel unit */\r | |
796 | sim_activate (&tq_unit[TQ_QUEUE], tq_qtime);\r | |
797 | }\r | |
798 | else if (uptr->pktq && /* head of q? */\r | |
799 | (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */\r | |
800 | tpkt = uptr->pktq; /* save match */\r | |
801 | uptr->pktq = tq_pkt[tpkt].link; /* unlink */\r | |
802 | }\r | |
803 | else if (prv = uptr->pktq) { /* srch pkt q */\r | |
804 | while (tpkt = tq_pkt[prv].link) { /* walk list */\r | |
805 | if (GETP32 (tpkt, RSP_REFL) == ref) { /* match ref? */\r | |
806 | tq_pkt[prv].link = tq_pkt[tpkt].link; /* unlink */\r | |
807 | break;\r | |
808 | }\r | |
809 | }\r | |
810 | }\r | |
811 | if (tpkt) { /* found target? */\r | |
812 | uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */\r | |
813 | tq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ);\r | |
814 | if (!tq_putpkt (tpkt, TRUE)) return ERR;\r | |
815 | }\r | |
816 | } /* end if unit */\r | |
817 | tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ);\r | |
818 | return tq_putpkt (pkt, TRUE);\r | |
819 | }\r | |
820 | \r | |
821 | /* Unit available - set unit status to available\r | |
822 | Deferred if q'd cmds, bypassed if ser exc */\r | |
823 | \r | |
824 | t_bool tq_avl (int32 pkt)\r | |
825 | {\r | |
826 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
827 | uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */\r | |
828 | uint32 sts;\r | |
829 | UNIT *uptr;\r | |
830 | \r | |
831 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
832 | if (uptr->flags & UNIT_SXC) sts = ST_SXC; /* ser exc pending? */\r | |
833 | else {\r | |
834 | uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_TMK | UNIT_POL);\r | |
835 | sim_tape_rewind (uptr); /* rewind */\r | |
836 | uptr->uf = uptr->objp = 0; /* clr flags */\r | |
837 | if (uptr->flags & UNIT_ATT) { /* attached? */\r | |
838 | sts = ST_SUC; /* success */\r | |
839 | if (mdf & MD_UNL) tq_detach (uptr); /* unload? */\r | |
840 | }\r | |
841 | else sts = ST_OFL | SB_OFL_NV; /* no, offline */\r | |
842 | }\r | |
843 | }\r | |
844 | else sts = ST_OFL; /* offline */\r | |
845 | tq_putr (pkt, OP_AVL | OP_END, tq_efl (uptr), sts, AVL_LNT, UQ_TYP_SEQ);\r | |
846 | return tq_putpkt (pkt, TRUE);\r | |
847 | }\r | |
848 | \r | |
849 | /* Get command status - only interested in active xfr cmd */\r | |
850 | \r | |
851 | t_bool tq_gcs (int32 pkt)\r | |
852 | {\r | |
853 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
854 | uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */\r | |
855 | int32 tpkt;\r | |
856 | UNIT *uptr;\r | |
857 | \r | |
858 | if ((uptr = tq_getucb (lu)) && /* valid lu? */\r | |
859 | (tpkt = uptr->cpkt) && /* queued pkt? */\r | |
860 | (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */\r | |
861 | (tq_cmf[GETP (tpkt, CMD_OPC, OPC)] & CMF_RW)) { /* rd/wr cmd? */\r | |
862 | tq_pkt[pkt].d[GCS_STSL] = tq_pkt[tpkt].d[RW_BCL];\r | |
863 | tq_pkt[pkt].d[GCS_STSH] = tq_pkt[tpkt].d[RW_BCH];\r | |
864 | }\r | |
865 | else tq_pkt[pkt].d[GCS_STSL] = tq_pkt[pkt].d[GCS_STSH] = 0;\r | |
866 | tq_putr (pkt, OP_GCS | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ);\r | |
867 | return tq_putpkt (pkt, TRUE);\r | |
868 | }\r | |
869 | \r | |
870 | /* Get unit status */\r | |
871 | \r | |
872 | t_bool tq_gus (int32 pkt)\r | |
873 | {\r | |
874 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
875 | uint32 sts;\r | |
876 | UNIT *uptr;\r | |
877 | \r | |
878 | if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */\r | |
879 | if (lu >= TQ_NUMDR) { /* end of range? */\r | |
880 | lu = 0; /* reset to 0 */\r | |
881 | tq_pkt[pkt].d[RSP_UN] = lu;\r | |
882 | }\r | |
883 | }\r | |
884 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
885 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r | |
886 | sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r | |
887 | else if (uptr->flags & UNIT_ONL) sts = ST_SUC; /* online */\r | |
888 | else sts = ST_AVL; /* avail */\r | |
889 | tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */\r | |
890 | tq_pkt[pkt].d[GUS_MENU] = drv_tab[tq_typ].fmt; /* format menu */\r | |
891 | tq_pkt[pkt].d[GUS_CAP] = 0; /* free capacity */\r | |
892 | tq_pkt[pkt].d[GUS_FVER] = drv_tab[tq_typ].fver; /* formatter version */\r | |
893 | tq_pkt[pkt].d[GUS_UVER] = drv_tab[tq_typ].uver; /* unit version */\r | |
894 | }\r | |
895 | else sts = ST_OFL; /* offline */\r | |
896 | tq_putr (pkt, OP_GUS | OP_END, tq_efl (uptr), sts, GUS_LNT_T, UQ_TYP_SEQ);\r | |
897 | return tq_putpkt (pkt, TRUE);\r | |
898 | }\r | |
899 | \r | |
900 | /* Unit online - deferred if q'd commands */\r | |
901 | \r | |
902 | t_bool tq_onl (int32 pkt)\r | |
903 | {\r | |
904 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
905 | uint32 sts;\r | |
906 | UNIT *uptr;\r | |
907 | \r | |
908 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
909 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r | |
910 | sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r | |
911 | else if (uptr->flags & UNIT_ONL) /* already online? */\r | |
912 | sts = ST_SUC | SB_SUC_ON;\r | |
913 | else {\r | |
914 | sts = ST_SUC; /* mark online */\r | |
915 | sim_tape_rewind (uptr); /* rewind */\r | |
916 | uptr->objp = 0; /* clear flags */\r | |
917 | uptr->flags = (uptr->flags | UNIT_ONL) &\r | |
918 | ~(UNIT_TMK | UNIT_POL); /* onl, pos ok */\r | |
919 | tq_setf_unit (pkt, uptr); /* hack flags */\r | |
920 | }\r | |
921 | tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */\r | |
922 | }\r | |
923 | else sts = ST_OFL; /* offline */\r | |
924 | tq_putr (pkt, OP_ONL | OP_END, tq_efl (uptr), sts, ONL_LNT, UQ_TYP_SEQ);\r | |
925 | return tq_putpkt (pkt, TRUE);\r | |
926 | }\r | |
927 | \r | |
928 | /* Set controller characteristics */\r | |
929 | \r | |
930 | t_bool tq_scc (int32 pkt)\r | |
931 | {\r | |
932 | if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */\r | |
933 | tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ);\r | |
934 | else {\r | |
935 | tq_cflgs = (tq_cflgs & CF_RPL) | /* hack ctrl flgs */\r | |
936 | tq_pkt[pkt].d[SCC_CFL];\r | |
937 | if (tq_htmo = tq_pkt[pkt].d[SCC_TMO]) /* set timeout */\r | |
938 | tq_htmo = tq_htmo + 2; /* if nz, round up */\r | |
939 | tq_pkt[pkt].d[SCC_CFL] = tq_cflgs; /* return flags */\r | |
940 | tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO; /* ctrl timeout */\r | |
941 | tq_pkt[pkt].d[SCC_VER] = drv_tab[tq_typ].cver; /* ctrl version */\r | |
942 | tq_pkt[pkt].d[SCC_CIDA] = 0; /* ctrl ID */\r | |
943 | tq_pkt[pkt].d[SCC_CIDB] = 0;\r | |
944 | tq_pkt[pkt].d[SCC_CIDC] = 0;\r | |
945 | tq_pkt[pkt].d[SCC_CIDD] = (TQ_CLASS << SCC_CIDD_V_CLS) |\r | |
946 | (drv_tab[tq_typ].cmod << SCC_CIDD_V_MOD);\r | |
947 | PUTP32 (pkt, SCC_MBCL, TQ_MAXFR); /* max bc */\r | |
948 | tq_putr (pkt, OP_SCC | OP_END, 0, ST_SUC, SCC_LNT, UQ_TYP_SEQ);\r | |
949 | }\r | |
950 | return tq_putpkt (pkt, TRUE);\r | |
951 | }\r | |
952 | \r | |
953 | /* Set unit characteristics - defer if q'd commands */\r | |
954 | \r | |
955 | t_bool tq_suc (int32 pkt)\r | |
956 | {\r | |
957 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
958 | uint32 sts;\r | |
959 | UNIT *uptr;\r | |
960 | \r | |
961 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
962 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r | |
963 | sts = ST_OFL | SB_OFL_NV; /* offl no vol */\r | |
964 | else {\r | |
965 | sts = ST_SUC; /* avail or onl */\r | |
966 | tq_setf_unit (pkt, uptr); /* hack flags */\r | |
967 | }\r | |
968 | tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */\r | |
969 | }\r | |
970 | else sts = ST_OFL; /* offline */\r | |
971 | tq_putr (pkt, OP_SUC | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ);\r | |
972 | return tq_putpkt (pkt, TRUE);\r | |
973 | }\r | |
974 | \r | |
975 | /* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */\r | |
976 | \r | |
977 | t_bool tq_flu (int32 pkt)\r | |
978 | {\r | |
979 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
980 | uint32 sts;\r | |
981 | UNIT *uptr;\r | |
982 | \r | |
983 | if (uptr = tq_getucb (lu)) /* unit exist? */\r | |
984 | sts = tq_mot_valid (uptr, OP_FLU); /* validate req */\r | |
985 | else sts = ST_OFL; /* offline */\r | |
986 | tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ);\r | |
987 | return tq_putpkt (pkt, TRUE);\r | |
988 | }\r | |
989 | \r | |
990 | /* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */\r | |
991 | \r | |
992 | t_bool tq_erase (int32 pkt)\r | |
993 | {\r | |
994 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
995 | uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */\r | |
996 | uint32 sts;\r | |
997 | UNIT *uptr;\r | |
998 | \r | |
999 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
1000 | sts = tq_mot_valid (uptr, cmd); /* validity checks */\r | |
1001 | if (sts == ST_SUC) { /* ok? */\r | |
1002 | uptr->cpkt = pkt; /* op in progress */\r | |
1003 | sim_activate (uptr, tq_xtime); /* activate */\r | |
1004 | return OK; /* done */\r | |
1005 | }\r | |
1006 | }\r | |
1007 | else sts = ST_OFL; /* offline */\r | |
1008 | tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, ERS_LNT, UQ_TYP_SEQ);\r | |
1009 | return tq_putpkt (pkt, TRUE);\r | |
1010 | }\r | |
1011 | \r | |
1012 | /* Write tape mark - deferred if q'd cmds, bypassed if ser exc */\r | |
1013 | \r | |
1014 | t_bool tq_wtm (int32 pkt)\r | |
1015 | {\r | |
1016 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
1017 | uint32 sts, objp = 0;\r | |
1018 | UNIT *uptr;\r | |
1019 | \r | |
1020 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
1021 | objp = uptr->objp; /* position op */\r | |
1022 | sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */\r | |
1023 | if (sts == ST_SUC) { /* ok? */\r | |
1024 | uptr->cpkt = pkt; /* op in progress */\r | |
1025 | sim_activate (uptr, tq_xtime); /* activate */\r | |
1026 | return OK; /* done */\r | |
1027 | }\r | |
1028 | }\r | |
1029 | else sts = ST_OFL; /* offline */\r | |
1030 | PUTP32 (pkt, WTM_POSL, objp); /* set obj pos */\r | |
1031 | tq_putr (pkt, OP_WTM | OP_END, tq_efl (uptr), sts, WTM_LNT, UQ_TYP_SEQ);\r | |
1032 | return tq_putpkt (pkt, TRUE);\r | |
1033 | }\r | |
1034 | \r | |
1035 | /* Position - deferred if q'd cmds, bypassed if ser exc */\r | |
1036 | \r | |
1037 | t_bool tq_pos (int32 pkt)\r | |
1038 | {\r | |
1039 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
1040 | uint32 sts, objp = 0;\r | |
1041 | UNIT *uptr;\r | |
1042 | \r | |
1043 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
1044 | objp = uptr->objp; /* position op */\r | |
1045 | sts = tq_mot_valid (uptr, OP_POS); /* validity checks */\r | |
1046 | if (sts == ST_SUC) { /* ok? */\r | |
1047 | uptr->cpkt = pkt; /* op in progress */\r | |
1048 | sim_activate (uptr, tq_xtime); /* activate */\r | |
1049 | return OK; /* done */\r | |
1050 | }\r | |
1051 | }\r | |
1052 | else sts = ST_OFL; /* offline */\r | |
1053 | PUTP32 (pkt, POS_RCL, 0); /* clear #skipped */\r | |
1054 | PUTP32 (pkt, POS_TMCL, 0);\r | |
1055 | PUTP32 (pkt, POS_POSL, objp); /* set obj pos */\r | |
1056 | tq_putr (pkt, OP_POS | OP_END, tq_efl (uptr), sts, POS_LNT, UQ_TYP_SEQ);\r | |
1057 | return tq_putpkt (pkt, TRUE);\r | |
1058 | }\r | |
1059 | \r | |
1060 | /* Data transfer commands - deferred if q'd commands, bypassed if ser exc */\r | |
1061 | \r | |
1062 | t_bool tq_rw (int32 pkt)\r | |
1063 | {\r | |
1064 | uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */\r | |
1065 | uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */\r | |
1066 | uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */\r | |
1067 | uint32 sts, objp = 0;\r | |
1068 | UNIT *uptr;\r | |
1069 | \r | |
1070 | if (uptr = tq_getucb (lu)) { /* unit exist? */\r | |
1071 | objp = uptr->objp; /* position op */\r | |
1072 | sts = tq_mot_valid (uptr, cmd); /* validity checks */\r | |
1073 | if (sts == ST_SUC) { /* ok? */\r | |
1074 | if ((bc == 0) || (bc > TQ_MAXFR)) { /* invalid? */\r | |
1075 | uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r | |
1076 | sts = ST_CMD | I_BCNT;\r | |
1077 | }\r | |
1078 | else {\r | |
1079 | uptr->cpkt = pkt; /* op in progress */\r | |
1080 | sim_activate (uptr, tq_xtime); /* activate */\r | |
1081 | return OK; /* done */\r | |
1082 | }\r | |
1083 | }\r | |
1084 | }\r | |
1085 | else sts = ST_OFL; /* offline */\r | |
1086 | PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r | |
1087 | PUTP32 (pkt, RW_POSL, objp); /* set obj pos */\r | |
1088 | PUTP32 (pkt, RW_RSZL, 0); /* clr rec size */\r | |
1089 | tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT_T, UQ_TYP_SEQ);\r | |
1090 | return tq_putpkt (pkt, TRUE);\r | |
1091 | }\r | |
1092 | \r | |
1093 | /* Validity checks */\r | |
1094 | \r | |
1095 | int32 tq_mot_valid (UNIT *uptr, uint32 cmd)\r | |
1096 | {\r | |
1097 | if (uptr->flags & UNIT_SXC) return ST_SXC; /* ser exc pend? */\r | |
1098 | if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */\r | |
1099 | return (ST_OFL | SB_OFL_NV); /* offl no vol */\r | |
1100 | if ((uptr->flags & UNIT_ONL) == 0) /* not online? */\r | |
1101 | return ST_AVL; /* only avail */\r | |
1102 | if (tq_cmf[cmd] & CMF_WR) { /* write op? */\r | |
1103 | if (uptr->uf & UF_WPS) { /* swre wlk? */\r | |
1104 | uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r | |
1105 | return (ST_WPR | SB_WPR_SW);\r | |
1106 | }\r | |
1107 | if (TQ_WPH (uptr)) { /* hwre wlk? */\r | |
1108 | uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r | |
1109 | return (ST_WPR | SB_WPR_HW);\r | |
1110 | }\r | |
1111 | }\r | |
1112 | return ST_SUC; /* success! */\r | |
1113 | }\r | |
1114 | \r | |
1115 | /* Unit service for motion commands */\r | |
1116 | \r | |
1117 | t_stat tq_svc (UNIT *uptr)\r | |
1118 | {\r | |
1119 | uint32 t, sts, sktmk, skrec;\r | |
1120 | t_mtrlnt i, tbc, wbc;\r | |
1121 | int32 pkt = uptr->cpkt; /* get packet */\r | |
1122 | uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */\r | |
1123 | uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */\r | |
1124 | uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */\r | |
1125 | t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */\r | |
1126 | uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */\r | |
1127 | uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */\r | |
1128 | \r | |
1129 | if (pkt == 0) return SCPE_IERR; /* what??? */\r | |
1130 | if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */\r | |
1131 | tq_mot_end (uptr, 0, ST_OFL | SB_OFL_NV, 0); /* offl no vol */\r | |
1132 | return SCPE_OK;\r | |
1133 | }\r | |
1134 | \r | |
1135 | if (tq_cmf[cmd] & CMF_WR) { /* write op? */\r | |
1136 | if (TQ_WPH (uptr)) { /* hwre write prot? */\r | |
1137 | uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r | |
1138 | tq_mot_end (uptr, 0, ST_WPR | SB_WPR_HW, 0);\r | |
1139 | return SCPE_OK;\r | |
1140 | }\r | |
1141 | if (uptr->uf & UF_WPS) { /* swre write prot? */\r | |
1142 | uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */\r | |
1143 | tq_mot_end (uptr, 0, ST_WPR | SB_WPR_SW, 0);\r | |
1144 | return SCPE_OK;\r | |
1145 | }\r | |
1146 | }\r | |
1147 | sts = ST_SUC; /* assume success */\r | |
1148 | tbc = 0; /* assume zero rec */\r | |
1149 | switch (cmd) { /* case on command */\r | |
1150 | \r | |
1151 | case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */\r | |
1152 | if (mdf & MD_REV) sts = tq_rdbufr (uptr, &tbc); /* read record */\r | |
1153 | else sts = tq_rdbuff (uptr, &tbc);\r | |
1154 | if (sts == ST_DRV) { /* read error? */\r | |
1155 | PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r | |
1156 | return tq_mot_err (uptr, tbc); /* log, done */\r | |
1157 | }\r | |
1158 | if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */\r | |
1159 | PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */\r | |
1160 | break;\r | |
1161 | }\r | |
1162 | if (tbc > bc) { /* tape rec > buf? */\r | |
1163 | uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */\r | |
1164 | sts = ST_RDT; /* data truncated */\r | |
1165 | wbc = bc; /* set working bc */\r | |
1166 | }\r | |
1167 | else wbc = tbc;\r | |
1168 | if (cmd == OP_RD) { /* read? */\r | |
1169 | if (t = Map_WriteB (ba, wbc, tqxb)) { /* store, nxm? */\r | |
1170 | PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */\r | |
1171 | if (tq_hbe (uptr, ba + wbc - t)) /* post err log */\r | |
1172 | tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); \r | |
1173 | return SCPE_OK; /* end if nxm */\r | |
1174 | }\r | |
1175 | } /* end if read */\r | |
1176 | else { /* compare */\r | |
1177 | uint8 mby, dby;\r | |
1178 | uint32 mba;\r | |
1179 | for (i = 0; i < wbc; i++) { /* loop */\r | |
1180 | if (mdf & MD_REV) { /* reverse? */\r | |
1181 | mba = ba + bc - 1 - i; /* mem addr */\r | |
1182 | dby = tqxb[tbc - 1 - i]; /* byte */\r | |
1183 | }\r | |
1184 | else {\r | |
1185 | mba = ba + i;\r | |
1186 | dby = tqxb[i];\r | |
1187 | }\r | |
1188 | if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */\r | |
1189 | PUTP32 (pkt, RW_BCL, i); /* adj bc */\r | |
1190 | if (tq_hbe (uptr, mba)) /* post err log */\r | |
1191 | tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);\r | |
1192 | return SCPE_OK;\r | |
1193 | }\r | |
1194 | if (mby != dby) { /* cmp err? */\r | |
1195 | uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */\r | |
1196 | PUTP32 (pkt, RW_BCL, i); /* adj bc */\r | |
1197 | tq_mot_end (uptr, 0, ST_CMP, tbc);\r | |
1198 | return SCPE_OK; /* exit */\r | |
1199 | }\r | |
1200 | } /* end for */\r | |
1201 | } /* end if compare */\r | |
1202 | PUTP32 (pkt, RW_BCL, wbc); /* bytes read/cmp'd */\r | |
1203 | break;\r | |
1204 | \r | |
1205 | case OP_WR: /* write */\r | |
1206 | if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */\r | |
1207 | PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */\r | |
1208 | if (tq_hbe (uptr, ba + bc - t)) /* post err log */\r | |
1209 | tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); \r | |
1210 | return SCPE_OK; /* end else wr */\r | |
1211 | }\r | |
1212 | if (sim_tape_wrrecf (uptr, tqxb, bc)) /* write rec fwd, err? */\r | |
1213 | return tq_mot_err (uptr, bc); /* log, end */\r | |
1214 | uptr->objp = uptr->objp + 1; /* upd obj pos */\r | |
1215 | if (TEST_EOT (uptr)) /* EOT on write? */\r | |
1216 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1217 | uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */\r | |
1218 | tbc = bc; /* RW_BC is ok */\r | |
1219 | break;\r | |
1220 | \r | |
1221 | case OP_WTM: /* write tape mark */\r | |
1222 | if (sim_tape_wrtmk (uptr)) /* write tmk, err? */\r | |
1223 | return tq_mot_err (uptr, 0); /* log, end */\r | |
1224 | uptr->objp = uptr->objp + 1; /* incr obj cnt */\r | |
1225 | case OP_ERG: /* erase gap */\r | |
1226 | if (TEST_EOT (uptr)) /* EOT on write? */\r | |
1227 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1228 | uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */\r | |
1229 | break;\r | |
1230 | \r | |
1231 | case OP_ERS: /* erase */\r | |
1232 | if (sim_tape_wreom (uptr)) /* write eom, err? */\r | |
1233 | return tq_mot_err (uptr, 0); /* log, end */\r | |
1234 | sim_tape_rewind (uptr); /* rewind */\r | |
1235 | uptr->objp = 0;\r | |
1236 | uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);\r | |
1237 | break;\r | |
1238 | \r | |
1239 | case OP_POS: /* position */\r | |
1240 | sktmk = skrec = 0; /* clr skipped */\r | |
1241 | if (mdf & MD_RWD) { /* rewind? */\r | |
1242 | sim_tape_rewind (uptr);\r | |
1243 | uptr->objp = 0; /* clr flags */\r | |
1244 | uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL);\r | |
1245 | }\r | |
1246 | if (mdf & MD_OBC) { /* skip obj? */\r | |
1247 | if (mdf & MD_REV) /* reverse? */\r | |
1248 | sts = tq_spacer (uptr, nrec, &skrec, FALSE);\r | |
1249 | else sts = tq_spacef (uptr, nrec, &skrec, FALSE);\r | |
1250 | } \r | |
1251 | else { /* skip tmk, rec */\r | |
1252 | if (mdf & MD_REV) sts = tq_skipfr (uptr, ntmk, &sktmk);\r | |
1253 | else sts = tq_skipff (uptr, ntmk, &sktmk); \r | |
1254 | if (sts == ST_SUC) { /* tmk succeed? */\r | |
1255 | if (mdf & MD_REV) /* reverse? */\r | |
1256 | sts = tq_spacer (uptr, nrec, &skrec, TRUE);\r | |
1257 | else sts = tq_spacef (uptr, nrec, &skrec, TRUE);\r | |
1258 | if (sts == ST_TMK) sktmk = sktmk + 1;\r | |
1259 | }\r | |
1260 | }\r | |
1261 | PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */\r | |
1262 | PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */\r | |
1263 | break;\r | |
1264 | \r | |
1265 | default:\r | |
1266 | return SCPE_IERR;\r | |
1267 | }\r | |
1268 | \r | |
1269 | tq_mot_end (uptr, 0, sts, tbc); /* done */\r | |
1270 | return SCPE_OK;\r | |
1271 | }\r | |
1272 | \r | |
1273 | /* Motion command drive error */\r | |
1274 | \r | |
1275 | t_stat tq_mot_err (UNIT *uptr, uint32 rsiz)\r | |
1276 | {\r | |
1277 | uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_TMK; /* serious exception */\r | |
1278 | if (tq_dte (uptr, ST_DRV)) /* post err log */\r | |
1279 | tq_mot_end (uptr, EF_LOG, ST_DRV, rsiz); /* if ok, report err */\r | |
1280 | perror ("TQ I/O error");\r | |
1281 | clearerr (uptr->fileref);\r | |
1282 | return SCPE_IOERR;\r | |
1283 | }\r | |
1284 | \r | |
1285 | /* Motion command complete */\r | |
1286 | \r | |
1287 | t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz)\r | |
1288 | {\r | |
1289 | int32 pkt = uptr->cpkt; /* packet */\r | |
1290 | uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */\r | |
1291 | uint32 lnt = RW_LNT_T; /* assume rw */\r | |
1292 | \r | |
1293 | if (cmd == OP_ERG) lnt = ERG_LNT; /* set pkt lnt */\r | |
1294 | else if (cmd == OP_ERS) lnt = ERS_LNT;\r | |
1295 | else if (cmd == OP_WTM) lnt = WTM_LNT;\r | |
1296 | else if (cmd == OP_POS) lnt = POS_LNT;\r | |
1297 | \r | |
1298 | uptr->cpkt = 0; /* done */\r | |
1299 | if (lnt > ERG_LNT) { /* xfer cmd? */\r | |
1300 | PUTP32 (pkt, RW_POSL, uptr->objp); /* position */\r | |
1301 | PUTP32 (pkt, RW_RSZL, rsiz); /* record size */\r | |
1302 | }\r | |
1303 | tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ);\r | |
1304 | if (!tq_putpkt (pkt, TRUE)) return ERR; /* send pkt */\r | |
1305 | if (uptr->pktq) /* more to do? */\r | |
1306 | sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate thread */\r | |
1307 | return OK;\r | |
1308 | }\r | |
1309 | \r | |
1310 | /* Tape motion routines */\r | |
1311 | \r | |
1312 | uint32 tq_map_status (UNIT *uptr, t_stat st)\r | |
1313 | {\r | |
1314 | switch (st) {\r | |
1315 | \r | |
1316 | case MTSE_OK:\r | |
1317 | break;\r | |
1318 | \r | |
1319 | case MTSE_UNATT:\r | |
1320 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1321 | return (ST_OFL | SB_OFL_NV);\r | |
1322 | \r | |
1323 | case MTSE_FMT:\r | |
1324 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1325 | return ST_MFE;\r | |
1326 | \r | |
1327 | case MTSE_TMK:\r | |
1328 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1329 | return ST_TMK;\r | |
1330 | \r | |
1331 | case MTSE_INVRL:\r | |
1332 | uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r | |
1333 | return ST_FMT;\r | |
1334 | \r | |
1335 | case MTSE_RECE:\r | |
1336 | case MTSE_IOERR:\r | |
1337 | uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r | |
1338 | return ST_DRV;\r | |
1339 | \r | |
1340 | case MTSE_EOM:\r | |
1341 | uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL;\r | |
1342 | return ST_DAT;\r | |
1343 | \r | |
1344 | case MTSE_BOT:\r | |
1345 | uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL;\r | |
1346 | return ST_BOT;\r | |
1347 | \r | |
1348 | case MTSE_WRP:\r | |
1349 | uptr->flags = uptr->flags | UNIT_SXC;\r | |
1350 | return ST_WPR;\r | |
1351 | }\r | |
1352 | \r | |
1353 | return ST_SUC;\r | |
1354 | }\r | |
1355 | \r | |
1356 | uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)\r | |
1357 | {\r | |
1358 | t_stat st;\r | |
1359 | t_mtrlnt tbc;\r | |
1360 | \r | |
1361 | *skipped = 0;\r | |
1362 | while (*skipped < cnt) { /* loop */\r | |
1363 | st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */\r | |
1364 | if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */\r | |
1365 | return tq_map_status (uptr, st); /* map status */\r | |
1366 | uptr->objp = uptr->objp + 1; /* upd obj cnt */\r | |
1367 | if (st == MTSE_TMK) { /* tape mark? */\r | |
1368 | int32 pkt = uptr->cpkt; /* get pkt */\r | |
1369 | if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) && /* LEOT? */\r | |
1370 | (uptr->flags & UNIT_TMK)) {\r | |
1371 | sim_tape_sprecr (uptr, &tbc); /* rev over tmk */\r | |
1372 | uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ \r | |
1373 | return ST_LED;\r | |
1374 | }\r | |
1375 | uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */\r | |
1376 | if (qrec) return ST_TMK; /* rec spc? stop */\r | |
1377 | }\r | |
1378 | else uptr->flags = uptr->flags & ~UNIT_TMK; /* clr TM seen */\r | |
1379 | *skipped = *skipped + 1; /* # obj skipped */\r | |
1380 | }\r | |
1381 | return ST_SUC;\r | |
1382 | }\r | |
1383 | \r | |
1384 | uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped)\r | |
1385 | {\r | |
1386 | uint32 st, skrec;\r | |
1387 | \r | |
1388 | *skipped = 0;\r | |
1389 | while (*skipped < cnt) { /* loop */\r | |
1390 | st = tq_spacef (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc fwd */\r | |
1391 | if (st == ST_TMK) *skipped = *skipped + 1; /* count files */\r | |
1392 | else if (st != ST_SUC) return st;\r | |
1393 | }\r | |
1394 | return ST_SUC;\r | |
1395 | }\r | |
1396 | \r | |
1397 | uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec)\r | |
1398 | {\r | |
1399 | t_stat st;\r | |
1400 | t_mtrlnt tbc;\r | |
1401 | \r | |
1402 | *skipped = 0;\r | |
1403 | while (*skipped < cnt) { /* loop */\r | |
1404 | st = sim_tape_sprecr (uptr, &tbc); /* spc rec rev */\r | |
1405 | if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */\r | |
1406 | return tq_map_status (uptr, st); /* map status */\r | |
1407 | uptr->objp = uptr->objp - 1; /* upd obj cnt */\r | |
1408 | if ((st == MTSE_TMK) && qrec) return ST_TMK; /* tape mark, stop? */\r | |
1409 | *skipped = *skipped + 1; /* # obj skipped */\r | |
1410 | }\r | |
1411 | return ST_SUC;\r | |
1412 | }\r | |
1413 | \r | |
1414 | uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped)\r | |
1415 | {\r | |
1416 | uint32 st, skrec;\r | |
1417 | \r | |
1418 | *skipped = 0;\r | |
1419 | while (*skipped < cnt) { /* loopo */\r | |
1420 | st = tq_spacer (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc rev */\r | |
1421 | if (st == ST_TMK) *skipped = *skipped + 1; /* tape mark? */\r | |
1422 | else if (st != 0) return st; /* error? */\r | |
1423 | }\r | |
1424 | return ST_SUC;\r | |
1425 | }\r | |
1426 | \r | |
1427 | /* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */\r | |
1428 | \r | |
1429 | uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc)\r | |
1430 | {\r | |
1431 | t_stat st;\r | |
1432 | \r | |
1433 | st = sim_tape_rdrecf (uptr, tqxb, tbc, MT_MAXFR); /* read rec fwd */\r | |
1434 | if (st == MTSE_TMK) { /* tape mark? */\r | |
1435 | uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */\r | |
1436 | uptr->objp = uptr->objp + 1; /* update obj cnt */\r | |
1437 | return ST_TMK;\r | |
1438 | }\r | |
1439 | if (st != MTSE_OK) return tq_map_status (uptr, st); /* other error? */\r | |
1440 | uptr->flags = uptr->flags & ~UNIT_TMK; /* clr tape mark */\r | |
1441 | uptr->objp = uptr->objp + 1; /* upd obj cnt */\r | |
1442 | return ST_SUC;\r | |
1443 | }\r | |
1444 | \r | |
1445 | uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc)\r | |
1446 | {\r | |
1447 | t_stat st;\r | |
1448 | \r | |
1449 | st = sim_tape_rdrecr (uptr, tqxb, tbc, MT_MAXFR); /* read rec rev */\r | |
1450 | if (st == MTSE_TMK) { /* tape mark? */\r | |
1451 | uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */\r | |
1452 | uptr->objp = uptr->objp - 1; /* update obj cnt */\r | |
1453 | return ST_TMK;\r | |
1454 | }\r | |
1455 | if (st != MTSE_OK) return tq_map_status (uptr, st); /* other error? */\r | |
1456 | uptr->objp = uptr->objp - 1; /* upd obj cnt */\r | |
1457 | return ST_SUC;\r | |
1458 | }\r | |
1459 | \r | |
1460 | /* Data transfer error log packet */\r | |
1461 | \r | |
1462 | t_bool tq_dte (UNIT *uptr, uint32 err)\r | |
1463 | {\r | |
1464 | int32 pkt, tpkt;\r | |
1465 | uint32 lu;\r | |
1466 | \r | |
1467 | if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */\r | |
1468 | if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r | |
1469 | tpkt = uptr->cpkt; /* rw pkt */\r | |
1470 | lu = tq_pkt[tpkt].d[CMD_UN]; /* unit # */\r | |
1471 | \r | |
1472 | tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */\r | |
1473 | tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */\r | |
1474 | tq_pkt[pkt].d[ELP_UN] = lu; /* copy unit */\r | |
1475 | tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */\r | |
1476 | tq_pkt[pkt].d[DTE_CIDA] = 0; /* ctrl ID */\r | |
1477 | tq_pkt[pkt].d[DTE_CIDB] = 0;\r | |
1478 | tq_pkt[pkt].d[DTE_CIDC] = 0;\r | |
1479 | tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |\r | |
1480 | (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);\r | |
1481 | tq_pkt[pkt].d[DTE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */\r | |
1482 | tq_pkt[pkt].d[DTE_MLUN] = lu; /* MLUN */\r | |
1483 | tq_pkt[pkt].d[DTE_UIDA] = lu; /* unit ID */\r | |
1484 | tq_pkt[pkt].d[DTE_UIDB] = 0;\r | |
1485 | tq_pkt[pkt].d[DTE_UIDC] = 0;\r | |
1486 | tq_pkt[pkt].d[DTE_UIDD] = (UID_TAPE << DTE_UIDD_V_CLS) |\r | |
1487 | (drv_tab[tq_typ].umod << DTE_UIDD_V_MOD);\r | |
1488 | tq_pkt[pkt].d[DTE_UVER] = drv_tab[tq_typ].uver; /* unit ver */\r | |
1489 | PUTP32 (pkt, DTE_POSL, uptr->objp); /* position */\r | |
1490 | tq_pkt[pkt].d[DTE_FVER] = drv_tab[tq_typ].fver; /* fmtr ver */\r | |
1491 | tq_putr (pkt, FM_TAP, LF_SNR, err, DTE_LNT, UQ_TYP_DAT);\r | |
1492 | return tq_putpkt (pkt, TRUE);\r | |
1493 | }\r | |
1494 | \r | |
1495 | /* Host bus error log packet */\r | |
1496 | \r | |
1497 | t_bool tq_hbe (UNIT *uptr, uint32 ba)\r | |
1498 | {\r | |
1499 | int32 pkt, tpkt;\r | |
1500 | \r | |
1501 | if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */\r | |
1502 | if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r | |
1503 | tpkt = uptr->cpkt; /* rw pkt */\r | |
1504 | tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */\r | |
1505 | tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */\r | |
1506 | tq_pkt[pkt].d[ELP_UN] = tq_pkt[tpkt].d[CMD_UN]; /* copy unit */\r | |
1507 | tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */\r | |
1508 | tq_pkt[pkt].d[HBE_CIDA] = 0; /* ctrl ID */\r | |
1509 | tq_pkt[pkt].d[HBE_CIDB] = 0;\r | |
1510 | tq_pkt[pkt].d[HBE_CIDC] = 0;\r | |
1511 | tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) |\r | |
1512 | (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD);\r | |
1513 | tq_pkt[pkt].d[HBE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */\r | |
1514 | tq_pkt[pkt].d[HBE_RSV] = 0;\r | |
1515 | PUTP32 (pkt, HBE_BADL, ba); /* bad addr */\r | |
1516 | tq_putr (pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT);\r | |
1517 | return tq_putpkt (pkt, TRUE);\r | |
1518 | }\r | |
1519 | \r | |
1520 | /* Port last failure error log packet */\r | |
1521 | \r | |
1522 | t_bool tq_plf (uint32 err)\r | |
1523 | {\r | |
1524 | int32 pkt;\r | |
1525 | \r | |
1526 | if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r | |
1527 | tq_pkt[pkt].d[ELP_REFL] = tq_pkt[pkt].d[ELP_REFH] = 0; /* ref = 0 */\r | |
1528 | tq_pkt[pkt].d[ELP_UN] = tq_pkt[pkt].d[ELP_SEQ] = 0; /* no unit, seq */\r | |
1529 | tq_pkt[pkt].d[PLF_CIDA] = 0; /* cntl ID */\r | |
1530 | tq_pkt[pkt].d[PLF_CIDB] = 0;\r | |
1531 | tq_pkt[pkt].d[PLF_CIDC] = 0;\r | |
1532 | tq_pkt[pkt].d[PLF_CIDD] = (TQ_CLASS << PLF_CIDD_V_CLS) |\r | |
1533 | (drv_tab[tq_typ].cmod << PLF_CIDD_V_MOD);\r | |
1534 | tq_pkt[pkt].d[PLF_VER] = drv_tab[tq_typ].cver;\r | |
1535 | tq_pkt[pkt].d[PLF_ERR] = err;\r | |
1536 | tq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT);\r | |
1537 | tq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID);\r | |
1538 | return tq_putpkt (pkt, TRUE);\r | |
1539 | }\r | |
1540 | \r | |
1541 | /* Unit now available attention packet */\r | |
1542 | \r | |
1543 | int32 tq_una (UNIT *uptr)\r | |
1544 | {\r | |
1545 | int32 pkt;\r | |
1546 | uint32 lu;\r | |
1547 | \r | |
1548 | if (!tq_deqf (&pkt)) return ERR; /* get log pkt */\r | |
1549 | lu = (uint32) (uptr - tq_dev.units); /* get unit */\r | |
1550 | tq_pkt[pkt].d[RSP_REFL] = tq_pkt[pkt].d[RSP_REFH] = 0; /* ref = 0 */\r | |
1551 | tq_pkt[pkt].d[RSP_UN] = lu;\r | |
1552 | tq_pkt[pkt].d[RSP_RSV] = 0;\r | |
1553 | tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */\r | |
1554 | tq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */\r | |
1555 | return tq_putpkt (pkt, TRUE);\r | |
1556 | }\r | |
1557 | \r | |
1558 | /* List handling\r | |
1559 | \r | |
1560 | tq_deqf - dequeue head of free list (fatal err if none)\r | |
1561 | tq_deqh - dequeue head of list\r | |
1562 | tq_enqh - enqueue at head of list\r | |
1563 | tq_enqt - enqueue at tail of list\r | |
1564 | */\r | |
1565 | \r | |
1566 | t_bool tq_deqf (int32 *pkt)\r | |
1567 | {\r | |
1568 | if (tq_freq == 0) return tq_fatal (PE_NSR); /* no free pkts?? */\r | |
1569 | tq_pbsy = tq_pbsy + 1; /* cnt busy pkts */\r | |
1570 | *pkt = tq_freq; /* head of list */\r | |
1571 | tq_freq = tq_pkt[tq_freq].link; /* next */\r | |
1572 | return OK;\r | |
1573 | }\r | |
1574 | \r | |
1575 | int32 tq_deqh (int32 *lh)\r | |
1576 | {\r | |
1577 | int32 ptr = *lh; /* head of list */\r | |
1578 | \r | |
1579 | if (ptr) *lh = tq_pkt[ptr].link; /* next */\r | |
1580 | return ptr;\r | |
1581 | }\r | |
1582 | \r | |
1583 | void tq_enqh (int32 *lh, int32 pkt)\r | |
1584 | {\r | |
1585 | if (pkt == 0) return; /* any pkt? */\r | |
1586 | tq_pkt[pkt].link = *lh; /* link is old lh */\r | |
1587 | *lh = pkt; /* pkt is new lh */\r | |
1588 | return;\r | |
1589 | }\r | |
1590 | \r | |
1591 | void tq_enqt (int32 *lh, int32 pkt)\r | |
1592 | {\r | |
1593 | if (pkt == 0) return; /* any pkt? */\r | |
1594 | tq_pkt[pkt].link = 0; /* it will be tail */\r | |
1595 | if (*lh == 0) *lh = pkt; /* if empty, enqh */\r | |
1596 | else {\r | |
1597 | uint32 ptr = *lh; /* chase to end */\r | |
1598 | while (tq_pkt[ptr].link) ptr = tq_pkt[ptr].link;\r | |
1599 | tq_pkt[ptr].link = pkt; /* enq at tail */\r | |
1600 | }\r | |
1601 | return;\r | |
1602 | }\r | |
1603 | \r | |
1604 | /* Packet and descriptor handling */\r | |
1605 | \r | |
1606 | /* Get packet from command ring */\r | |
1607 | \r | |
1608 | t_bool tq_getpkt (int32 *pkt)\r | |
1609 | {\r | |
1610 | uint32 addr, desc;\r | |
1611 | \r | |
1612 | if (!tq_getdesc (&tq_cq, &desc)) return ERR; /* get cmd desc */\r | |
1613 | if ((desc & UQ_DESC_OWN) == 0) { /* none */\r | |
1614 | *pkt = 0; /* pkt = 0 */\r | |
1615 | return OK; /* no error */\r | |
1616 | }\r | |
1617 | if (!tq_deqf (pkt)) return ERR; /* get cmd pkt */\r | |
1618 | tq_hat = 0; /* dsbl hst timer */\r | |
1619 | addr = desc & UQ_ADDR; /* get Q22 addr */\r | |
1620 | if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d))\r | |
1621 | return tq_fatal (PE_PRE); /* read pkt */\r | |
1622 | return tq_putdesc (&tq_cq, desc); /* release desc */\r | |
1623 | }\r | |
1624 | \r | |
1625 | /* Put packet to response ring - note the clever hack about credits.\r | |
1626 | The controller sends all its credits to the host. Thereafter, it\r | |
1627 | supplies one credit for every response packet sent over. Simple!\r | |
1628 | */\r | |
1629 | \r | |
1630 | t_bool tq_putpkt (int32 pkt, t_bool qt)\r | |
1631 | {\r | |
1632 | uint32 addr, desc, lnt, cr;\r | |
1633 | \r | |
1634 | if (pkt == 0) return OK; /* any packet? */\r | |
1635 | if (DEBUG_PRS (tq_dev)) {\r | |
1636 | UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]);\r | |
1637 | fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X",\r | |
1638 | tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]);\r | |
1639 | if (up) fprintf (sim_deb, ", pos=%d, obj=%d\n", up->pos, up->objp);\r | |
1640 | else fprintf (sim_deb, "\n");\r | |
1641 | fflush (sim_deb);\r | |
1642 | }\r | |
1643 | if (!tq_getdesc (&tq_rq, &desc)) return ERR; /* get rsp desc */\r | |
1644 | if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */\r | |
1645 | if (qt) tq_enqt (&tq_rspq, pkt); /* normal? q tail */\r | |
1646 | else tq_enqh (&tq_rspq, pkt); /* resp q call */\r | |
1647 | sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate q thrd */\r | |
1648 | return OK;\r | |
1649 | }\r | |
1650 | addr = desc & UQ_ADDR; /* get Q22 addr */\r | |
1651 | lnt = tq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */\r | |
1652 | if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */\r | |
1653 | (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */\r | |
1654 | cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */\r | |
1655 | tq_credits = tq_credits - cr; /* decr credits */\r | |
1656 | tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR);\r | |
1657 | }\r | |
1658 | if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d))\r | |
1659 | return tq_fatal (PE_PWE); /* write pkt */\r | |
1660 | tq_enqh (&tq_freq, pkt); /* pkt is free */\r | |
1661 | tq_pbsy = tq_pbsy - 1; /* decr busy cnt */\r | |
1662 | if (tq_pbsy == 0) tq_hat = tq_htmo; /* idle? strt hst tmr */\r | |
1663 | return tq_putdesc (&tq_rq, desc); /* release desc */\r | |
1664 | }\r | |
1665 | \r | |
1666 | /* Get a descriptor from the host */\r | |
1667 | \r | |
1668 | t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc)\r | |
1669 | {\r | |
1670 | uint32 addr = ring->ba + ring->idx;\r | |
1671 | uint16 d[2];\r | |
1672 | \r | |
1673 | if (Map_ReadW (addr, 4, d)) /* fetch desc */\r | |
1674 | return tq_fatal (PE_QRE); /* err? dead */\r | |
1675 | *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r | |
1676 | return OK;\r | |
1677 | }\r | |
1678 | \r | |
1679 | /* Return a descriptor to the host, clearing owner bit\r | |
1680 | If rings transitions from "empty" to "not empty" or "full" to\r | |
1681 | "not full", and interrupt bit was set, interrupt the host.\r | |
1682 | Actually, test whether previous ring entry was owned by host.\r | |
1683 | */\r | |
1684 | \r | |
1685 | t_bool tq_putdesc (struct uq_ring *ring, uint32 desc)\r | |
1686 | {\r | |
1687 | uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F;\r | |
1688 | uint32 prva, addr = ring->ba + ring->idx;\r | |
1689 | uint16 d[2];\r | |
1690 | \r | |
1691 | d[0] = newd & 0xFFFF; /* 32b to 16b */\r | |
1692 | d[1] = (newd >> 16) & 0xFFFF;\r | |
1693 | if (Map_WriteW (addr, 4, d)) /* store desc */\r | |
1694 | return tq_fatal (PE_QWE); /* err? dead */\r | |
1695 | if (desc & UQ_DESC_F) { /* was F set? */\r | |
1696 | if (ring->lnt <= 4) tq_ring_int (ring); /* lnt = 1? intr */\r | |
1697 | else {\r | |
1698 | prva = ring->ba + /* prv desc */\r | |
1699 | ((ring->idx - 4) & (ring->lnt - 1));\r | |
1700 | if (Map_ReadW (prva, 4, d)) /* read prv */\r | |
1701 | return tq_fatal (PE_QRE);\r | |
1702 | prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r | |
1703 | if (prvd & UQ_DESC_OWN) tq_ring_int (ring);\r | |
1704 | }\r | |
1705 | }\r | |
1706 | ring->idx = (ring->idx + 4) & (ring->lnt - 1);\r | |
1707 | return OK;\r | |
1708 | }\r | |
1709 | \r | |
1710 | /* Get unit descriptor for logical unit - trivial now,\r | |
1711 | but eventually, hide multiboard complexities here */\r | |
1712 | \r | |
1713 | UNIT *tq_getucb (uint32 lu)\r | |
1714 | {\r | |
1715 | UNIT *uptr;\r | |
1716 | \r | |
1717 | if (lu >= TQ_NUMDR) return NULL;\r | |
1718 | uptr = tq_dev.units + lu;\r | |
1719 | if (uptr->flags & UNIT_DIS) return NULL;\r | |
1720 | return uptr;\r | |
1721 | }\r | |
1722 | \r | |
1723 | /* Hack unit flags */\r | |
1724 | \r | |
1725 | void tq_setf_unit (int32 pkt, UNIT *uptr)\r | |
1726 | {\r | |
1727 | uptr->uf = tq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */\r | |
1728 | if ((tq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */\r | |
1729 | (tq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */\r | |
1730 | uptr->uf = uptr->uf | UF_WPS; /* simon says... */\r | |
1731 | return;\r | |
1732 | }\r | |
1733 | \r | |
1734 | /* Hack end flags */\r | |
1735 | \r | |
1736 | uint32 tq_efl (UNIT *uptr)\r | |
1737 | {\r | |
1738 | uint32 t = 0;\r | |
1739 | \r | |
1740 | if (uptr) { /* any unit? */\r | |
1741 | if (uptr->flags & UNIT_POL) t = t | EF_PLS; /* note pos lost */\r | |
1742 | if (uptr->flags & UNIT_SXC) t = t | EF_SXC; /* note ser exc */\r | |
1743 | if (TEST_EOT (uptr)) t = t | EF_EOT; /* note EOT */\r | |
1744 | }\r | |
1745 | return t;\r | |
1746 | }\r | |
1747 | \r | |
1748 | /* Unit response fields */\r | |
1749 | \r | |
1750 | void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all)\r | |
1751 | {\r | |
1752 | tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */\r | |
1753 | tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */\r | |
1754 | tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */\r | |
1755 | tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */\r | |
1756 | tq_pkt[pkt].d[ONL_UIDB] = 0;\r | |
1757 | tq_pkt[pkt].d[ONL_UIDC] = 0;\r | |
1758 | tq_pkt[pkt].d[ONL_UIDD] = (UID_TAPE << ONL_UIDD_V_CLS) |\r | |
1759 | (drv_tab[tq_typ].umod << ONL_UIDD_V_MOD); /* UID hi */\r | |
1760 | PUTP32 (pkt, ONL_MEDL, drv_tab[tq_typ].med); /* media type */\r | |
1761 | if (all) { /* if long form */\r | |
1762 | tq_pkt[pkt].d[ONL_FMT] = drv_tab[tq_typ].fmt; /* format */\r | |
1763 | tq_pkt[pkt].d[ONL_SPD] = 0; /* speed */\r | |
1764 | PUTP32 (pkt, ONL_MAXL, TQ_MAXFR); /* max xfr */\r | |
1765 | tq_pkt[pkt].d[ONL_NREC] = 0; /* noise rec */\r | |
1766 | tq_pkt[pkt].d[ONL_RSVE] = 0; /* reserved */\r | |
1767 | }\r | |
1768 | return;\r | |
1769 | }\r | |
1770 | \r | |
1771 | /* UQ_HDR and RSP_OP fields */\r | |
1772 | \r | |
1773 | void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ)\r | |
1774 | {\r | |
1775 | tq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */\r | |
1776 | (flg << RSP_OPF_V_FLG);\r | |
1777 | tq_pkt[pkt].d[RSP_STS] = sts;\r | |
1778 | tq_pkt[pkt].d[UQ_HLNT] = lnt; /* length */\r | |
1779 | tq_pkt[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */\r | |
1780 | (UQ_CID_TMSCP << UQ_HCTC_V_CID); /* clr credits */\r | |
1781 | return;\r | |
1782 | }\r | |
1783 | \r | |
1784 | /* Post interrupt during init */\r | |
1785 | \r | |
1786 | void tq_init_int (void)\r | |
1787 | {\r | |
1788 | if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec) SET_INT (TQ);\r | |
1789 | return;\r | |
1790 | }\r | |
1791 | \r | |
1792 | /* Post interrupt during putpkt - note that NXMs are ignored! */\r | |
1793 | \r | |
1794 | void tq_ring_int (struct uq_ring *ring)\r | |
1795 | {\r | |
1796 | uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */\r | |
1797 | uint16 flag = 1;\r | |
1798 | \r | |
1799 | Map_WriteW (iadr, 2, &flag); /* write flag */\r | |
1800 | if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */\r | |
1801 | return;\r | |
1802 | }\r | |
1803 | \r | |
1804 | /* Return interrupt vector */\r | |
1805 | \r | |
1806 | int32 tq_inta (void)\r | |
1807 | {\r | |
1808 | return tq_dib.vec; /* prog vector */\r | |
1809 | }\r | |
1810 | \r | |
1811 | /* Fatal error */\r | |
1812 | \r | |
1813 | t_bool tq_fatal (uint32 err)\r | |
1814 | {\r | |
1815 | if (DEBUG_PRS (tq_dev)) fprintf (sim_deb, ">>TQ: fatal err=%X\n", err);\r | |
1816 | tq_reset (&tq_dev); /* reset device */\r | |
1817 | tq_sa = SA_ER | err; /* SA = dead code */\r | |
1818 | tq_csta = CST_DEAD; /* state = dead */\r | |
1819 | tq_perr = err; /* save error */\r | |
1820 | return ERR;\r | |
1821 | }\r | |
1822 | \r | |
1823 | /* Device attach */\r | |
1824 | \r | |
1825 | t_stat tq_attach (UNIT *uptr, char *cptr)\r | |
1826 | {\r | |
1827 | t_stat r;\r | |
1828 | \r | |
1829 | r = sim_tape_attach (uptr, cptr);\r | |
1830 | if (r != SCPE_OK) return r;\r | |
1831 | if (tq_csta == CST_UP) uptr->flags = (uptr->flags | UNIT_ATP) &\r | |
1832 | ~(UNIT_SXC | UNIT_POL | UNIT_TMK);\r | |
1833 | return SCPE_OK;\r | |
1834 | }\r | |
1835 | \r | |
1836 | /* Device detach */\r | |
1837 | \r | |
1838 | t_stat tq_detach (UNIT *uptr)\r | |
1839 | {\r | |
1840 | t_stat r;\r | |
1841 | \r | |
1842 | r = sim_tape_detach (uptr); /* detach unit */\r | |
1843 | if (r != SCPE_OK) return r;\r | |
1844 | uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP | UNIT_SXC | UNIT_POL | UNIT_TMK);\r | |
1845 | uptr->uf = 0; /* clr unit flgs */\r | |
1846 | return SCPE_OK;\r | |
1847 | } \r | |
1848 | \r | |
1849 | /* Device reset */\r | |
1850 | \r | |
1851 | t_stat tq_reset (DEVICE *dptr)\r | |
1852 | {\r | |
1853 | int32 i, j;\r | |
1854 | UNIT *uptr;\r | |
1855 | \r | |
1856 | tq_csta = CST_S1; /* init stage 1 */\r | |
1857 | tq_s1dat = 0; /* no S1 data */\r | |
1858 | tq_dib.vec = 0; /* no vector */\r | |
1859 | if (UNIBUS) tq_sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; /* Unibus? */\r | |
1860 | else tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */\r | |
1861 | tq_cflgs = CF_RPL; /* ctrl flgs off */\r | |
1862 | tq_htmo = TQ_DHTMO; /* default timeout */\r | |
1863 | tq_hat = tq_htmo; /* default timer */\r | |
1864 | tq_cq.ba = tq_cq.lnt = tq_cq.idx = 0; /* clr cmd ring */\r | |
1865 | tq_rq.ba = tq_rq.lnt = tq_rq.idx = 0; /* clr rsp ring */\r | |
1866 | tq_credits = (TQ_NPKTS / 2) - 1; /* init credits */\r | |
1867 | tq_freq = 1; /* init free list */\r | |
1868 | for (i = 0; i < TQ_NPKTS; i++) { /* all pkts free */\r | |
1869 | if (i) tq_pkt[i].link = (i + 1) & TQ_M_NPKTS;\r | |
1870 | else tq_pkt[i].link = 0;\r | |
1871 | for (j = 0; j < TQ_PKT_SIZE_W; j++) tq_pkt[i].d[j] = 0;\r | |
1872 | }\r | |
1873 | tq_rspq = 0; /* no q'd rsp pkts */\r | |
1874 | tq_pbsy = 0; /* all pkts free */\r | |
1875 | tq_pip = 0; /* not polling */\r | |
1876 | CLR_INT (TQ); /* clr intr req */\r | |
1877 | for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */\r | |
1878 | uptr = tq_dev.units + i;\r | |
1879 | sim_cancel (uptr); /* clr activity */\r | |
1880 | sim_tape_reset (uptr);\r | |
1881 | uptr->flags = uptr->flags & /* not online */\r | |
1882 | ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK);\r | |
1883 | uptr->uf = 0; /* clr unit flags */\r | |
1884 | uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */\r | |
1885 | }\r | |
1886 | if (tqxb == NULL) tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8));\r | |
1887 | if (tqxb == NULL) return SCPE_MEM;\r | |
1888 | return SCPE_OK;\r | |
1889 | }\r | |
1890 | \r | |
1891 | /* Device bootstrap */\r | |
1892 | \r | |
1893 | #if defined (VM_PDP11)\r | |
1894 | \r | |
1895 | #define BOOT_START 016000 /* start */\r | |
1896 | #define BOOT_ENTRY (BOOT_START + 002) /* entry */\r | |
1897 | #define BOOT_UNIT (BOOT_START + 010) /* unit number */\r | |
1898 | #define BOOT_CSR (BOOT_START + 014) /* CSR */\r | |
1899 | #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))\r | |
1900 | \r | |
1901 | /* Data structure definitions */\r | |
1902 | \r | |
1903 | #define B_CMDINT (BOOT_START - 01000) /* cmd int */\r | |
1904 | #define B_RSPINT (B_CMDINT + 002) /* rsp int */\r | |
1905 | #define B_RING (B_RSPINT + 002) /* ring base */\r | |
1906 | #define B_RSPH (B_RING + 010) /* resp pkt hdr */\r | |
1907 | #define B_TKRSP (B_RSPH + 004) /* resp pkt */\r | |
1908 | #define B_CMDH (B_TKRSP + 060) /* cmd pkt hdr */\r | |
1909 | #define B_TKCMD (B_CMDH + 004) /* cmd pkt */\r | |
1910 | #define B_UNIT (B_TKCMD + 004) /* unit # */\r | |
1911 | \r | |
1912 | static const uint16 boot_rom[] = {\r | |
1913 | \r | |
1914 | 0046525, /* ST: "UM" */\r | |
1915 | \r | |
1916 | 0012706, 0016000, /* mov #st,sp */\r | |
1917 | 0012700, 0000000, /* mov #unitno,r0 */\r | |
1918 | 0012701, 0174500, /* mov #174500,r1 ; ip addr */\r | |
1919 | 0005021, /* clr (r1)+ ; init */\r | |
1920 | 0012704, 0004000, /* mov #4000,r4 ; s1 mask */\r | |
1921 | 0005002, /* clr r2 */\r | |
1922 | 0005022, /* 10$: clr (r2)+ ; clr up to boot */\r | |
1923 | 0020237, BOOT_START - 2, /* cmp r2,#st-2 */\r | |
1924 | 0103774, /* blo 10$ */\r | |
1925 | 0012705, BOOT_START+0312, /* mov #cmdtbl,r5 ; addr of tbl */\r | |
1926 | \r | |
1927 | /* Four step init process */\r | |
1928 | \r | |
1929 | 0005711, /* 20$: tst (r1) ; err? */\r | |
1930 | 0100001, /* bpl 30$ */\r | |
1931 | 0000000, /* halt */\r | |
1932 | 0030411, /* 30$: bit r4,(r1) ; step set? */\r | |
1933 | 0001773, /* beq 20$ ; wait */\r | |
1934 | 0012511, /* mov (r5)+,(r1) ; send next */\r | |
1935 | 0006304, /* asl r4 ; next mask */\r | |
1936 | 0100370, /* bpl 20$ ; s4 done? */\r | |
1937 | \r | |
1938 | /* Set up rings, issue ONLINE, REWIND, READ */\r | |
1939 | \r | |
1940 | 0012737, 0000400, B_CMDH + 2, /* mov #400,cmdh+2 ; VCID = 1 */\r | |
1941 | 0012737, 0000044, B_CMDH, /* mov #36.,cmdh ; cmd pkt lnt */\r | |
1942 | 0010037, B_UNIT, /* mov r0,unit ; unit # */\r | |
1943 | 0012737, 0000011, B_TKCMD + 8, /* mov #11,tkcmd+8. ; online op */\r | |
1944 | 0012737, 0020000, B_TKCMD + 10, /* mov #20000,tkcmd+10. ; clr ser ex */\r | |
1945 | 0012702, B_RING, /* mov #ring,r2 ; init rings */\r | |
1946 | 0012722, B_TKRSP, /* mov #tkrsp,(r2)+ ; rsp pkt addr */\r | |
1947 | 0010203, /* mov r2,r3 ; save ring+2 */\r | |
1948 | 0010423, /* mov r4,(r3)+ ; set TK own */\r | |
1949 | 0012723, B_TKCMD, /* mov #tkcmd,(r3)+ ; cmd pkt addr */\r | |
1950 | 0010423, /* mov r4,(r3)+ ; set TK own */\r | |
1951 | 0005741, /* tst -(r1) ; start poll */\r | |
1952 | 0005712, /* 40$: tst (r2) ; wait for resp */\r | |
1953 | 0100776, /* bmi 40$ */\r | |
1954 | 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r | |
1955 | 0001401, /* beq 50$ */\r | |
1956 | 0000000, /* halt */\r | |
1957 | 0012703, B_TKCMD + 8, /* 50$: mov #tkcmd+8.,r3 */\r | |
1958 | 0012723, 0000045, /* mov #45,(r3)+ ; reposition */\r | |
1959 | 0012723, 0020002, /* mov #20002,(r3)+ ; rew, clr exc */\r | |
1960 | 0012723, 0000001, /* mov #1,(r3)+ ; lo rec skp */\r | |
1961 | 0005023, /* clr (r3)+ ; hi rec skp */\r | |
1962 | 0005023, /* clr (r3)+ ; lo tmk skp */\r | |
1963 | 0005023, /* clr (r3)+ ; hi tmk skp */\r | |
1964 | 0010412, /* mov r4,(r2) ; TK own rsp */\r | |
1965 | 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */\r | |
1966 | 0005711, /* tst (r1) ; start poll */\r | |
1967 | 0005712, /* 60$: tst (r2) ; wait for resp */\r | |
1968 | 0100776, /* bmi 60$ */\r | |
1969 | 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r | |
1970 | 0001401, /* beq 70$ */\r | |
1971 | 0000000, /* halt */\r | |
1972 | 0012703, B_TKCMD + 8, /* 70$: mov #tkcmd+8.,r3 */\r | |
1973 | 0012723, 0000041, /* mov #41,(r3)+ ; read */\r | |
1974 | 0012723, 0020000, /* mov #20000,(r3)+ ; clr exc */\r | |
1975 | 0012723, 0001000, /* mov #512.,(r3)+ ; bc = 512 */\r | |
1976 | 0005023, /* clr (r3)+ ; clr args */\r | |
1977 | 0005023, /* clr (r3)+ ; ba = 0 */\r | |
1978 | 0010412, /* mov r4,(r2) ; TK own rsp */\r | |
1979 | 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */\r | |
1980 | 0005711, /* tst (r1) ; start poll */\r | |
1981 | 0005712, /* 80$: tst (r2) ; wait for resp */\r | |
1982 | 0100776, /* bmi 80$ */\r | |
1983 | 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */\r | |
1984 | 0001401, /* beq 90$ */\r | |
1985 | 0000000, /* halt */\r | |
1986 | \r | |
1987 | /* Boot block read in, jump to 0 - leave controller init'd */\r | |
1988 | \r | |
1989 | 0005003, /* clr r3 */\r | |
1990 | 0012704, BOOT_START+020, /* mov #st+020,r4 */\r | |
1991 | 0005005, /* clr r5 */\r | |
1992 | 0005007, /* clr pc */\r | |
1993 | \r | |
1994 | 0100000, /* cmdtbl: init step 1 */\r | |
1995 | B_RING, /* ring base */\r | |
1996 | 0000000, /* high ring base */\r | |
1997 | 0000001 /* go */\r | |
1998 | };\r | |
1999 | \r | |
2000 | t_stat tq_boot (int32 unitno, DEVICE *dptr)\r | |
2001 | {\r | |
2002 | int32 i;\r | |
2003 | extern int32 saved_PC;\r | |
2004 | extern uint16 *M;\r | |
2005 | \r | |
2006 | for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r | |
2007 | M[BOOT_UNIT >> 1] = unitno & 3;\r | |
2008 | M[BOOT_CSR >> 1] = tq_dib.ba & DMASK;\r | |
2009 | saved_PC = BOOT_ENTRY;\r | |
2010 | return SCPE_OK;\r | |
2011 | }\r | |
2012 | \r | |
2013 | #else\r | |
2014 | \r | |
2015 | t_stat tq_boot (int32 unitno, DEVICE *dptr)\r | |
2016 | {\r | |
2017 | return SCPE_NOFNC;\r | |
2018 | }\r | |
2019 | \r | |
2020 | #endif\r | |
2021 | \r | |
2022 | /* Special show commands */\r | |
2023 | \r | |
2024 | void tq_show_ring (FILE *st, struct uq_ring *rp)\r | |
2025 | {\r | |
2026 | uint32 i, desc;\r | |
2027 | uint16 d[2];\r | |
2028 | \r | |
2029 | #if defined (VM_PDP11)\r | |
2030 | fprintf (st, "ring, base = %o, index = %d, length = %d\n",\r | |
2031 | rp->ba, rp->idx >> 2, rp->lnt >> 2);\r | |
2032 | #else\r | |
2033 | fprintf (st, "ring, base = %x, index = %d, length = %d\n",\r | |
2034 | rp->ba, rp->idx >> 2, rp->lnt >> 2);\r | |
2035 | #endif\r | |
2036 | for (i = 0; i < (rp->lnt >> 2); i++) {\r | |
2037 | if (Map_ReadW (rp->ba + (i << 2), 4, d)) {\r | |
2038 | fprintf (st, " %3d: non-existent memory\n", i);\r | |
2039 | break;\r | |
2040 | }\r | |
2041 | desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);\r | |
2042 | #if defined (VM_PDP11)\r | |
2043 | fprintf (st, " %3d: %011o\n", i, desc);\r | |
2044 | #else\r | |
2045 | fprintf (st, " %3d: %08x\n", i, desc);\r | |
2046 | #endif\r | |
2047 | }\r | |
2048 | return;\r | |
2049 | }\r | |
2050 | \r | |
2051 | void tq_show_pkt (FILE *st, int32 pkt)\r | |
2052 | {\r | |
2053 | int32 i, j;\r | |
2054 | uint32 cr = GETP (pkt, UQ_HCTC, CR);\r | |
2055 | uint32 typ = GETP (pkt, UQ_HCTC, TYP);\r | |
2056 | uint32 cid = GETP (pkt, UQ_HCTC, CID);\r | |
2057 | \r | |
2058 | fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n",\r | |
2059 | pkt, cr, typ, cid);\r | |
2060 | for (i = 0; i < TQ_SH_MAX; i = i + TQ_SH_PPL) {\r | |
2061 | fprintf (st, " %2d:", i);\r | |
2062 | for (j = i; j < (i + TQ_SH_PPL); j++)\r | |
2063 | #if defined (VM_PDP11)\r | |
2064 | fprintf (st, " %06o", tq_pkt[pkt].d[j]);\r | |
2065 | #else\r | |
2066 | fprintf (st, " %04x", tq_pkt[pkt].d[j]);\r | |
2067 | #endif\r | |
2068 | fprintf (st, "\n");\r | |
2069 | }\r | |
2070 | return;\r | |
2071 | }\r | |
2072 | \r | |
2073 | t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
2074 | {\r | |
2075 | int32 pkt, u = uptr - tq_dev.units;\r | |
2076 | \r | |
2077 | if (tq_csta != CST_UP) {\r | |
2078 | fprintf (st, "Controller is not initialized\n");\r | |
2079 | return SCPE_OK;\r | |
2080 | }\r | |
2081 | if ((uptr->flags & UNIT_ONL) == 0) {\r | |
2082 | if (uptr->flags & UNIT_ATT)\r | |
2083 | fprintf (st, "Unit %d is available\n", u);\r | |
2084 | else fprintf (st, "Unit %d is offline\n", u);\r | |
2085 | return SCPE_OK;\r | |
2086 | }\r | |
2087 | if (uptr->cpkt) {\r | |
2088 | fprintf (st, "Unit %d current ", u);\r | |
2089 | tq_show_pkt (st, uptr->cpkt);\r | |
2090 | if (pkt = uptr->pktq) {\r | |
2091 | do {\r | |
2092 | fprintf (st, "Unit %d queued ", u);\r | |
2093 | tq_show_pkt (st, pkt);\r | |
2094 | } while (pkt = tq_pkt[pkt].link);\r | |
2095 | }\r | |
2096 | }\r | |
2097 | else fprintf (st, "Unit %d queues are empty\n", u);\r | |
2098 | return SCPE_OK;\r | |
2099 | }\r | |
2100 | \r | |
2101 | t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
2102 | {\r | |
2103 | int32 i, pkt;\r | |
2104 | \r | |
2105 | if (tq_csta != CST_UP) {\r | |
2106 | fprintf (st, "Controller is not initialized\n");\r | |
2107 | return SCPE_OK;\r | |
2108 | }\r | |
2109 | if (val & TQ_SH_RI) {\r | |
2110 | if (tq_pip) fprintf (st, "Polling in progress, host timer = %d\n", tq_hat);\r | |
2111 | else fprintf (st, "Host timer = %d\n", tq_hat);\r | |
2112 | fprintf (st, "Command ");\r | |
2113 | tq_show_ring (st, &tq_cq);\r | |
2114 | fprintf (st, "Response ");\r | |
2115 | tq_show_ring (st, &tq_rq);\r | |
2116 | }\r | |
2117 | if (val & TQ_SH_FR) {\r | |
2118 | if (pkt = tq_freq) {\r | |
2119 | for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) {\r | |
2120 | if (i == 0) fprintf (st, "Free queue = %d", pkt);\r | |
2121 | else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt);\r | |
2122 | else fprintf (st, ", %d", pkt);\r | |
2123 | }\r | |
2124 | fprintf (st, "\n");\r | |
2125 | }\r | |
2126 | else fprintf (st, "Free queue is empty\n");\r | |
2127 | }\r | |
2128 | if (val & TQ_SH_RS) {\r | |
2129 | if (pkt = tq_rspq) {\r | |
2130 | do {\r | |
2131 | fprintf (st, "Response ");\r | |
2132 | tq_show_pkt (st, pkt);\r | |
2133 | } while (pkt = tq_pkt[pkt].link);\r | |
2134 | }\r | |
2135 | else fprintf (st, "Response queue is empty\n");\r | |
2136 | }\r | |
2137 | if (val & TQ_SH_UN) {\r | |
2138 | for (i = 0; i < TQ_NUMDR; i++)\r | |
2139 | tq_show_unitq (st, &tq_unit[i], 0, NULL);\r | |
2140 | }\r | |
2141 | return SCPE_OK;\r | |
2142 | }\r | |
2143 | \r | |
2144 | /* Set controller type (and capacity for user-defined type) */\r | |
2145 | \r | |
2146 | t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
2147 | {\r | |
2148 | uint32 i, cap;\r | |
2149 | uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC;\r | |
2150 | t_stat r;\r | |
2151 | \r | |
2152 | if ((val < 0) || (val > TQU_TYPE) || ((val != TQU_TYPE) && cptr))\r | |
2153 | return SCPE_ARG;\r | |
2154 | for (i = 0; i < TQ_NUMDR; i++) {\r | |
2155 | if (tq_unit[i].flags & UNIT_ATT) return SCPE_ALATT;\r | |
2156 | }\r | |
2157 | if (cptr) {\r | |
2158 | cap = (uint32) get_uint (cptr, 10, max, &r);\r | |
2159 | if ((r != SCPE_OK) || (cap < TQU_MINC)) return SCPE_ARG;\r | |
2160 | drv_tab[TQU_TYPE].cap = ((t_addr) cap) << 20;\r | |
2161 | }\r | |
2162 | tq_typ = val;\r | |
2163 | for (i = 0; i < TQ_NUMDR; i++)\r | |
2164 | tq_unit[i].capac = drv_tab[tq_typ].cap;\r | |
2165 | return SCPE_OK;\r | |
2166 | }\r | |
2167 | \r | |
2168 | /* Show controller type and capacity */\r | |
2169 | \r | |
2170 | t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
2171 | {\r | |
2172 | fprintf (st, "%s (%dMB)", drv_tab[tq_typ].name, (uint32) (drv_tab[tq_typ].cap >> 20));\r | |
2173 | return SCPE_OK;\r | |
2174 | }\r |