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