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