First Commit of my working state
[simh.git] / I7094 / i7094_io.c
CommitLineData
196ba1fc
PH
1/* i7094_io.c: IBM 7094 I/O subsystem (channels)\r
2\r
3 Copyright (c) 2003-2006, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 chana..chanh I/O channels\r
27\r
28 Notes on channels and CTSS.\r
29\r
30 - CTSS B-core is supported by the addition of a 16th bit to the current\r
31 address field of the channel command. Both the channel location counter\r
32 and the channel current address register are widened to 16b. Thus,\r
33 channel programs can run in B-core, and channel transfers can access B-core.\r
34 CTSS assumes that a channel command which starts a transfer in B-core\r
35 will not access A-core; the 16th bit does not increment.\r
36 - The channel start commands (RCHx and LCHx) incorporate the A-core/B-core\r
37 select as part of effective address generation. CTSS does not relocate\r
38 RCHx and LCHx target addresses; because the relocation indicator is\r
39 always zero, it's impossible to tell whether the protection indicator\r
40 affects address generation.\r
41 - The CTSS protection RPQ does not cover channel operations. Thus, CTSS\r
42 must inspect and vet all channel programs initiated by user mode programs,\r
43 notably the background processor FMS. CTSS inspects in-progress 7607\r
44 channel programs to make sure than either the nostore bit or the B-core\r
45 bit is set; thus, SCHx must store all 16b of the current address.\r
46*/\r
47\r
48#include "i7094_defs.h"\r
49\r
50#define CHAMASK ((cpu_model & I_CT)? PAMASK: AMASK) /* chan addr mask */\r
51#define CHAINC(x) (((x) & ~AMASK) | (((x) + 1) & AMASK))\r
52\r
53typedef struct {\r
54 char *name;\r
55 uint32 flags;\r
56 } DEV_CHAR;\r
57\r
58uint32 ch_sta[NUM_CHAN]; /* channel state */\r
59uint32 ch_dso[NUM_CHAN]; /* data select op */\r
60uint32 ch_dsu[NUM_CHAN]; /* data select unit */\r
61uint32 ch_ndso[NUM_CHAN]; /* non-data select op */\r
62uint32 ch_ndsu[NUM_CHAN]; /* non-data select unit */\r
63uint32 ch_flags[NUM_CHAN]; /* flags */\r
64uint32 ch_clc[NUM_CHAN]; /* chan loc ctr */\r
65uint32 ch_op[NUM_CHAN]; /* channel op */\r
66uint32 ch_wc[NUM_CHAN]; /* word count */\r
67uint32 ch_ca[NUM_CHAN]; /* core address */\r
68uint32 ch_lcc[NUM_CHAN]; /* control cntr (7909) */\r
69uint32 ch_cnd[NUM_CHAN]; /* cond reg (7909) */\r
70uint32 ch_sms[NUM_CHAN]; /* cond mask reg (7909) */\r
71t_uint64 ch_ar[NUM_CHAN]; /* assembly register */\r
72uint32 ch_idf[NUM_CHAN]; /* channel input data flags */\r
73DEVICE *ch2dev[NUM_CHAN] = { NULL };\r
74uint32 ch_tpoll = 5; /* channel poll */\r
75\r
76extern t_uint64 *M;\r
77extern uint32 cpu_model, data_base;\r
78extern uint32 hst_ch;\r
79extern uint32 ch_req;\r
80extern uint32 chtr_inht, chtr_inhi, chtr_enab;\r
81extern uint32 ind_ioc;\r
82extern uint32 chtr_clk;\r
83extern DEVICE cdr_dev, cdp_dev;\r
84extern DEVICE lpt_dev;\r
85extern DEVICE mt_dev[NUM_CHAN];\r
86extern DEVICE drm_dev;\r
87extern DEVICE dsk_dev;\r
88extern DEVICE com_dev;\r
89extern int32 sim_brk_summ;\r
90\r
91t_stat ch_reset (DEVICE *dptr);\r
92t_stat ch6_svc (UNIT *uptr);\r
93t_stat ch_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc);\r
94t_stat ch_set_disable (UNIT *uptr, int32 val, char *cptr, void *desc);\r
95t_stat ch_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);\r
96DEVICE *ch_find_dev (uint32 ch, uint32 unit);\r
97t_stat ch6_sel (uint32 ch, uint32 sel, uint32 unit, uint32 sta);\r
98t_bool ch6_rd_putw (uint32 ch);\r
99t_stat ch6_wr_getw (uint32 ch, t_bool eorz);\r
100t_stat ch6_new_cmd (uint32 ch, t_bool ch_ld);\r
101t_stat ch6_ioxt (uint32 ch);\r
102void ch6_iosp_cclr (uint32 ch);\r
103t_stat ch9_new_cmd (uint32 ch);\r
104t_stat ch9_exec_cmd (uint32 ch, t_uint64 ir);\r
105t_stat ch9_sel (uint32 ch, uint32 sel);\r
106t_stat ch9_wr (uint32 ch, t_uint64 dat, uint32 fl);\r
107t_stat ch9_rd_putw (uint32 ch);\r
108t_stat ch9_wr_getw (uint32 ch);\r
109void ch9_eval_int (uint32 ch, uint32 iflags);\r
110DEVICE *ch_map_flags (uint32 ch, int32 fl);\r
111\r
112extern CTAB *sim_vm_cmd;\r
113extern t_stat ch_bkpt (uint32 ch, uint32 clc);\r
114\r
115const uint32 col_masks[12] = { /* row 9,8,..,0,11,12 */\r
116 00001, 00002, 00004,\r
117 00010, 00020, 00040,\r
118 00100, 00200, 00400,\r
119 01000, 02000, 04000\r
120 };\r
121\r
122const t_uint64 bit_masks[36] = {\r
123 0000000000001, 0000000000002, 0000000000004,\r
124 0000000000010, 0000000000020, 0000000000040,\r
125 0000000000100, 0000000000200, 0000000000400,\r
126 0000000001000, 0000000002000, 0000000004000,\r
127 0000000010000, 0000000020000, 0000000040000,\r
128 0000000100000, 0000000200000, 0000000400000,\r
129 0000001000000, 0000002000000, 0000004000000,\r
130 0000010000000, 0000020000000, 0000040000000,\r
131 0000100000000, 0000200000000, 0000400000000,\r
132 0001000000000, 0002000000000, 0004000000000,\r
133 0010000000000, 0020000000000, 0040000000000,\r
134 0100000000000, 0200000000000, 0400000000000\r
135 };\r
136\r
137const DEV_CHAR dev_table[] = {\r
138 { "729", 0 },\r
139 { "TAPE", 0 },\r
140 { "7289", DEV_7289 },\r
141 { "DRUM", DEV_7289 },\r
142 { "7631", DEV_7909|DEV_7631 },\r
143 { "FILE", DEV_7909|DEV_7631 },\r
144 { "7750", DEV_7909|DEV_7750 },\r
145 { "COMM", DEV_7909|DEV_7750 },\r
146 { NULL },\r
147 };\r
148\r
149const char *sel_name[] = {\r
150 "UNK", "RDS", "WRS", "SNS", "CTL", "FMT", "UNK", "UNK",\r
151 "WEF", "WBT", "BSR", "BSF", "REW", "RUN", "SDN", "UNK"\r
152 };\r
153\r
154/* Channel data structures */\r
155\r
156UNIT ch_unit[NUM_CHAN] = {\r
157 { UDATA (&ch6_svc, 0, 0) },\r
158 { UDATA (&ch6_svc, 0, 0) },\r
159 { UDATA (&ch6_svc, 0, 0) },\r
160 { UDATA (&ch6_svc, 0, 0) },\r
161 { UDATA (&ch6_svc, 0, 0) },\r
162 { UDATA (&ch6_svc, 0, 0) },\r
163 { UDATA (&ch6_svc, 0, 0) },\r
164 { UDATA (&ch6_svc, 0, 0) }\r
165 };\r
166\r
167MTAB ch_mod[] = {\r
168 { MTAB_XTD|MTAB_VDV, 0, "TYPE", NULL,\r
169 NULL, &ch_show_type, NULL },\r
170 { MTAB_XTD|MTAB_VDV, 0, NULL, "ENABLED",\r
171 &ch_set_enable, NULL, NULL },\r
172 { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED",\r
173 &ch_set_disable, NULL, NULL },\r
174 { 0 }\r
175 };\r
176\r
177REG cha_reg[] = {\r
178 { ORDATA (STA, ch_sta[CH_A], 8) },\r
179 { ORDATA (DSC, ch_dso[CH_A], 4) },\r
180 { ORDATA (DSU, ch_dsu[CH_A], 9) },\r
181 { ORDATA (NDSC, ch_ndso[CH_A], 4) },\r
182 { ORDATA (NDSU, ch_ndsu[CH_A], 9) },\r
183 { ORDATA (FLAGS, ch_flags[CH_A], 30) },\r
184 { ORDATA (IDF, ch_idf[CH_A], 2) },\r
185 { ORDATA (OP, ch_op[CH_A], 5) },\r
186 { ORDATA (CLC, ch_clc[CH_A], 16) },\r
187 { ORDATA (WC, ch_wc[CH_A], 15) },\r
188 { ORDATA (CA, ch_ca[CH_A], 16) },\r
189 { ORDATA (AR, ch_ar[CH_A], 36) },\r
190 { ORDATA (CND, ch_cnd[CH_A], 6), REG_HRO },\r
191 { ORDATA (LCC, ch_lcc[CH_A], 6), REG_HRO },\r
192 { ORDATA (SMS, ch_sms[CH_A], 7), REG_HRO },\r
193 { 0 }\r
194 };\r
195\r
196REG chb_reg[] = {\r
197 { ORDATA (STATE, ch_sta[CH_B], 8) },\r
198 { ORDATA (DSC, ch_dso[CH_B], 4) },\r
199 { ORDATA (DSU, ch_dsu[CH_B], 9) },\r
200 { ORDATA (NDSC, ch_ndso[CH_B], 4) },\r
201 { ORDATA (NDSU, ch_ndsu[CH_B], 9) },\r
202 { ORDATA (FLAGS, ch_flags[CH_B], 30) },\r
203 { ORDATA (IDF, ch_idf[CH_B], 2) },\r
204 { ORDATA (OP, ch_op[CH_B], 5) },\r
205 { ORDATA (CLC, ch_clc[CH_B], 16) },\r
206 { ORDATA (WC, ch_wc[CH_B], 15) },\r
207 { ORDATA (CA, ch_ca[CH_B], 16) },\r
208 { ORDATA (AR, ch_ar[CH_B], 36) },\r
209 { ORDATA (CND, ch_cnd[CH_B], 6) },\r
210 { ORDATA (LCC, ch_lcc[CH_B], 6) },\r
211 { ORDATA (SMS, ch_sms[CH_B], 7) },\r
212 { 0 }\r
213 };\r
214\r
215REG chc_reg[] = {\r
216 { ORDATA (STATE, ch_sta[CH_C], 8) },\r
217 { ORDATA (DSC, ch_dso[CH_C], 4) },\r
218 { ORDATA (DSU, ch_dsu[CH_C], 9) },\r
219 { ORDATA (NDSC, ch_ndso[CH_C], 4) },\r
220 { ORDATA (NDSU, ch_ndsu[CH_C], 9) },\r
221 { ORDATA (FLAGS, ch_flags[CH_C], 30) },\r
222 { ORDATA (IDF, ch_idf[CH_C], 2) },\r
223 { ORDATA (OP, ch_op[CH_C], 5) },\r
224 { ORDATA (CLC, ch_clc[CH_C], 16) },\r
225 { ORDATA (WC, ch_wc[CH_C], 15) },\r
226 { ORDATA (CA, ch_ca[CH_C], 16) },\r
227 { ORDATA (AR, ch_ar[CH_C], 36) },\r
228 { ORDATA (CND, ch_cnd[CH_C], 6) },\r
229 { ORDATA (LCC, ch_lcc[CH_C], 6) },\r
230 { ORDATA (SMS, ch_sms[CH_C], 7) },\r
231 { 0 }\r
232 };\r
233\r
234REG chd_reg[] = {\r
235 { ORDATA (STATE, ch_sta[CH_D], 8) },\r
236 { ORDATA (DSC, ch_dso[CH_D], 4) },\r
237 { ORDATA (DSU, ch_dsu[CH_D], 9) },\r
238 { ORDATA (NDSC, ch_ndso[CH_D], 4) },\r
239 { ORDATA (NDSU, ch_ndsu[CH_D], 9) },\r
240 { ORDATA (FLAGS, ch_flags[CH_D], 30) },\r
241 { ORDATA (IDF, ch_idf[CH_D], 2) },\r
242 { ORDATA (OP, ch_op[CH_D], 5) },\r
243 { ORDATA (CLC, ch_clc[CH_D], 16) },\r
244 { ORDATA (WC, ch_wc[CH_D], 15) },\r
245 { ORDATA (CA, ch_ca[CH_D], 16) },\r
246 { ORDATA (AR, ch_ar[CH_D], 36) },\r
247 { ORDATA (CND, ch_cnd[CH_D], 6) },\r
248 { ORDATA (LCC, ch_lcc[CH_D], 6) },\r
249 { ORDATA (SMS, ch_sms[CH_D], 7) },\r
250 { 0 }\r
251 };\r
252\r
253REG che_reg[] = {\r
254 { ORDATA (STATE, ch_sta[CH_E], 8) },\r
255 { ORDATA (DSC, ch_dso[CH_E], 4) },\r
256 { ORDATA (DSU, ch_dsu[CH_E], 9) },\r
257 { ORDATA (NDSC, ch_ndso[CH_E], 4) },\r
258 { ORDATA (NDSU, ch_ndsu[CH_E], 9) },\r
259 { ORDATA (FLAGS, ch_flags[CH_E], 30) },\r
260 { ORDATA (IDF, ch_idf[CH_E], 2) },\r
261 { ORDATA (OP, ch_op[CH_E], 5) },\r
262 { ORDATA (CLC, ch_clc[CH_E], 16) },\r
263 { ORDATA (WC, ch_wc[CH_E], 15) },\r
264 { ORDATA (CA, ch_ca[CH_E], 16) },\r
265 { ORDATA (AR, ch_ar[CH_E], 36) },\r
266 { ORDATA (CND, ch_cnd[CH_E], 6) },\r
267 { ORDATA (LCC, ch_lcc[CH_E], 6) },\r
268 { ORDATA (SMS, ch_sms[CH_E], 7) },\r
269 { 0 }\r
270 };\r
271\r
272REG chf_reg[] = {\r
273 { ORDATA (STATE, ch_sta[CH_F], 8) },\r
274 { ORDATA (DSC, ch_dso[CH_F], 4) },\r
275 { ORDATA (DSU, ch_dsu[CH_F], 9) },\r
276 { ORDATA (NDSC, ch_ndso[CH_F], 4) },\r
277 { ORDATA (NDSU, ch_ndsu[CH_F], 9) },\r
278 { ORDATA (FLAGS, ch_flags[CH_F], 30) },\r
279 { ORDATA (IDF, ch_idf[CH_F], 2) },\r
280 { ORDATA (OP, ch_op[CH_F], 5) },\r
281 { ORDATA (CLC, ch_clc[CH_F], 16) },\r
282 { ORDATA (WC, ch_wc[CH_F], 15) },\r
283 { ORDATA (CA, ch_ca[CH_F], 16) },\r
284 { ORDATA (AR, ch_ar[CH_F], 36) },\r
285 { ORDATA (CND, ch_cnd[CH_F], 6) },\r
286 { ORDATA (LCC, ch_lcc[CH_F], 6) },\r
287 { ORDATA (SMS, ch_sms[CH_F], 7) },\r
288 { 0 }\r
289 };\r
290\r
291REG chg_reg[] = {\r
292 { ORDATA (STATE, ch_sta[CH_G], 8) },\r
293 { ORDATA (DSC, ch_dso[CH_G], 4) },\r
294 { ORDATA (DSU, ch_dsu[CH_G], 9) },\r
295 { ORDATA (NDSC, ch_ndso[CH_G], 4) },\r
296 { ORDATA (NDSU, ch_ndsu[CH_G], 9) },\r
297 { ORDATA (FLAGS, ch_flags[CH_G], 30) },\r
298 { ORDATA (IDF, ch_idf[CH_G], 2) },\r
299 { ORDATA (OP, ch_op[CH_G], 5) },\r
300 { ORDATA (CLC, ch_clc[CH_G], 16) },\r
301 { ORDATA (WC, ch_wc[CH_G], 15) },\r
302 { ORDATA (CA, ch_ca[CH_G], 16) },\r
303 { ORDATA (AR, ch_ar[CH_G], 36) },\r
304 { ORDATA (CND, ch_cnd[CH_G], 6) },\r
305 { ORDATA (LCC, ch_lcc[CH_G], 6) },\r
306 { ORDATA (SMS, ch_sms[CH_G], 7) },\r
307 { 0 }\r
308 };\r
309\r
310REG chh_reg[] = {\r
311 { ORDATA (STATE, ch_sta[CH_H], 8) },\r
312 { ORDATA (DSC, ch_dso[CH_H], 4) },\r
313 { ORDATA (DSU, ch_dsu[CH_H], 9) },\r
314 { ORDATA (NDSC, ch_ndso[CH_H], 4) },\r
315 { ORDATA (NDSU, ch_ndsu[CH_H],9) },\r
316 { ORDATA (FLAGS, ch_flags[CH_H], 30) },\r
317 { ORDATA (IDF, ch_idf[CH_H], 2) },\r
318 { ORDATA (OP, ch_op[CH_H], 5) },\r
319 { ORDATA (CLC, ch_clc[CH_H], 16) },\r
320 { ORDATA (WC, ch_wc[CH_H], 15) },\r
321 { ORDATA (CA, ch_ca[CH_H], 16) },\r
322 { ORDATA (AR, ch_ar[CH_H], 36) },\r
323 { ORDATA (CND, ch_cnd[CH_H], 6) },\r
324 { ORDATA (LCC, ch_lcc[CH_H], 6) },\r
325 { ORDATA (SMS, ch_sms[CH_H], 7) },\r
326 { 0 }\r
327 };\r
328\r
329DEVICE ch_dev[NUM_CHAN] = {\r
330 {\r
331 "CHANA", &ch_unit[CH_A], cha_reg, ch_mod,\r
332 1, 8, 8, 1, 8, 8,\r
333 NULL, NULL, &ch_reset,\r
334 NULL, NULL, NULL,\r
335 NULL, 0\r
336 },\r
337 {\r
338 "CHANB", &ch_unit[CH_B], chb_reg, ch_mod,\r
339 1, 8, 8, 1, 8, 8,\r
340 NULL, NULL, &ch_reset,\r
341 NULL, NULL, NULL,\r
342 NULL, DEV_DISABLE | DEV_DIS\r
343 },\r
344 {\r
345 "CHANC", &ch_unit[CH_C], chc_reg, ch_mod,\r
346 1, 8, 8, 1, 8, 8,\r
347 NULL, NULL, &ch_reset,\r
348 NULL, NULL, NULL,\r
349 NULL, DEV_DISABLE | DEV_DIS\r
350 },\r
351 {\r
352 "CHAND", &ch_unit[CH_D], chd_reg, ch_mod,\r
353 1, 8, 8, 1, 8, 8,\r
354 NULL, NULL, &ch_reset,\r
355 NULL, NULL, NULL,\r
356 NULL, DEV_DISABLE | DEV_DIS\r
357 },\r
358 {\r
359 "CHANE", &ch_unit[CH_E], che_reg, ch_mod,\r
360 1, 8, 8, 1, 8, 8,\r
361 NULL, NULL, &ch_reset,\r
362 NULL, NULL, NULL,\r
363 NULL, DEV_DISABLE | DEV_DIS\r
364 },\r
365 {\r
366 "CHANF", &ch_unit[CH_F], chf_reg, ch_mod,\r
367 1, 8, 8, 1, 8, 8,\r
368 NULL, NULL, &ch_reset,\r
369 NULL, NULL, NULL,\r
370 NULL, DEV_DISABLE | DEV_DIS\r
371 },\r
372 {\r
373 "CHANG", &ch_unit[CH_G], chg_reg, ch_mod,\r
374 1, 8, 8, 1, 8, 8,\r
375 NULL, NULL, &ch_reset,\r
376 NULL, NULL, NULL,\r
377 NULL, DEV_DISABLE | DEV_DIS\r
378 },\r
379 {\r
380 "CHANH", &ch_unit[CH_H], chh_reg, ch_mod,\r
381 1, 8, 8, 1, 8, 8,\r
382 NULL, NULL, &ch_reset,\r
383 NULL, NULL, NULL,\r
384 NULL, DEV_DISABLE | DEV_DIS\r
385 }\r
386 };\r
387\r
388/* 7607 channel overview\r
389\r
390 Channel variables:\r
391\r
392 ch_sta channel state\r
393 ch_dso, ch_dsu operation and unit for current data select\r
394 ch_ndso, ch_ndsu operation and unit for current non-data select\r
395 ch_clc current location counter\r
396 ch_ca memory addres\r
397 ch_wc word count\r
398 ch_op channel opcode (bits <S,1:2,19>)\r
399 ch_flags channel flags\r
400\r
401 States of a channel\r
402\r
403 IDLE - channel is not in operation\r
404\r
405 RDS, WDS: -> DSW if device is idle, schedule device\r
406 device timeout drives next transition\r
407 -> stall if device is busy\r
408 repeat until device is idle\r
409 other I/O: -> NDS if device is idle, schedule device\r
410 device timeout drives next transition\r
411 -> stall if device is busy\r
412 repeat until device is idle\r
413 chan reset: -> IDLE \r
414\r
415 PDS (PNDS) - channel is polling device to start data (non-data) select\r
416\r
417 chan timeout: -> DSW (NDS) if device is idle\r
418 device timeout drives next transition\r
419 -> no change if device is busy, schedule channel\r
420 chan reset: -> IDLE \r
421 \r
422 DSW - channel is waiting for channel start command\r
423 \r
424 dev timeout: -> IDLE if no stacked non-data select\r
425 -> PNDS if stacked non-data select\r
426 channel timeout drives next transition\r
427 start chan: -> DSX if chan program transfers data\r
428 device timeout drives next transition\r
429 -> IDLE if channel disconnects, no stacked NDS\r
430 -> PNDS if channel disconnects, stacked NDS\r
431 channel timeout drives next transition\r
432 chan reset: -> IDLE \r
433 \r
434 DSX - channel is executing data select\r
435 \r
436 dev timeout: -> DSX if transfer not complete, reschedule device\r
437 device timeout drives next transition\r
438 -> DSW if channel command completes, CHF_LDW set\r
439 -> IDLE if transfer complete, no stacked NDS, or\r
440 if channel command completes, CHF_LDW clear\r
441 -> PNDS if channel disconnects, stacked NDS\r
442 channel timeout drives next transition\r
443 start chan: -> DSX with CHF_LDW, CPU stall\r
444 chan reset: -> IDLE \r
445\r
446 NDS - channel is executing non-data select\r
447 \r
448 dev timeout: -> IDLE if transfer complete, no stacked DS\r
449 -> PDS if channel disconnects, stacked DS\r
450 channel timeout drives next transition\r
451 chan reset: -> IDLE\r
452\r
453 The channel has two interfaces to a device. The select routine:\r
454\r
455 dev_select (uint32 ch, uint32 sel, uint32 unit)\r
456\r
457 Returns can include device errors and ERR_STALL. If ERR_STALL, the\r
458 device is busy. For I/O instructions, ERR_STALL stalls execution of\r
459 the instruction until the device is not busy. For stacked command\r
460 polls, ERR_STALL causes the poll to be repeated after a delay.\r
461\r
462 The device write routine is used to place output data in the device\r
463 write buffer.\r
464\r
465 Channel transfers are driven by the channel. When a device needs to\r
466 read or write data, it sets a channel request in ch_req. The channel\r
467 process transfers the data and updates channel control parameters\r
468 accordingly. Note that the channel may disconnect; in this case, the\r
469 transfer completes 'correctly' from the point of view of the device.\r
470\r
471 The channel transfer commands (IOxT) require the channel to 'hold'\r
472 a new channel command in anticipation of the current transfer. If\r
473 the channel is currently executing (CH6S_DSX) and a channel start\r
474 is issued by the CPU, a 'start pending' flag is set and the CPU is\r
475 stalled. When the channel reaches the end of an IOxT command, it\r
476 checks the 'start pending' flag. If the flag is set, the channel\r
477 sets itself to waiting and then requeues itself for one cycle later.\r
478 The CPU tries the channel start, sees that the channel is waiting,\r
479 and issues the new channel command.\r
480\r
481 state op device channel\r
482\r
483 IDLE RDS,WDS start I/O ->DSW\r
484\r
485 DSW LCHx (timed wait) ->DSX\r
486\r
487 DSX -- timeout, req svc\r
488 (timed wait) transfer word\r
489 timeout, req svc\r
490 (timed wait)\r
491 LCHx, stalls :\r
492 timeout, EOR/EOC IOxT: ->DSW, resched\r
493 DSW LCHx (timed wait) ->DSX, etc \r
494\r
495 7909 channel overview\r
496\r
497 Channel variables:\r
498\r
499 ch_sta channel state\r
500 ch_clc current location counter\r
501 ch_ca memory addres\r
502 ch_wc word count\r
503 ch_op channel opcode (bits <S,1:3,19>)\r
504 ch_sms status mask\r
505 ch_cond interrupt conditions\r
506 ch_lcc control counter\r
507 ch_flags channel flags\r
508\r
509 States of a channel\r
510\r
511 IDLE - channel is not in operation\r
512\r
513 RDCx, SDCx, interrupt -> DSX\r
514\r
515 DSX - channel is executing data select\r
516\r
517 TWT, WTR -> IDLE\r
518\r
519 The 7909 is more capable than the 7607 but also simpler in some ways.\r
520 It has many more instructions, built in counters and status checking,\r
521 and interrupts. But it has only two states and no concept of records.\r
522\r
523 The 7909 read process is driven by the device:\r
524\r
525 channel CTLR/SNS: send select\r
526 device: schedule timeout\r
527 device timeout: device to AR, request channel\r
528 channel: AR to memory\r
529 device timeout: device to AR, request channel\r
530 channel: AR to memory\r
531 :\r
532 device timeout: set end, request channel\r
533 channel: disconnect on CPYD, send STOP\r
534\r
535 The 7909 write process is also driven by the device:\r
536\r
537 channel CTL/CTLW: send select\r
538 device: schedule timeout, request channel\r
539 channel: memory to output buffer\r
540 device timeout: output buffer to device, request channel\r
541 channel: memory to output buffer\r
542 device timeout: output buffer to device, request channel\r
543 :\r
544 channel: memory to output buffer\r
545 device timeout: output buffer to device, set end, request channel\r
546 channel: disconnect on CPYD, send STOP\r
547\r
548 For both reads and writes, devices must implement an 'interblock' or\r
549 'interrecord' state that is long enough for the channel to see the \r
550 end, disconnect, and send a stop signal.\r
551*/\r
552\r
553/* Data select - called by RDS or WDS instructions - 7607/7289 only\r
554\r
555 - Channel is from address and has been corrected\r
556 - Channel must be an enabled 7607\r
557 - If data select already in use, stall CPU\r
558 - If non-data select is a write end-of-file, stall CPU\r
559 - If channel is busy, stack command\r
560 - Otherwise, start IO, set channel to waiting */\r
561\r
562t_stat ch_op_ds (uint32 ch, uint32 ds, uint32 unit)\r
563{\r
564t_stat r;\r
565\r
566if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid arg? */\r
567if (ch_dev[ch].flags & DEV_DIS) return STOP_NXCHN; /* disabled? stop */\r
568if (ch_dev[ch].flags & DEV_7909) return STOP_7909; /* 7909? stop */\r
569if (ch_dso[ch]) return ERR_STALL; /* DS in use? */\r
570if (ch_ndso[ch] == CHSL_WEF) return ERR_STALL; /* NDS = WEF? */\r
571if (ch_sta[ch] == CHXS_IDLE) { /* chan idle? */\r
572 r = ch6_sel (ch, ds, unit, CH6S_DSW); /* select device */\r
573 if (r != SCPE_OK) return r;\r
574 }\r
575ch_dso[ch] = ds; /* set command, unit */\r
576ch_dsu[ch] = unit;\r
577ch_flags[ch] &= ~(CHF_LDW|CHF_EOR|CHF_CMD); /* clear flags */\r
578ch_idf[ch] = 0;\r
579return SCPE_OK;\r
580}\r
581\r
582/* Non-data select - called by BSR, BSF, WEF, REW, RUN, SDS instructions - 7607 only\r
583\r
584 - Channel is from address and has been corrected\r
585 - Channel must be an enabled 7607\r
586 - If non-data select already in use, stall CPU\r
587 - If data select is card or printer, stall CPU\r
588 - If channel is busy, stack command\r
589 - Otherwise, start IO, set channel to waiting */\r
590\r
591t_stat ch_op_nds (uint32 ch, uint32 nds, uint32 unit)\r
592{\r
593DEVICE *dptr;\r
594t_stat r;\r
595\r
596if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid arg? */\r
597if (ch_dev[ch].flags & DEV_DIS) return STOP_NXCHN; /* disabled? stop */\r
598if (ch_dev[ch].flags & DEV_7909) return STOP_7909; /* 7909? stop */\r
599if (ch_ndso[ch]) return ERR_STALL; /* NDS in use? */\r
600if (ch_dso[ch] && (dptr = ch_find_dev (ch, ch_dsu[ch])) /* DS, cd or lpt? */\r
601 && (dptr->flags & DEV_CDLP)) return ERR_STALL;\r
602if (ch_sta[ch] == CHXS_IDLE) { /* chan idle? */\r
603 r = ch6_sel (ch, nds, unit, CH6S_NDS); /* select device */\r
604 if (r != SCPE_OK) return r;\r
605 }\r
606ch_ndso[ch] = nds; /* set command, unit */\r
607ch_ndsu[ch] = unit;\r
608return SCPE_OK;\r
609}\r
610\r
611/* End of data select - called from channel - 7607/7289 only\r
612\r
613 - If executing, set command trap flag\r
614 - Set channel idle\r
615 - If stacked nds, set up immediate channel timeout */\r
616\r
617t_stat ch6_end_ds (uint32 ch)\r
618{\r
619if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid arg? */\r
620ch_dso[ch] = ch_dsu[ch] = 0; /* no data select */\r
621if (ch_ndso[ch]) { /* stacked non-data sel? */\r
622 sim_activate (ch_dev[ch].units, 0); /* immediate poll */\r
623 ch_sta[ch] = CH6S_PNDS; /* state = polling */\r
624 }\r
625else ch_sta[ch] = CHXS_IDLE; /* else state = idle */\r
626return SCPE_OK;\r
627}\r
628\r
629/* End of non-data select - called from I/O device completion - 7607/7289 only\r
630\r
631 - Set channel idle\r
632 - If stacked ds, set up immediate channel timeout */\r
633\r
634t_stat ch6_end_nds (uint32 ch)\r
635{\r
636if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid arg? */\r
637ch_ndso[ch] = ch_ndsu[ch] = 0; /* no non-data select */\r
638if (ch_dso[ch]) { /* stacked data sel? */\r
639 sim_activate (ch_dev[ch].units, 0); /* immediate poll */\r
640 ch_sta[ch] = CH6S_PDS; /* state = polling */\r
641 }\r
642else ch_sta[ch] = CHXS_IDLE; /* else state = idle */\r
643return SCPE_OK;\r
644}\r
645\r
646/* Send select to device - 7607/7289 only */\r
647\r
648t_stat ch6_sel (uint32 ch, uint32 sel, uint32 unit, uint32 sta)\r
649{\r
650DEVICE *dptr;\r
651DIB *dibp;\r
652t_stat r;\r
653\r
654if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid arg? */\r
655dptr = ch_find_dev (ch, unit); /* find device */\r
656if (dptr == NULL) return STOP_NXDEV; /* invalid device? */\r
657dibp = (DIB *) dptr->ctxt;\r
658r = dibp->chsel (ch, sel, unit); /* select device */\r
659if (r == SCPE_OK) ch_sta[ch] = sta; /* set status */\r
660return r;\r
661}\r
662\r
663/* Channel unit service - called to start stacked command - 7607 only */\r
664\r
665t_stat ch6_svc (UNIT *uptr)\r
666{\r
667uint32 ch = uptr - &ch_unit[0]; /* get channel */\r
668t_stat r;\r
669\r
670if (ch >= NUM_CHAN) return SCPE_IERR; /* invalid chan? */\r
671switch (ch_sta[ch]) { /* case on state */\r
672\r
673 case CH6S_PDS: /* polling for ds */\r
674 r = ch6_sel (ch, ch_dso[ch], ch_dsu[ch], CH6S_DSW);\r
675 break;\r
676\r
677 case CH6S_PNDS: /* polling for nds */\r
678 r = ch6_sel (ch, ch_ndso[ch], ch_ndsu[ch], CH6S_NDS);\r
679 break;\r
680\r
681 default:\r
682 return SCPE_OK;\r
683 }\r
684\r
685if (r == ERR_STALL) { /* stalled? */\r
686 sim_activate (uptr, ch_tpoll); /* continue poll */\r
687 return SCPE_OK;\r
688 }\r
689return r;\r
690}\r
691\r
692/* Map channel and unit number to device - all channels */\r
693\r
694DEVICE *ch_find_dev (uint32 ch, uint32 unit)\r
695{\r
696if (ch >= NUM_CHAN) return NULL; /* invalid arg? */\r
697if (ch_dev[ch].flags & (DEV_7909|DEV_7289)) return ch2dev[ch];\r
698unit = unit & 0777;\r
699if (((unit >= U_MTBCD) && (unit <= (U_MTBCD + MT_NUMDR))) ||\r
700 ((unit >= U_MTBIN) && (unit <= (U_MTBIN + MT_NUMDR))))\r
701 return ch2dev[ch];\r
702if (ch != 0) return NULL;\r
703if (unit == U_CDR) return &cdr_dev;\r
704if (unit == U_CDP) return &cdp_dev;\r
705if ((unit == U_LPBCD) || (unit == U_LPBIN)) return &lpt_dev;\r
706return NULL;\r
707}\r
708\r
709/* Start channel - channel is from opcode\r
710\r
711 7607: channel should have a data select operation pending (DSW state)\r
712 7909: channel should be idle (IDLE state) */\r
713\r
714t_stat ch_op_start (uint32 ch, uint32 clc, t_bool reset)\r
715{\r
716t_uint64 ir;\r
717t_stat r;\r
718\r
719clc = clc | data_base; /* add A/B select */\r
720if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid argument? */\r
721if (ch_dev[ch].flags & DEV_DIS) return STOP_NXCHN; /* disabled? stop */\r
722if (ch_dev[ch].flags & DEV_7909) { /* 7909? */\r
723 if (ch_sta[ch] != CHXS_IDLE) return ERR_STALL; /* must be idle */\r
724 if (reset) { /* RDCx? */\r
725 ch_cnd[ch] = 0; /* clear conditions */\r
726 ch_clc[ch] = clc; /* set clc */\r
727 }\r
728 else { /* SDCx */\r
729 if (BIT_TST (chtr_enab, CHTR_V_TWT + ch) && /* pending trap? */\r
730 (ch_flags[ch] & CHF_TWT)) return ERR_STALL;\r
731 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* finish WTR, TWT */\r
732 }\r
733 ch_flags[ch] &= ~CHF_CLR_7909; /* clear flags, not IP */\r
734 ch_idf[ch] = 0;\r
735 ch_sta[ch] = CHXS_DSX; /* set state */\r
736 return ch9_new_cmd (ch); /* start executing */\r
737 }\r
738 /* 7607, 7289 */\r
739if (reset) { /* reset? */\r
740 if (ch_sta[ch] == CHXS_DSX) ch_sta[ch] = CH6S_DSW;\r
741 ch_flags[ch] &= ~(CHF_LDW|CHF_EOR|CHF_TRC|CHF_CMD);\r
742 ch_idf[ch] = 0;\r
743 }\r
744\r
745switch (ch_sta[ch]) { /* case on chan state */\r
746\r
747 case CHXS_IDLE: /* idle */\r
748 ind_ioc = 1; /* IO check */\r
749 ir = ReadP (clc); /* get chan word */\r
750 ch_clc[ch] = CHAINC (clc); /* incr chan pc */\r
751 ch_wc[ch] = GET_DEC (ir); /* get word cnt */\r
752 ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */\r
753 ch_op[ch] = (GET_OPD (ir) << 1) | /* get opcode */\r
754 ((((uint32) ir) & CH6I_NST)? 1: 0); /* plus 'no store' */\r
755 break;\r
756\r
757 case CH6S_PNDS: /* NDS polling */\r
758 case CH6S_PDS: /* DS polling */\r
759 case CH6S_NDS: /* NDS executing */\r
760 return ERR_STALL; /* wait it out */\r
761\r
762 case CH6S_DSW: /* expecting command */\r
763 ch_sta[ch] = CHXS_DSX; /* update state */\r
764 if (ch_dev[ch].flags & DEV_7289) { /* drum channel? */\r
765 ir = ReadP (clc); /* read addr */\r
766 ch_clc[ch] = CHAINC (clc); /* incr chan pc */\r
767 if (r = ch9_wr (ch, ir, 0)) return r; /* write to dev */\r
768 }\r
769 else ch_clc[ch] = clc; /* set clc */\r
770 return ch6_new_cmd (ch, TRUE); /* start channel */\r
771\r
772 case CHXS_DSX: /* executing */\r
773 ch_flags[ch] = ch_flags[ch] | CHF_LDW; /* flag pending LCH */\r
774 return ERR_STALL; /* stall */\r
775 }\r
776\r
777return SCPE_OK;\r
778}\r
779\r
780/* Store channel \r
781\r
782 7607/7289 stores op,ca,nostore,clc\r
783 7909 stores clc,,ca */\r
784\r
785t_stat ch_op_store (uint32 ch, t_uint64 *dat)\r
786{\r
787if ((ch >= NUM_CHAN) || (ch_dev[ch].flags & DEV_DIS)) return STOP_NXCHN;\r
788if (ch_dev[ch].flags & DEV_7909)\r
789 *dat = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) |\r
790 (((t_uint64) ch_clc[ch] & CHAMASK) << INST_V_ADDR);\r
791else *dat = (((t_uint64) ch_clc[ch] & CHAMASK) << INST_V_DEC) |\r
792 (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_ADDR) |\r
793 (((t_uint64) (ch_op[ch] & 1)) << 16) |\r
794 (((t_uint64) (ch_op[ch] & 016)) << 32);\r
795return SCPE_OK;\r
796}\r
797\r
798/* Store channel diagnostic \r
799\r
800 7607 is undefined\r
801 7289 stores IOC+???\r
802 7909 stores 7909 lcc+flags */\r
803\r
804t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat)\r
805{\r
806if ((ch >= NUM_CHAN) || (ch_dev[ch].flags & DEV_DIS)) return STOP_NXCHN;\r
807if (ch_flags[ch] & DEV_7289) *dat = ind_ioc? SIGN: 0;\r
808else if (ch_flags[ch] & DEV_7909) *dat =\r
809 (((t_uint64) (ch_lcc[ch] & CHF_M_LCC)) << CHF_V_LCC) | \r
810 (ch_flags[ch] & CHF_SDC_7909);\r
811else *dat = 0;\r
812return SCPE_OK;\r
813}\r
814\r
815/* Reset data channel \r
816\r
817 7607 responds to RDC\r
818 7909 responds to RIC */\r
819\r
820t_stat ch_op_reset (uint32 ch, t_bool ch7909)\r
821{\r
822DEVICE *dptr;\r
823\r
824if (ch >= NUM_CHAN) return STOP_NXCHN; /* invalid argument? */\r
825if (ch_dev[ch].flags & DEV_DIS) return SCPE_OK; /* disabled? ok */\r
826if (ch_dev[ch].flags & DEV_7909) { /* 7909? */\r
827 if (!ch7909) return SCPE_OK; /* wrong reset is NOP */\r
828 dptr = ch2dev[ch]; /* get device */\r
829 }\r
830else { /* 7607, 7289 */\r
831 if (ch7909) return STOP_NT7909; /* wrong reset is err */\r
832 dptr = ch_find_dev (ch, ch_ndsu[ch]); /* find device */\r
833 }\r
834ch_reset (&ch_dev[ch]); /* reset channel */\r
835if (dptr && dptr->reset) dptr->reset (dptr); /* reset device */\r
836return SCPE_OK;\r
837}\r
838\r
839/* Channel process - called from main CPU loop. If the channel is unable\r
840 to get a valid command, it will reschedule itself for the next cycle.\r
841\r
842 The read process is basically synchronous with the device timeout routine.\r
843 The device requests the channel and supplies the word to be stored in memory.\r
844 In the next time slot, the channel stores the word in memory. */\r
845\r
846t_stat ch_proc (uint32 ch)\r
847{\r
848t_stat r;\r
849\r
850if (ch >= NUM_CHAN) return SCPE_IERR; /* bad channel? */\r
851ch_req &= ~REQ_CH (ch); /* clear request */\r
852if (ch_dev[ch].flags & DEV_DIS) return SCPE_IERR; /* disabled? */\r
853if (ch_dev[ch].flags & DEV_7909) { /* 7909 */\r
854\r
855 t_uint64 sr;\r
856 uint32 csel, sc, tval, mask, ta;\r
857 t_bool xfr;\r
858\r
859 if (ch_flags[ch] & CHF_IRQ) { /* interrupt? */\r
860 ta = CHINT_CHA_SAV + (ch << 1); /* save location */\r
861 if (ch_sta[ch] == CHXS_IDLE) /* waiting? */\r
862 sr = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) |\r
863 ((t_uint64) ch_clc[ch] & CHAMASK); /* save CLC */\r
864 else sr = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) |\r
865 ((t_uint64) CHAINC (ch_clc[ch])); /* no, save CLC+1 */\r
866 ch_sta[ch] = CHXS_DSX; /* set running */\r
867 ch_flags[ch] = (ch_flags[ch] | CHF_INT) & /* set intr state */\r
868 ~(CHF_IRQ|CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS); /* clr flags */\r
869 WriteP (ta, sr); /* write ca,,clc */\r
870 sr = ReadP (ta + 1); /* get chan cmd */\r
871 return ch9_exec_cmd (ch, sr); /* exec cmd */\r
872 }\r
873\r
874 switch (ch_op[ch] & CH9_OPMASK) { /* switch on op */\r
875\r
876 case CH9_TWT: /* transfer of TWT */\r
877 case CH9_WTR: /* transfer of WTR */\r
878 case CH9_TCH: /* transfer */\r
879 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */\r
880 break;\r
881\r
882 case CH9_TDC: /* decr & transfer */\r
883 if (ch_lcc[ch] != 0) { /* counter != 0? */\r
884 ch_lcc[ch]--; /* decr counter */\r
885 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */\r
886 }\r
887 break;\r
888\r
889 case CH9_TCM: /* transfer on cond */\r
890 csel = CH9D_COND (ch_wc[ch]);\r
891 mask = CH9D_MASK (ch_wc[ch]);\r
892 if (csel == 7) xfr = (mask == 0); /* C = 7? mask mbz */\r
893 else { /* C = 0..6 */\r
894 if (csel == 0) tval = ch_cnd[ch]; /* C = 0? test cond */\r
895 else tval = (uint32) (ch_ar[ch] >> (6 * (6 - csel))) & 077;\r
896 if (ch_wc[ch] & CH9D_B11)\r
897 xfr = ((tval & mask) == mask);\r
898 else xfr = (tval == mask);\r
899 }\r
900 if (xfr) ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */\r
901 break;\r
902\r
903 case CH9_LIP: /* leave interrupt */\r
904 ta = CHINT_CHA_SAV + (ch << 1); /* save location */\r
905 ch_flags[ch] &= ~(CHF_INT|CHF_IRQ); /* clear intr */\r
906 ch_cnd[ch] = 0; /* clear channel cond */\r
907 ch_clc[ch] = (uint32) ReadP (ta) & CHAMASK;\r
908 break;\r
909\r
910 case CH9_LIPT: /* leave intr, transfer */\r
911 ch_flags[ch] &= ~(CHF_INT|CHF_IRQ); /* clear intr */\r
912 ch_cnd[ch] = 0; /* clear channel cond */\r
913 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */\r
914 break;\r
915\r
916 case CH9_LAR: /* load assembly reg */\r
917 ch_ar[ch] = ReadP (ch_ca[ch]);\r
918 break;\r
919\r
920 case CH9_SAR: /* store assembly reg */\r
921 WriteP (ch_ca[ch], ch_ar[ch]);\r
922 break;\r
923\r
924 case CH9_SMS: /* load SMS reg */\r
925 ch_sms[ch] = CH9A_SMS (ch_ca[ch]); /* from eff addr */\r
926 if (!(ch_sms[ch] & CHSMS_IATN1) && /* atn inhbit off */\r
927 (ch_flags[ch] & CHF_ATN1)) /* and atn pending? */\r
928 ch9_eval_int (ch, 0); /* force int eval */\r
929 break;\r
930\r
931 case CH9_LCC: /* load control cntr */\r
932 ch_lcc[ch] = CH9A_LCC (ch_ca[ch]); /* from eff addr */\r
933 break;\r
934\r
935 case CH9_ICC: /* insert control cntr */\r
936 case CH9_ICCA:\r
937 csel = CH9D_COND (ch_wc[ch]); /* get C */\r
938 if (csel == 0) ch_ar[ch] = /* C = 0? read SMS */\r
939 (ch_ar[ch] & 0777777770000) | ((t_uint64) ch_sms[ch]);\r
940 else if (csel < 7) { /* else read cond cntr */\r
941 sc = 6 * (6 - csel);\r
942 ch_ar[ch] = (ch_ar[ch] & ~(((t_uint64) 077) << sc)) |\r
943 (((t_uint64) ch_lcc[ch]) << sc);\r
944 }\r
945 break;\r
946\r
947 case CH9_XMT: /* transmit */\r
948 if (ch_wc[ch] == 0) break;\r
949 sr = ReadP (ch_clc[ch]); /* next word */\r
950 WriteP (ch_ca[ch], sr);\r
951 ch_clc[ch] = CHAINC (ch_clc[ch]); /* incr pointers */\r
952 ch_ca[ch] = CHAINC (ch_ca[ch]);\r
953 ch_wc[ch] = ch_wc[ch] - 1; /* decr count */\r
954 ch_req |= REQ_CH (ch); /* go again */\r
955 return SCPE_OK;\r
956\r
957 case CH9_SNS: /* sense */\r
958 if (r = ch9_sel (ch, CHSL_SNS)) return r; /* send sense to dev */\r
959 ch_flags[ch] |= CHF_PRD; /* prepare to read */\r
960 break; /* next command */\r
961\r
962 case CH9_CTL:\r
963 case CH9_CTLR:\r
964 case CH9_CTLW: /* control */\r
965 if (((ch_wc[ch] & CH9D_NST) == 0) && /* N = 0 and */\r
966 !(ch_flags[ch] & CHF_EOR)) { /* end not set? */\r
967 sr = ReadP (ch_ca[ch]);\r
968 ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */\r
969 return ch9_wr (ch, sr, 0); /* write ctrl wd */\r
970 }\r
971 ch_flags[ch] &= ~CHF_EOR; /* clear end */\r
972 if (ch_op[ch] == CH9_CTLR) { /* CTLR? */\r
973 if (r = ch9_sel (ch, CHSL_RDS)) return r; /* send read sel */\r
974 ch_flags[ch] |= CHF_PRD; /* prep to read */\r
975 ch_idf[ch] = 0;\r
976 }\r
977 else if (ch_op[ch] == CH9_CTLW) { /* CTLW? */\r
978 if (r = ch9_sel (ch, CHSL_WRS)) return r; /* end write sel */\r
979 ch_flags[ch] |= CHF_PWR; /* prep to write */\r
980 }\r
981 break;\r
982\r
983 case CH9_CPYD: /* copy & disc */\r
984 if ((ch_wc[ch] == 0) || (ch_flags[ch] & CHF_EOR)) { /* wc == 0 or EOR? */\r
985 if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) {\r
986 ch_flags[ch] &= ~(CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS);\r
987 if (r = ch9_wr (ch, 0, CH9DF_STOP)) return r; /* send stop */\r
988 }\r
989 if (ch_flags[ch] & CHF_EOR) { /* EOR? */\r
990 ch_flags[ch] &= ~CHF_EOR; /* clear flag */\r
991 break; /* new command */\r
992 }\r
993 return SCPE_OK; /* wait for end */\r
994 } \r
995 if (ch_flags[ch] & CHF_RDS) /* read? */\r
996 return ch9_rd_putw (ch);\r
997 return ch9_wr_getw (ch); /* no, write */\r
998\r
999 case CH9_CPYP: /* anything to do? */\r
1000 if (ch_wc[ch] == 0) break; /* (new, wc = 0) next */\r
1001 if (ch_flags[ch] & CHF_EOR) /* end? */\r
1002 ch_flags[ch] &= ~CHF_EOR; /* ignore */\r
1003 else if (ch_flags[ch] & CHF_RDS) /* read? */\r
1004 ch9_rd_putw (ch);\r
1005 else if (r = ch9_wr_getw (ch)) return r; /* no, write */\r
1006 if (ch_wc[ch] == 0) break; /* done? get next */\r
1007 return SCPE_OK; /* more to do */\r
1008 \r
1009 default:\r
1010 return STOP_ILLIOP;\r
1011 }\r
1012\r
1013 return ch9_new_cmd (ch); /* next command */\r
1014 }\r
1015\r
1016else if (ch_flags[ch] & CHF_RDS) { /* 7607 read? */\r
1017\r
1018 if (ch_sta[ch] != CHXS_DSX) return ch6_end_ds (ch); /* chan exec? no, disc */\r
1019 switch (ch_op[ch] & CH6_OPMASK) { /* switch on op */\r
1020\r
1021 case CH6_TCH: /* transfer */\r
1022 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change clc */\r
1023 return ch6_new_cmd (ch, FALSE); /* unpack new cmd */\r
1024\r
1025 case CH6_IOCD: /* IOCD */\r
1026 if (ch_wc[ch]) { /* wc > 0? */\r
1027 if (ch6_rd_putw (ch)) return SCPE_OK; /* store; more? cont */\r
1028 }\r
1029 return ch6_end_ds (ch); /* no, disconnect */\r
1030\r
1031 case CH6_IOCP: /* IOCP */\r
1032 if (ch_wc[ch]) { /* wc > 0? */\r
1033 if (ch6_rd_putw (ch)) return SCPE_OK; /* store; more? cont */\r
1034 }\r
1035 return ch6_new_cmd (ch, FALSE); /* unpack new cmd */\r
1036\r
1037 case CH6_IOCT: /* IOCT */\r
1038 if (ch_wc[ch]) { /* wc > 0? */\r
1039 if (ch6_rd_putw (ch)) return SCPE_OK; /* store; more? cont */\r
1040 }\r
1041 return ch6_ioxt (ch); /* unstall or disc */\r
1042\r
1043 case CH6_IOSP: /* IOSP */\r
1044 if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */\r
1045 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1046 return ch6_new_cmd (ch, FALSE); /* get next cmd */\r
1047 }\r
1048 if (ch_wc[ch]) { /* wc > 0? */\r
1049 if (ch6_rd_putw (ch) && !(ch_flags[ch] & CHF_EOR))\r
1050 return SCPE_OK; /* yes, store; more? */\r
1051 ch6_iosp_cclr (ch); /* cond clear eor */\r
1052 }\r
1053 return ch6_new_cmd (ch, FALSE); /* next cmd */\r
1054\r
1055 case CH6_IOST: /* IOST */\r
1056 if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */\r
1057 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1058 return ch6_ioxt (ch); /* get next cmd */\r
1059 }\r
1060 if (ch_wc[ch]) { /* wc > 0? */\r
1061 if (ch6_rd_putw (ch) && !(ch_flags[ch] & CHF_EOR))\r
1062 return SCPE_OK; /* yes, store; more? */\r
1063 ch6_iosp_cclr (ch); /* cond clear eor */\r
1064 }\r
1065 return ch6_ioxt (ch); /* unstall or disc */\r
1066\r
1067 case CH6_IORP: /* IORP */\r
1068 if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */\r
1069 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1070 return ch6_new_cmd (ch, FALSE); /* get next cmd */\r
1071 }\r
1072 ch6_rd_putw (ch); /* store wd; ignore wc */ \r
1073 if (ch_flags[ch] & CHF_EOR) { /* EOR? */\r
1074 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1075 return ch6_new_cmd (ch, FALSE); /* get next cmd */\r
1076 }\r
1077 return SCPE_OK; /* done */\r
1078 \r
1079 case CH6_IORT: /* IORT */\r
1080 if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */\r
1081 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1082 return ch6_ioxt (ch); /* get next cmd */\r
1083 }\r
1084 ch6_rd_putw (ch); /* store wd; ignore wc */ \r
1085 if (ch_flags[ch] & CHF_EOR) { /* EOR? */\r
1086 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */\r
1087 return ch6_ioxt (ch); /* unstall or disc */\r
1088 }\r
1089 return SCPE_OK; /* done */\r
1090\r
1091 default:\r
1092 return SCPE_IERR;\r
1093 } /* end case */\r
1094 } /* end if read */\r
1095\r
1096else { /* 7607 write */\r
1097\r
1098 if (ch_sta[ch] != CHXS_DSX) return ch6_end_ds (ch); /* chan exec? no, disc */\r
1099 switch (ch_op[ch] & CH6_OPMASK) { /* switch on op */\r
1100\r
1101 case CH6_TCH: /* transfer */\r
1102 ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change clc */\r
1103 return ch6_new_cmd (ch, FALSE); /* unpack new cmd */\r
1104\r
1105 case CH6_IOCD: /* IOCD */\r
1106 if (ch_wc[ch]) { /* wc > 0? */\r
1107 if (r = ch6_wr_getw (ch, TRUE)) return r; /* send wd to dev; err? */\r
1108 if (ch_wc[ch]) return SCPE_OK; /* more to do? */\r
1109 }\r
1110 return ch6_end_ds (ch); /* disconnect */\r
1111\r
1112 case CH6_IOCP: /* IOCP */\r
1113 case CH6_IOSP: /* IOSP */\r
1114 if (ch_wc[ch]) { /* wc > 0? */\r
1115 if (r = ch6_wr_getw (ch, FALSE)) return r; /* send wd to dev; err? */\r
1116 if (ch_wc[ch]) return SCPE_OK; /* more to do? */\r
1117 }\r
1118 return ch6_new_cmd (ch, FALSE); /* get next cmd */\r
1119\r
1120 case CH6_IOCT: /* IOCT */\r
1121 case CH6_IOST: /* IOST */\r
1122 if (ch_wc[ch]) { /* wc > 0? */\r
1123 if (r = ch6_wr_getw (ch, FALSE)) return r; /* send wd to dev; err? */\r
1124 if (ch_wc[ch]) return SCPE_OK; /* more to do? */\r
1125 }\r
1126 return ch6_ioxt (ch); /* get next cmd */\r
1127\r
1128 case CH6_IORP: /* IORP */\r
1129 if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */\r
1130 if (r = ch6_wr_getw (ch, TRUE)) return r; /* send wd to dev; err? */\r
1131 if (ch_wc[ch]) return SCPE_OK; /* more to do? */\r
1132 }\r
1133 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear EOR */\r
1134 return ch6_new_cmd (ch, FALSE); /* get next cmd */\r
1135\r
1136 case CH6_IORT: /* IORT */\r
1137 if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */\r
1138 if (r = ch6_wr_getw (ch, TRUE)) return r; /* send wd to dev; err? */\r
1139 if (ch_wc[ch]) return SCPE_OK; /* more to do? */\r
1140 }\r
1141 ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear EOR */\r
1142 return ch6_ioxt (ch); /* unstall or disc */\r
1143\r
1144 default:\r
1145 return SCPE_IERR;\r
1146 } /* end switch */\r
1147 } /* end else write */\r
1148}\r
1149\r
1150/* 7607 channel support routines */\r
1151\r
1152/* 7607 channel input routine - put one word to memory */\r
1153\r
1154t_bool ch6_rd_putw (uint32 ch)\r
1155{\r
1156if (ch_idf[ch] & CH6DF_EOR) ch_flags[ch] |= CHF_EOR; /* eor from dev? */\r
1157else ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* set/clr chan eor */\r
1158ch_idf[ch] = 0; /* clear eor, valid */\r
1159if (ch_wc[ch]) { /* wc > 0? */\r
1160 if ((ch_op[ch] & 1) == 0) { /* do store? */\r
1161 WriteP (ch_ca[ch], ch_ar[ch]);\r
1162 ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */\r
1163 }\r
1164 ch_wc[ch] = ch_wc[ch] - 1;\r
1165 }\r
1166return (ch_wc[ch]? TRUE: FALSE);\r
1167}\r
1168\r
1169/* 7607 channel output routine - get one word from memory */\r
1170\r
1171t_stat ch6_wr_getw (uint32 ch, t_bool eorz)\r
1172{\r
1173DEVICE *dptr;\r
1174DIB *dibp;\r
1175uint32 eorfl;\r
1176\r
1177ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clr eor */\r
1178if (ch_wc[ch]) {\r
1179 ch_ar[ch] = ReadP (ch_ca[ch]); /* get word */\r
1180 ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */\r
1181 ch_wc[ch] = ch_wc[ch] - 1;\r
1182 }\r
1183else ch_ar[ch] = 0;\r
1184if (eorz && (ch_wc[ch] == 0)) eorfl = 1; /* eor on wc = 0? */\r
1185else eorfl = 0;\r
1186dptr = ch_find_dev (ch, ch_dsu[ch]); /* find device */\r
1187if (dptr && /* valid device? */\r
1188 (dibp = (DIB *) dptr->ctxt) && /* with DIB? */\r
1189 dibp->write) /* and write routine? */\r
1190 return dibp->write (ch, ch_ar[ch], eorfl);\r
1191return SCPE_IERR; /* huh? */\r
1192}\r
1193\r
1194/* 7607 channel new command - on channel load, check for disconnects\r
1195\r
1196 The protocol for new commands is as follows:\r
1197 - If IOCD 0,,0, disconnect immediately\r
1198 - If IOCT 0,,0 or IOST 0,,0 and loaded by RCHA, disconnect immediately\r
1199 - If an effective NOP (TCH, IOCx 0,,0, IOSx 0,,0), force a channel\r
1200 cycle to retire the channel comand as quickly as possible.\r
1201 - If an IORx and EOR is set, force a channel cycle to retire the\r
1202 channel command as quickly as possible.\r
1203*/\r
1204\r
1205t_stat ch6_new_cmd (uint32 ch, t_bool ch_ld)\r
1206{\r
1207t_uint64 ir;\r
1208uint32 op, t;\r
1209\r
1210ir = ReadP (t = ch_clc[ch]); /* read cmd */\r
1211ch_wc[ch] = GET_DEC (ir); /* get word cnt */\r
1212ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */\r
1213op = GET_OPD (ir) << 1; /* get opcode */\r
1214ch_op[ch] = op | ((((uint32) ir) & CH6I_NST)? 1: 0); /* plus 'no store' */\r
1215if ((ir & CHI_IND) && (ch_wc[ch] || /* indirect? */\r
1216 ((op != CH6_IOCP) && (op != CH6_IOSP)))) { /* wc >0, or !IOxP? */\r
1217 t_uint64 sr = ReadP (ch_ca[ch] & AMASK); /* read indirect */\r
1218 ch_ca[ch] = ((uint32) sr) & ((cpu_model & I_CT)? PAMASK: AMASK);\r
1219 }\r
1220if (hst_ch) cpu_ent_hist (ch_clc[ch] | ((ch + 1) << HIST_V_CH), ch_ca[ch], ir, 0);\r
1221ch_clc[ch] = (ch_clc[ch] + 1) & AMASK; /* incr chan pc */\r
1222\r
1223switch (op) { /* case on opcode */\r
1224\r
1225 case CH6_IOCD: /* IOCD */\r
1226 if (ch_wc[ch] == 0) ch6_end_ds (ch); /* wc 0? end now */\r
1227 break;\r
1228\r
1229 case CH6_IOST: /* IOST */\r
1230 if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */\r
1231 ch_req |= REQ_CH (ch);\r
1232 case CH6_IOCT: /* IOCT */\r
1233 if (ch_wc[ch] == 0) { /* wc 0? */\r
1234 if (ch_ld) ch6_end_ds (ch); /* load? end now */\r
1235 else ch_req |= REQ_CH (ch); /* else immed ch req */\r
1236 }\r
1237 break;\r
1238\r
1239 case CH6_IOSP: /* IOSP */\r
1240 if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */\r
1241 ch_req |= REQ_CH (ch);\r
1242 case CH6_IOCP: /* IOCP */\r
1243 if (ch_wc[ch] == 0) ch_req |= REQ_CH (ch); /* wc 0? immed ch req */\r
1244 break;\r
1245\r
1246 case CH6_IORT: /* IORT */\r
1247 case CH6_IORP: /* IORP */\r
1248 if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */\r
1249 ch_req |= REQ_CH (ch);\r
1250 break;\r
1251\r
1252 case CH6_TCH: /* TCH */\r
1253 ch_req |= REQ_CH (ch); /* immed ch req */\r
1254 break;\r
1255\r
1256 default: /* all others */\r
1257 break;\r
1258 } /* end case */\r
1259\r
1260if (sim_brk_summ && sim_brk_test (t, SWMASK ('E')))\r
1261 return ch_bkpt (ch, t);\r
1262return SCPE_OK;\r
1263}\r
1264\r
1265/* 7607 channel IOxT: if LCH stall, set state back to DSW; else disconnect and trap */\r
1266\r
1267t_stat ch6_ioxt (uint32 ch)\r
1268{\r
1269if (ch_flags[ch] & CHF_LDW) { /* LCH cmd pending? */\r
1270 ch_flags[ch] &= ~CHF_LDW; /* clr pending flag */\r
1271 ch_sta[ch] = CH6S_DSW; /* unstall pending LCH */\r
1272 }\r
1273else {\r
1274 ch_flags[ch] |= CHF_CMD; /* set cmd trap flag */\r
1275 ch6_end_ds (ch); /* disconnect */\r
1276 }\r
1277return SCPE_OK;\r
1278}\r
1279\r
1280/* 7607 conditionally clear EOR on IOSx completion */\r
1281\r
1282void ch6_iosp_cclr (uint32 ch)\r
1283{\r
1284uint32 i, op;\r
1285\r
1286if (ch_wc[ch] == 0) { /* wc = 0? */\r
1287 uint32 ccnt = 5; /* allow 5 for CPU */\r
1288 for (i = 0; i < NUM_CHAN; i++) { /* test channels */\r
1289 if (ch_sta[ch] != CHXS_DSX) continue; /* idle? skip */\r
1290 op = ch_op[ch] & ~1; /* get op */\r
1291 ccnt++; /* 1 per active ch */\r
1292 if ((op == CH6_IOCP) || (op == CH6_IORP) || /* 1 per proceed */\r
1293 (op == CH6_IOSP)) ccnt++;\r
1294 }\r
1295 if (ccnt <= 11) return; /* <= 11? ok */\r
1296 }\r
1297ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear eor */\r
1298return;\r
1299}\r
1300\r
1301/* 7607 external interface routines */\r
1302\r
1303/* Input - store word, request channel input service */\r
1304\r
1305t_stat ch6_req_rd (uint32 ch, uint32 unit, t_uint64 val, uint32 fl)\r
1306{\r
1307if (ch6_qconn (ch, unit)) { /* ch conn to caller? */\r
1308 if (ch_idf[ch] & CH6DF_VLD) ind_ioc = 1; /* overrun? */\r
1309 ch_idf[ch] = CH6DF_VLD; /* set ar valid */\r
1310 if (fl) ch_idf[ch] |= CH6DF_EOR; /* set eor if requested */\r
1311 ch_req |= REQ_CH (ch); /* request chan */\r
1312 ch_flags[ch] |= CHF_RDS;\r
1313 ch_ar[ch] = val & DMASK; /* save data */\r
1314 }\r
1315return SCPE_OK;\r
1316}\r
1317\r
1318/* Disconnect on error */\r
1319\r
1320t_stat ch6_err_disc (uint32 ch, uint32 unit, uint32 fl)\r
1321{\r
1322if (ch6_qconn (ch, unit)) { /* ch conn to caller? */\r
1323 ch_flags[ch] |= fl; /* set flag */\r
1324 return ch6_end_ds (ch); /* disconnect */\r
1325 }\r
1326return SCPE_OK;\r
1327}\r
1328\r
1329/* Output - request channel output service */\r
1330\r
1331t_bool ch6_req_wr (uint32 ch, uint32 unit)\r
1332{\r
1333if (ch6_qconn (ch, unit)) { /* ch conn to caller? */\r
1334 ch_req |= REQ_CH (ch);\r
1335 ch_flags[ch] &= ~CHF_RDS;\r
1336 }\r
1337return SCPE_OK;\r
1338}\r
1339\r
1340/* Set/read channel flags */\r
1341\r
1342uint32 ch6_set_flags (uint32 ch, uint32 unit, uint32 flags)\r
1343{\r
1344if (ch6_qconn (ch, unit)) { /* ch conn to caller? */\r
1345 ch_flags[ch] = ch_flags[ch] | flags;\r
1346 return ch_flags[ch];\r
1347 }\r
1348return 0;\r
1349}\r
1350\r
1351/* Channel connected to unit? */\r
1352\r
1353t_bool ch6_qconn (uint32 ch, uint32 unit)\r
1354{\r
1355if ((ch < NUM_CHAN) && /* valid chan */\r
1356 (ch_dsu[ch] == unit)) return TRUE; /* for right unit? */\r
1357return FALSE;\r
1358}\r
1359\r
1360/* 7909 channel support routines */\r
1361\r
1362/* 7909 channel input routine - put one word to memory */\r
1363\r
1364t_stat ch9_rd_putw (uint32 ch)\r
1365{\r
1366ch_idf[ch] = 0; /* invalidate */\r
1367if (ch_wc[ch]) { /* wc > 0? */\r
1368 WriteP (ch_ca[ch], ch_ar[ch]);\r
1369 ch_ca[ch] = CHAINC (ch_ca[ch]);\r
1370 ch_wc[ch] = ch_wc[ch] - 1;\r
1371 }\r
1372return SCPE_OK;\r
1373}\r
1374\r
1375/* 7909 channel output routine - get one word from memory */\r
1376\r
1377t_stat ch9_wr_getw (uint32 ch)\r
1378{\r
1379if (ch_wc[ch]) {\r
1380 ch_ar[ch] = ReadP (ch_ca[ch]); /* get word */\r
1381 ch_ca[ch] = CHAINC (ch_ca[ch]);\r
1382 ch_wc[ch] = ch_wc[ch] - 1;\r
1383 }\r
1384else ch_ar[ch] = 0;\r
1385return ch9_wr (ch, ch_ar[ch], 0); /* write to device */\r
1386}\r
1387\r
1388/* 7909 send select to device */\r
1389\r
1390t_stat ch9_sel (uint32 ch, uint32 sel)\r
1391{\r
1392DEVICE *dptr = ch2dev[ch];\r
1393DIB *dibp;\r
1394\r
1395if (dptr == NULL) return SCPE_IERR;\r
1396dibp = (DIB *) dptr->ctxt;\r
1397if (dibp && dibp->chsel) return dibp->chsel (ch, sel, 0);\r
1398return SCPE_IERR;\r
1399}\r
1400\r
1401/* 7909 send word to device */\r
1402\r
1403t_stat ch9_wr (uint32 ch, t_uint64 dat, uint32 fl)\r
1404{\r
1405DEVICE *dptr = ch2dev[ch];\r
1406DIB *dibp;\r
1407\r
1408if (dptr == NULL) return SCPE_IERR;\r
1409dibp = (DIB *) dptr->ctxt;\r
1410if (dibp && dibp->write) return dibp->write (ch, dat, fl);\r
1411return SCPE_IERR;\r
1412}\r
1413\r
1414/* 7909 channel new command */\r
1415\r
1416t_stat ch9_new_cmd (uint32 ch)\r
1417{\r
1418t_uint64 ir;\r
1419uint32 t;\r
1420t_stat r;\r
1421\r
1422ir = ReadP (t = ch_clc[ch]); /* read cmd */\r
1423r = ch9_exec_cmd (ch, ir); /* exec cmd */\r
1424if (ch_sta[ch] != CHXS_IDLE) /* chan running? */\r
1425 ch_clc[ch] = CHAINC (ch_clc[ch]); /* incr chan pc */\r
1426if ((r == SCPE_OK) && sim_brk_summ && sim_brk_test (t, SWMASK ('E')))\r
1427 return ch_bkpt (ch, t);\r
1428return r;\r
1429}\r
1430\r
1431t_stat ch9_exec_cmd (uint32 ch, t_uint64 ir)\r
1432{\r
1433uint32 op;\r
1434\r
1435ch_wc[ch] = GET_DEC (ir); /* get word cnt */\r
1436ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */\r
1437op = (GET_OPD (ir) << 2); /* get opcode */\r
1438ch_op[ch] = op | ((((uint32) ir) & 0200000)? 1: 0) | /* plus bit<19> */\r
1439 (((op & 010) && (ch_wc[ch] & 040000))? 2: 0); /* plus bit 3 if used */\r
1440if (ir & CHI_IND) { /* indirect? */\r
1441 t_uint64 sr = ReadP (ch_ca[ch] & CHAMASK); /* read indirect */\r
1442 ch_ca[ch] = ((uint32) sr) & CHAMASK; /* get address */\r
1443 }\r
1444if (hst_ch)\r
1445 cpu_ent_hist (ch_clc[ch] | ((ch + 1) << HIST_V_CH), ch_ca[ch], ir, 0);\r
1446\r
1447switch (ch_op[ch]) { /* check initial cond */\r
1448\r
1449 case CH9_LAR: /* misc processing */\r
1450 case CH9_SAR:\r
1451 case CH9_ICC:\r
1452 case CH9_ICCA:\r
1453 case CH9_XMT:\r
1454 case CH9_LCC:\r
1455 case CH9_SMS:\r
1456 if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS))\r
1457 ch9_eval_int (ch, CHINT_SEQC); /* not during data */\r
1458 /* fall through */\r
1459 case CH9_TCM: /* jumps */\r
1460 case CH9_TCH:\r
1461 case CH9_TDC:\r
1462 case CH9_LIPT:\r
1463 case CH9_LIP:\r
1464 ch_req |= REQ_CH (ch); /* process in chan */\r
1465 break;\r
1466\r
1467 case CH9_CTL: /* control */\r
1468 case CH9_CTLR:\r
1469 case CH9_CTLW:\r
1470 if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS))\r
1471 ch9_eval_int (ch, CHINT_SEQC); /* not during data */\r
1472 ch_flags[ch] &= ~CHF_EOR;\r
1473 if (ch_wc[ch] & CH9D_NST) ch_req |= REQ_CH (ch); /* N set? proc in chan */\r
1474 else return ch9_sel (ch, CHSL_CTL); /* sel, dev sets ch_req! */\r
1475 break;\r
1476\r
1477 case CH9_SNS: /* sense */\r
1478 if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS))\r
1479 ch9_eval_int (ch, CHINT_SEQC);\r
1480 ch_flags[ch] &= ~CHF_EOR;\r
1481 ch_req |= REQ_CH (ch); /* process in chan */\r
1482 break; \r
1483\r
1484 case CH9_CPYD: /* data transfers */\r
1485 case CH9_CPYP:\r
1486 if ((ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) == 0)\r
1487 ch9_eval_int (ch, CHINT_SEQC); /* not unless data */\r
1488 if (ch_flags[ch] & CHF_PRD) ch_flags[ch] |= CHF_RDS;\r
1489 else if (ch_flags[ch] & CHF_PWR) ch_flags[ch] |= CHF_WRS;\r
1490 ch_flags[ch] &= ~(CHF_EOR|CHF_PRD|CHF_PWR);\r
1491 if ((ch_op[ch] == CH9_CPYP) && (ch_wc[ch] == 0))\r
1492 ch_req |= REQ_CH (ch); /* CPYP x,,0? */\r
1493 break; /* dev sets ch_req! */\r
1494\r
1495 case CH9_WTR: /* wait */\r
1496 ch_sta[ch] = CHXS_IDLE; /* stop */\r
1497 break;\r
1498\r
1499 case CH9_TWT: /* trap and wait */\r
1500 ch_sta[ch] = CHXS_IDLE; /* stop */\r
1501 ch_flags[ch] |= CHF_TWT; /* set trap */\r
1502 break;\r
1503\r
1504 default:\r
1505 return STOP_ILLIOP;\r
1506 }\r
1507\r
1508return SCPE_OK;\r
1509}\r
1510\r
1511/* 7909 external interface routines */\r
1512\r
1513/* Input - store word, request channel input service */\r
1514\r
1515t_stat ch9_req_rd (uint32 ch, t_uint64 val)\r
1516{\r
1517if (ch < NUM_CHAN) { /* valid chan? */\r
1518 if (ch_idf[ch] & CH9DF_VLD) ch9_set_ioc (ch); /* prev still valid? io chk */\r
1519 ch_idf[ch] = CH9DF_VLD; /* set ar valid */\r
1520 ch_req |= REQ_CH (ch); /* request chan */\r
1521 ch_ar[ch] = val & DMASK; /* save data */\r
1522 }\r
1523return SCPE_OK;\r
1524}\r
1525\r
1526/* Set attention */\r
1527\r
1528void ch9_set_atn (uint32 ch)\r
1529{\r
1530if (ch < NUM_CHAN) ch9_eval_int (ch, CHINT_ATN1);\r
1531return;\r
1532}\r
1533\r
1534/* Set IO check - UEND will occur at end - not recognized in int mode */\r
1535\r
1536void ch9_set_ioc (uint32 ch)\r
1537{\r
1538if ((ch < NUM_CHAN) && !(ch_flags[ch] & CHF_INT)) {\r
1539 ind_ioc = 1; /* IO check */\r
1540 ch_flags[ch] |= CHF_IOC; /* ch IOC for end */\r
1541 }\r
1542return;\r
1543}\r
1544\r
1545/* Set end */\r
1546\r
1547void ch9_set_end (uint32 ch, uint32 iflags)\r
1548{\r
1549if (ch < NUM_CHAN) { /* valid chan? */\r
1550 ch_flags[ch] |= CHF_EOR;\r
1551 ch9_eval_int (ch, iflags);\r
1552 }\r
1553return;\r
1554}\r
1555\r
1556/* Test connected */\r
1557\r
1558t_bool ch9_qconn (uint32 ch)\r
1559{\r
1560if ((ch < NUM_CHAN) && (ch_sta[ch] == CHXS_DSX)) return TRUE;\r
1561return FALSE;\r
1562}\r
1563\r
1564/* Evaluate interrupts \r
1565\r
1566 - Interrupt requests set flags in the channel flags word\r
1567 - If an interrupt is not in progress, interrupt requests are evaluated\r
1568 - If an interrupt request is found, the interruptable flags are\r
1569 transferred to the channel condition register and cleared in\r
1570 the channel flags\r
1571\r
1572 This provides an effective stage of buffering for interrupt requests\r
1573 that are not immediately serviced */\r
1574\r
1575void ch9_eval_int (uint32 ch, uint32 iflags)\r
1576{\r
1577uint32 ireq;\r
1578\r
1579ch_flags[ch] |= (iflags << CHF_V_COND); /* or into chan flags */\r
1580if ((ch_flags[ch] & CHF_INT) == 0) { /* int not in prog? */\r
1581 ireq = ((ch_flags[ch] >> CHF_V_COND) & CHF_M_COND) &\r
1582 ~(((ch_sms[ch] & CHSMS_IUEND)? CHINT_UEND: 0) |\r
1583 ((ch_sms[ch] & CHSMS_IATN1)? CHINT_ATN1: 0) |\r
1584 ((ch_sms[ch] & CHSMS_IATN2)? CHINT_ATN2: 0) |\r
1585 ((ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS))? CHINT_SEQC: 0));\r
1586 if (ireq) { /* int pending? */\r
1587 ch_cnd[ch] = ireq; /* set cond reg */\r
1588 ch_flags[ch] &= ~(ireq << CHF_V_COND); /* clear chan flags */\r
1589 ch_flags[ch] |= CHF_IRQ; /* set int req */\r
1590 ch_req |= REQ_CH (ch); /* request channel */\r
1591 }\r
1592 }\r
1593return;\r
1594}\r
1595\r
1596/* Test for all channels idle */\r
1597\r
1598t_bool ch_qidle (void)\r
1599{\r
1600uint32 i;\r
1601\r
1602for (i = 0; i < NUM_CHAN; i++) {\r
1603 if (ch_sta[i] != CHXS_IDLE) return FALSE;\r
1604 }\r
1605return TRUE;\r
1606}\r
1607\r
1608/* Evaluate/execute channel traps */\r
1609\r
1610uint32 chtr_eval (uint32 *decr)\r
1611{\r
1612uint32 i, cme;\r
1613\r
1614if (!chtr_inht && !chtr_inhi && chtr_enab) {\r
1615 if (BIT_TST (chtr_enab, CHTR_V_CLK) && chtr_clk) { /* clock trap? */\r
1616 if (decr) { /* exec? */\r
1617 chtr_clk = 0; /* clr flag */\r
1618 *decr = 0;\r
1619 }\r
1620 return CHTR_CLK_SAV;\r
1621 }\r
1622 for (i = 0; i < NUM_CHAN; i++) { /* loop thru chan */\r
1623 cme = BIT_TST (chtr_enab, CHTR_V_CME + i); /* cmd/eof enab? */\r
1624 if (cme && (ch_flags[i] & CHF_CMD)) { /* cmd enab and set? */\r
1625 if (decr) { /* exec? */\r
1626 ch_flags[i] &= ~CHF_CMD; /* clr flag */\r
1627 *decr = CHTR_F_CMD;\r
1628 }\r
1629 return (CHTR_CHA_SAV + (i << 1));\r
1630 }\r
1631 if (cme && (ch_flags[i] & CHF_EOF)) { /* eof enab and set? */\r
1632 if (decr) { /* exec? */\r
1633 ch_flags[i] &= ~CHF_EOF; /* clr flag */\r
1634 *decr = CHTR_F_EOF;\r
1635 }\r
1636 return (CHTR_CHA_SAV + (i << 1));\r
1637 }\r
1638 if (BIT_TST (chtr_enab, CHTR_V_TRC + i) && /* trc enab? */\r
1639 (ch_flags[i] & CHF_TRC)) { /* trc flag? */\r
1640 if (decr) { /* exec? */\r
1641 ch_flags[i] &= ~CHF_TRC; /* clr flag */\r
1642 *decr = CHTR_F_TRC;\r
1643 }\r
1644 return (CHTR_CHA_SAV + (i << 1));\r
1645 } /* end if BIT_TST */\r
1646 } /* end for */\r
1647 } /* end if !chtr_inht */\r
1648if (decr) *decr = 0;\r
1649return 0;\r
1650}\r
1651\r
1652/* Channel reset */\r
1653\r
1654t_stat ch_reset (DEVICE *dptr)\r
1655{\r
1656uint32 ch = dptr - &ch_dev[0]; /* get channel */\r
1657\r
1658if (ch == CH_A) ch2dev[ch] = &mt_dev[0]; /* channel A fixed */\r
1659ch_sta[ch] = 0;\r
1660ch_flags[ch] = 0;\r
1661ch_idf[ch] = 0;\r
1662ch_dso[ch] = 0;\r
1663ch_dsu[ch] = 0;\r
1664ch_ndso[ch] = 0;\r
1665ch_ndsu[ch] = 0;\r
1666ch_op[ch] = 0;\r
1667ch_clc[ch] = 0;\r
1668ch_wc[ch] = 0;\r
1669ch_ca[ch] = 0;\r
1670ch_ar[ch] = 0;\r
1671ch_sms[ch] = 0;\r
1672ch_cnd[ch] = 0;\r
1673ch_lcc[ch] = 0;\r
1674sim_cancel (&ch_unit[ch]);\r
1675return SCPE_OK;\r
1676}\r
1677\r
1678/* Show channel type */\r
1679\r
1680t_stat ch_show_type (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1681{\r
1682DEVICE *dptr;\r
1683\r
1684dptr = find_dev_from_unit (uptr);\r
1685if (dptr == NULL) return SCPE_IERR;\r
1686if (dptr->flags & DEV_7909) fputs ("7909", st);\r
1687else if (dptr->flags & DEV_7289) fputs ("7289", st);\r
1688else fputs ("7607", st);\r
1689return SCPE_OK;\r
1690}\r
1691\r
1692/* Enable channel, assign device */\r
1693\r
1694t_stat ch_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1695{\r
1696DEVICE *dptr, *dptr1;\r
1697char gbuf[CBUFSIZE];\r
1698uint32 i, ch;\r
1699\r
1700dptr = find_dev_from_unit (uptr);\r
1701if (dptr == NULL) return SCPE_IERR;\r
1702ch = dptr - &ch_dev[0];\r
1703if ((ch == 0) || !(dptr->flags & DEV_DIS)) return SCPE_ARG;\r
1704if (cptr == NULL) cptr = "TAPE";\r
1705get_glyph (cptr, gbuf, 0);\r
1706for (i = 0; dev_table[i].name; i++) {\r
1707 if (strcmp (dev_table[i].name, gbuf) == 0) {\r
1708 dptr1 = ch_map_flags (ch, dev_table[i].flags);\r
1709 if (!dptr1 || !(dptr1->flags & DEV_DIS)) return SCPE_ARG;\r
1710 dptr->flags &= ~(DEV_DIS|DEV_7909|DEV_7289|DEV_7750|DEV_7631);\r
1711 dptr->flags |= dev_table[i].flags;\r
1712 dptr1->flags &= ~DEV_DIS;\r
1713 ch2dev[ch] = dptr1;\r
1714 return reset_all (0);\r
1715 }\r
1716 }\r
1717return SCPE_ARG;\r
1718}\r
1719\r
1720/* Map device flags to device pointer */\r
1721\r
1722DEVICE *ch_map_flags (uint32 ch, int32 fl)\r
1723{\r
1724if (fl & DEV_7289) return &drm_dev;\r
1725if (!(fl & DEV_7909)) return &mt_dev[ch];\r
1726if (fl & DEV_7631) return &dsk_dev;\r
1727if (fl & DEV_7750) return &com_dev;\r
1728return NULL;\r
1729}\r
1730\r
1731/* Set up channel map */\r
1732\r
1733void ch_set_map (void)\r
1734{\r
1735uint32 i;\r
1736\r
1737for (i = 0; i < NUM_CHAN; i++) {\r
1738 if (ch_dev[i].flags & DEV_DIS) ch2dev[i] = NULL;\r
1739 else ch2dev[i] = ch_map_flags (i, ch_dev[i].flags);\r
1740 }\r
1741return;\r
1742} \r
1743\r
1744/* Disable channel, deassign device */\r
1745\r
1746t_stat ch_set_disable (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1747{\r
1748DEVICE *dptr, *dptr1;\r
1749UNIT *uptr1;\r
1750uint32 i, ch;\r
1751\r
1752dptr = find_dev_from_unit (uptr);\r
1753if (dptr == NULL) return SCPE_IERR;\r
1754ch = dptr - &ch_dev[0];\r
1755if ((ch == 0) || (dptr->flags & DEV_DIS) || (cptr != NULL)) return SCPE_ARG;\r
1756dptr1 = ch2dev[ch];\r
1757if (dptr1 == NULL) return SCPE_IERR;\r
1758if (dptr1->units) {\r
1759 for (i = 0; i < dptr1->numunits; i++) {\r
1760 uptr1 = dptr1->units + i;\r
1761 if (dptr1->detach) dptr1->detach (uptr1);\r
1762 else detach_unit (uptr1);\r
1763 }\r
1764 }\r
1765dptr->flags &= ~(DEV_7909|DEV_7289);\r
1766dptr->flags |= DEV_DIS;\r
1767dptr1->flags |= DEV_DIS;\r
1768return reset_all (0);\r
1769}\r
1770\r
1771/* Show channel that device is on (tapes, 7289, 7909 only) */\r
1772\r
1773t_stat ch_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1774{\r
1775DEVICE *dptr;\r
1776uint32 i;\r
1777\r
1778dptr = find_dev_from_unit (uptr);\r
1779if (dptr) {\r
1780 for (i = 0; i < NUM_CHAN; i++) {\r
1781 if (ch2dev[i] == dptr) {\r
1782 fprintf (st, "channel %c", 'A' + i);\r
1783 return SCPE_OK;\r
1784 }\r
1785 }\r
1786 }\r
1787fprintf (st, "not assigned to channel");\r
1788return SCPE_OK;\r
1789}\r