1 /* i7094_io.c: IBM 7094 I/O subsystem (channels)
3 Copyright (c) 2003-2006, Robert M. Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 chana..chanh I/O channels
28 Notes on channels and CTSS.
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.
48 #include "i7094_defs.h"
50 #define CHAMASK ((cpu_model & I_CT)? PAMASK: AMASK) /* chan addr mask */
51 #define CHAINC(x) (((x) & ~AMASK) | (((x) + 1) & AMASK))
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 */
77 extern uint32 cpu_model
, data_base
;
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
;
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
);
112 extern CTAB
*sim_vm_cmd
;
113 extern t_stat
ch_bkpt (uint32 ch
, uint32 clc
);
115 const uint32 col_masks
[12] = { /* row 9,8,..,0,11,12 */
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
137 const DEV_CHAR dev_table
[] = {
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
},
149 const char *sel_name
[] = {
150 "UNK", "RDS", "WRS", "SNS", "CTL", "FMT", "UNK", "UNK",
151 "WEF", "WBT", "BSR", "BSF", "REW", "RUN", "SDN", "UNK"
154 /* Channel data structures */
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) }
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
},
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
},
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) },
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) },
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) },
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) },
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) },
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) },
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) },
329 DEVICE ch_dev
[NUM_CHAN
] = {
331 "CHANA", &ch_unit
[CH_A
], cha_reg
, ch_mod
,
333 NULL
, NULL
, &ch_reset
,
338 "CHANB", &ch_unit
[CH_B
], chb_reg
, ch_mod
,
340 NULL
, NULL
, &ch_reset
,
342 NULL
, DEV_DISABLE
| DEV_DIS
345 "CHANC", &ch_unit
[CH_C
], chc_reg
, ch_mod
,
347 NULL
, NULL
, &ch_reset
,
349 NULL
, DEV_DISABLE
| DEV_DIS
352 "CHAND", &ch_unit
[CH_D
], chd_reg
, ch_mod
,
354 NULL
, NULL
, &ch_reset
,
356 NULL
, DEV_DISABLE
| DEV_DIS
359 "CHANE", &ch_unit
[CH_E
], che_reg
, ch_mod
,
361 NULL
, NULL
, &ch_reset
,
363 NULL
, DEV_DISABLE
| DEV_DIS
366 "CHANF", &ch_unit
[CH_F
], chf_reg
, ch_mod
,
368 NULL
, NULL
, &ch_reset
,
370 NULL
, DEV_DISABLE
| DEV_DIS
373 "CHANG", &ch_unit
[CH_G
], chg_reg
, ch_mod
,
375 NULL
, NULL
, &ch_reset
,
377 NULL
, DEV_DISABLE
| DEV_DIS
380 "CHANH", &ch_unit
[CH_H
], chh_reg
, ch_mod
,
382 NULL
, NULL
, &ch_reset
,
384 NULL
, DEV_DISABLE
| DEV_DIS
388 /* 7607 channel overview
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
398 ch_op channel opcode (bits <S,1:2,19>)
399 ch_flags channel flags
403 IDLE - channel is not in operation
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
415 PDS (PNDS) - channel is polling device to start data (non-data) select
417 chan timeout: -> DSW (NDS) if device is idle
418 device timeout drives next transition
419 -> no change if device is busy, schedule channel
422 DSW - channel is waiting for channel start command
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
434 DSX - channel is executing data select
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
446 NDS - channel is executing non-data select
448 dev timeout: -> IDLE if transfer complete, no stacked DS
449 -> PDS if channel disconnects, stacked DS
450 channel timeout drives next transition
453 The channel has two interfaces to a device. The select routine:
455 dev_select (uint32 ch, uint32 sel, uint32 unit)
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.
462 The device write routine is used to place output data in the device
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.
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.
481 state op device channel
483 IDLE RDS,WDS start I/O ->DSW
485 DSW LCHx (timed wait) ->DSX
487 DSX -- timeout, req svc
488 (timed wait) transfer word
492 timeout, EOR/EOC IOxT: ->DSW, resched
493 DSW LCHx (timed wait) ->DSX, etc
495 7909 channel overview
500 ch_clc current location counter
503 ch_op channel opcode (bits <S,1:3,19>)
505 ch_cond interrupt conditions
506 ch_lcc control counter
507 ch_flags channel flags
511 IDLE - channel is not in operation
513 RDCx, SDCx, interrupt -> DSX
515 DSX - channel is executing data select
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.
523 The 7909 read process is driven by the device:
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
532 device timeout: set end, request channel
533 channel: disconnect on CPYD, send STOP
535 The 7909 write process is also driven by the device:
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
544 channel: memory to output buffer
545 device timeout: output buffer to device, set end, request channel
546 channel: disconnect on CPYD, send STOP
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.
553 /* Data select - called by RDS or WDS instructions - 7607/7289 only
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 */
562 t_stat
ch_op_ds (uint32 ch
, uint32 ds
, uint32 unit
)
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
;
575 ch_dso
[ch
] = ds
; /* set command, unit */
577 ch_flags
[ch
] &= ~(CHF_LDW
|CHF_EOR
|CHF_CMD
); /* clear flags */
582 /* Non-data select - called by BSR, BSF, WEF, REW, RUN, SDS instructions - 7607 only
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 */
591 t_stat
ch_op_nds (uint32 ch
, uint32 nds
, uint32 unit
)
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
;
606 ch_ndso
[ch
] = nds
; /* set command, unit */
611 /* End of data select - called from channel - 7607/7289 only
613 - If executing, set command trap flag
615 - If stacked nds, set up immediate channel timeout */
617 t_stat
ch6_end_ds (uint32 ch
)
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 */
625 else ch_sta
[ch
] = CHXS_IDLE
; /* else state = idle */
629 /* End of non-data select - called from I/O device completion - 7607/7289 only
632 - If stacked ds, set up immediate channel timeout */
634 t_stat
ch6_end_nds (uint32 ch
)
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 */
642 else ch_sta
[ch
] = CHXS_IDLE
; /* else state = idle */
646 /* Send select to device - 7607/7289 only */
648 t_stat
ch6_sel (uint32 ch
, uint32 sel
, uint32 unit
, uint32 sta
)
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 */
663 /* Channel unit service - called to start stacked command - 7607 only */
665 t_stat
ch6_svc (UNIT
*uptr
)
667 uint32 ch
= uptr
- &ch_unit
[0]; /* get channel */
670 if (ch
>= NUM_CHAN
) return SCPE_IERR
; /* invalid chan? */
671 switch (ch_sta
[ch
]) { /* case on state */
673 case CH6S_PDS
: /* polling for ds */
674 r
= ch6_sel (ch
, ch_dso
[ch
], ch_dsu
[ch
], CH6S_DSW
);
677 case CH6S_PNDS
: /* polling for nds */
678 r
= ch6_sel (ch
, ch_ndso
[ch
], ch_ndsu
[ch
], CH6S_NDS
);
685 if (r
== ERR_STALL
) { /* stalled? */
686 sim_activate (uptr
, ch_tpoll
); /* continue poll */
692 /* Map channel and unit number to device - all channels */
694 DEVICE
*ch_find_dev (uint32 ch
, uint32 unit
)
696 if (ch
>= NUM_CHAN
) return NULL
; /* invalid arg? */
697 if (ch_dev
[ch
].flags
& (DEV_7909
|DEV_7289
)) return ch2dev
[ch
];
699 if (((unit
>= U_MTBCD
) && (unit
<= (U_MTBCD
+ MT_NUMDR
))) ||
700 ((unit
>= U_MTBIN
) && (unit
<= (U_MTBIN
+ MT_NUMDR
))))
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
;
709 /* Start channel - channel is from opcode
711 7607: channel should have a data select operation pending (DSW state)
712 7909: channel should be idle (IDLE state) */
714 t_stat
ch_op_start (uint32 ch
, uint32 clc
, t_bool reset
)
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 */
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 */
733 ch_flags
[ch
] &= ~CHF_CLR_7909
; /* clear flags, not IP */
735 ch_sta
[ch
] = CHXS_DSX
; /* set state */
736 return ch9_new_cmd (ch
); /* start executing */
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
);
745 switch (ch_sta
[ch
]) { /* case on chan state */
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' */
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 */
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 */
769 else ch_clc
[ch
] = clc
; /* set clc */
770 return ch6_new_cmd (ch
, TRUE
); /* start channel */
772 case CHXS_DSX
: /* executing */
773 ch_flags
[ch
] = ch_flags
[ch
] | CHF_LDW
; /* flag pending LCH */
774 return ERR_STALL
; /* stall */
782 7607/7289 stores op,ca,nostore,clc
783 7909 stores clc,,ca */
785 t_stat
ch_op_store (uint32 ch
, t_uint64
*dat
)
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);
798 /* Store channel diagnostic
802 7909 stores 7909 lcc+flags */
804 t_stat
ch_op_store_diag (uint32 ch
, t_uint64
*dat
)
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
);
815 /* Reset data channel
818 7909 responds to RIC */
820 t_stat
ch_op_reset (uint32 ch
, t_bool ch7909
)
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 */
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 */
834 ch_reset (&ch_dev
[ch
]); /* reset channel */
835 if (dptr
&& dptr
->reset
) dptr
->reset (dptr
); /* reset device */
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.
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. */
846 t_stat
ch_proc (uint32 ch
)
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 */
856 uint32 csel
, sc
, tval
, mask
, ta
;
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 */
874 switch (ch_op
[ch
] & CH9_OPMASK
) { /* switch on op */
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 */
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 */
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
);
900 if (xfr
) ch_clc
[ch
] = ch_ca
[ch
] & CHAMASK
; /* change CLC */
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
;
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 */
916 case CH9_LAR
: /* load assembly reg */
917 ch_ar
[ch
] = ReadP (ch_ca
[ch
]);
920 case CH9_SAR
: /* store assembly reg */
921 WriteP (ch_ca
[ch
], ch_ar
[ch
]);
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 */
931 case CH9_LCC
: /* load control cntr */
932 ch_lcc
[ch
] = CH9A_LCC (ch_ca
[ch
]); /* from eff addr */
935 case CH9_ICC
: /* insert control cntr */
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 */
942 ch_ar
[ch
] = (ch_ar
[ch
] & ~(((t_uint64
) 077) << sc
)) |
943 (((t_uint64
) ch_lcc
[ch
]) << sc
);
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 */
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 */
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 */
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 */
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 */
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 */
989 if (ch_flags
[ch
] & CHF_EOR
) { /* EOR? */
990 ch_flags
[ch
] &= ~CHF_EOR
; /* clear flag */
991 break; /* new command */
993 return SCPE_OK
; /* wait for end */
995 if (ch_flags
[ch
] & CHF_RDS
) /* read? */
996 return ch9_rd_putw (ch
);
997 return ch9_wr_getw (ch
); /* no, write */
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? */
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 */
1013 return ch9_new_cmd (ch
); /* next command */
1016 else if (ch_flags
[ch
] & CHF_RDS
) { /* 7607 read? */
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 */
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 */
1025 case CH6_IOCD
: /* IOCD */
1026 if (ch_wc
[ch
]) { /* wc > 0? */
1027 if (ch6_rd_putw (ch
)) return SCPE_OK
; /* store; more? cont */
1029 return ch6_end_ds (ch
); /* no, disconnect */
1031 case CH6_IOCP
: /* IOCP */
1032 if (ch_wc
[ch
]) { /* wc > 0? */
1033 if (ch6_rd_putw (ch
)) return SCPE_OK
; /* store; more? cont */
1035 return ch6_new_cmd (ch
, FALSE
); /* unpack new cmd */
1037 case CH6_IOCT
: /* IOCT */
1038 if (ch_wc
[ch
]) { /* wc > 0? */
1039 if (ch6_rd_putw (ch
)) return SCPE_OK
; /* store; more? cont */
1041 return ch6_ioxt (ch
); /* unstall or disc */
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 */
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 */
1053 return ch6_new_cmd (ch
, FALSE
); /* next cmd */
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 */
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 */
1065 return ch6_ioxt (ch
); /* unstall or disc */
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 */
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 */
1077 return SCPE_OK
; /* done */
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 */
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 */
1089 return SCPE_OK
; /* done */
1096 else { /* 7607 write */
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 */
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 */
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? */
1110 return ch6_end_ds (ch
); /* disconnect */
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? */
1118 return ch6_new_cmd (ch
, FALSE
); /* get next cmd */
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? */
1126 return ch6_ioxt (ch
); /* get next cmd */
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? */
1133 ch_flags
[ch
] = ch_flags
[ch
] & ~CHF_EOR
; /* clear EOR */
1134 return ch6_new_cmd (ch
, FALSE
); /* get next cmd */
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? */
1141 ch_flags
[ch
] = ch_flags
[ch
] & ~CHF_EOR
; /* clear EOR */
1142 return ch6_ioxt (ch
); /* unstall or disc */
1147 } /* end else write */
1150 /* 7607 channel support routines */
1152 /* 7607 channel input routine - put one word to memory */
1154 t_bool
ch6_rd_putw (uint32 ch
)
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 */
1164 ch_wc
[ch
] = ch_wc
[ch
] - 1;
1166 return (ch_wc
[ch
]? TRUE
: FALSE
);
1169 /* 7607 channel output routine - get one word from memory */
1171 t_stat
ch6_wr_getw (uint32 ch
, t_bool eorz
)
1177 ch_flags
[ch
] = ch_flags
[ch
] & ~CHF_EOR
; /* clr eor */
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;
1184 if (eorz
&& (ch_wc
[ch
] == 0)) eorfl
= 1; /* eor on wc = 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? */
1194 /* 7607 channel new command - on channel load, check for disconnects
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.
1205 t_stat
ch6_new_cmd (uint32 ch
, t_bool ch_ld
)
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
);
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 */
1223 switch (op
) { /* case on opcode */
1225 case CH6_IOCD
: /* IOCD */
1226 if (ch_wc
[ch
] == 0) ch6_end_ds (ch
); /* wc 0? end now */
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 */
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 */
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
);
1252 case CH6_TCH
: /* TCH */
1253 ch_req
|= REQ_CH (ch
); /* immed ch req */
1256 default: /* all others */
1260 if (sim_brk_summ
&& sim_brk_test (t
, SWMASK ('E')))
1261 return ch_bkpt (ch
, t
);
1265 /* 7607 channel IOxT: if LCH stall, set state back to DSW; else disconnect and trap */
1267 t_stat
ch6_ioxt (uint32 ch
)
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 */
1274 ch_flags
[ch
] |= CHF_CMD
; /* set cmd trap flag */
1275 ch6_end_ds (ch
); /* disconnect */
1280 /* 7607 conditionally clear EOR on IOSx completion */
1282 void ch6_iosp_cclr (uint32 ch
)
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
++;
1295 if (ccnt
<= 11) return; /* <= 11? ok */
1297 ch_flags
[ch
] = ch_flags
[ch
] & ~CHF_EOR
; /* clear eor */
1301 /* 7607 external interface routines */
1303 /* Input - store word, request channel input service */
1305 t_stat
ch6_req_rd (uint32 ch
, uint32 unit
, t_uint64 val
, uint32 fl
)
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 */
1318 /* Disconnect on error */
1320 t_stat
ch6_err_disc (uint32 ch
, uint32 unit
, uint32 fl
)
1322 if (ch6_qconn (ch
, unit
)) { /* ch conn to caller? */
1323 ch_flags
[ch
] |= fl
; /* set flag */
1324 return ch6_end_ds (ch
); /* disconnect */
1329 /* Output - request channel output service */
1331 t_bool
ch6_req_wr (uint32 ch
, uint32 unit
)
1333 if (ch6_qconn (ch
, unit
)) { /* ch conn to caller? */
1334 ch_req
|= REQ_CH (ch
);
1335 ch_flags
[ch
] &= ~CHF_RDS
;
1340 /* Set/read channel flags */
1342 uint32
ch6_set_flags (uint32 ch
, uint32 unit
, uint32 flags
)
1344 if (ch6_qconn (ch
, unit
)) { /* ch conn to caller? */
1345 ch_flags
[ch
] = ch_flags
[ch
] | flags
;
1346 return ch_flags
[ch
];
1351 /* Channel connected to unit? */
1353 t_bool
ch6_qconn (uint32 ch
, uint32 unit
)
1355 if ((ch
< NUM_CHAN
) && /* valid chan */
1356 (ch_dsu
[ch
] == unit
)) return TRUE
; /* for right unit? */
1360 /* 7909 channel support routines */
1362 /* 7909 channel input routine - put one word to memory */
1364 t_stat
ch9_rd_putw (uint32 ch
)
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;
1375 /* 7909 channel output routine - get one word from memory */
1377 t_stat
ch9_wr_getw (uint32 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;
1385 return ch9_wr (ch
, ch_ar
[ch
], 0); /* write to device */
1388 /* 7909 send select to device */
1390 t_stat
ch9_sel (uint32 ch
, uint32 sel
)
1392 DEVICE
*dptr
= ch2dev
[ch
];
1395 if (dptr
== NULL
) return SCPE_IERR
;
1396 dibp
= (DIB
*) dptr
->ctxt
;
1397 if (dibp
&& dibp
->chsel
) return dibp
->chsel (ch
, sel
, 0);
1401 /* 7909 send word to device */
1403 t_stat
ch9_wr (uint32 ch
, t_uint64 dat
, uint32 fl
)
1405 DEVICE
*dptr
= ch2dev
[ch
];
1408 if (dptr
== NULL
) return SCPE_IERR
;
1409 dibp
= (DIB
*) dptr
->ctxt
;
1410 if (dibp
&& dibp
->write
) return dibp
->write (ch
, dat
, fl
);
1414 /* 7909 channel new command */
1416 t_stat
ch9_new_cmd (uint32 ch
)
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
);
1431 t_stat
ch9_exec_cmd (uint32 ch
, t_uint64 ir
)
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 */
1445 cpu_ent_hist (ch_clc
[ch
] | ((ch
+ 1) << HIST_V_CH
), ch_ca
[ch
], ir
, 0);
1447 switch (ch_op
[ch
]) { /* check initial cond */
1449 case CH9_LAR
: /* misc processing */
1456 if (ch_flags
[ch
] & (CHF_PRD
|CHF_PWR
|CHF_RDS
|CHF_WRS
))
1457 ch9_eval_int (ch
, CHINT_SEQC
); /* not during data */
1459 case CH9_TCM
: /* jumps */
1464 ch_req
|= REQ_CH (ch
); /* process in chan */
1467 case CH9_CTL
: /* control */
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! */
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 */
1484 case CH9_CPYD
: /* data transfers */
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! */
1495 case CH9_WTR
: /* wait */
1496 ch_sta
[ch
] = CHXS_IDLE
; /* stop */
1499 case CH9_TWT
: /* trap and wait */
1500 ch_sta
[ch
] = CHXS_IDLE
; /* stop */
1501 ch_flags
[ch
] |= CHF_TWT
; /* set trap */
1511 /* 7909 external interface routines */
1513 /* Input - store word, request channel input service */
1515 t_stat
ch9_req_rd (uint32 ch
, t_uint64 val
)
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 */
1528 void ch9_set_atn (uint32 ch
)
1530 if (ch
< NUM_CHAN
) ch9_eval_int (ch
, CHINT_ATN1
);
1534 /* Set IO check - UEND will occur at end - not recognized in int mode */
1536 void ch9_set_ioc (uint32 ch
)
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 */
1547 void ch9_set_end (uint32 ch
, uint32 iflags
)
1549 if (ch
< NUM_CHAN
) { /* valid chan? */
1550 ch_flags
[ch
] |= CHF_EOR
;
1551 ch9_eval_int (ch
, iflags
);
1556 /* Test connected */
1558 t_bool
ch9_qconn (uint32 ch
)
1560 if ((ch
< NUM_CHAN
) && (ch_sta
[ch
] == CHXS_DSX
)) return TRUE
;
1564 /* Evaluate interrupts
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
1572 This provides an effective stage of buffering for interrupt requests
1573 that are not immediately serviced */
1575 void ch9_eval_int (uint32 ch
, uint32 iflags
)
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 */
1596 /* Test for all channels idle */
1598 t_bool
ch_qidle (void)
1602 for (i
= 0; i
< NUM_CHAN
; i
++) {
1603 if (ch_sta
[i
] != CHXS_IDLE
) return FALSE
;
1608 /* Evaluate/execute channel traps */
1610 uint32
chtr_eval (uint32
*decr
)
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 */
1620 return CHTR_CLK_SAV
;
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 */
1629 return (CHTR_CHA_SAV
+ (i
<< 1));
1631 if (cme
&& (ch_flags
[i
] & CHF_EOF
)) { /* eof enab and set? */
1632 if (decr
) { /* exec? */
1633 ch_flags
[i
] &= ~CHF_EOF
; /* clr flag */
1636 return (CHTR_CHA_SAV
+ (i
<< 1));
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 */
1644 return (CHTR_CHA_SAV
+ (i
<< 1));
1645 } /* end if BIT_TST */
1647 } /* end if !chtr_inht */
1648 if (decr
) *decr
= 0;
1654 t_stat
ch_reset (DEVICE
*dptr
)
1656 uint32 ch
= dptr
- &ch_dev
[0]; /* get channel */
1658 if (ch
== CH_A
) ch2dev
[ch
] = &mt_dev
[0]; /* channel A fixed */
1674 sim_cancel (&ch_unit
[ch
]);
1678 /* Show channel type */
1680 t_stat
ch_show_type (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
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
);
1692 /* Enable channel, assign device */
1694 t_stat
ch_set_enable (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1696 DEVICE
*dptr
, *dptr1
;
1697 char gbuf
[CBUFSIZE
];
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
;
1714 return reset_all (0);
1720 /* Map device flags to device pointer */
1722 DEVICE
*ch_map_flags (uint32 ch
, int32 fl
)
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
;
1731 /* Set up channel map */
1733 void ch_set_map (void)
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
);
1744 /* Disable channel, deassign device */
1746 t_stat
ch_set_disable (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1748 DEVICE
*dptr
, *dptr1
;
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
;
1757 if (dptr1
== NULL
) return SCPE_IERR
;
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
);
1765 dptr
->flags
&= ~(DEV_7909
|DEV_7289
);
1766 dptr
->flags
|= DEV_DIS
;
1767 dptr1
->flags
|= DEV_DIS
;
1768 return reset_all (0);
1771 /* Show channel that device is on (tapes, 7289, 7909 only) */
1773 t_stat
ch_show_chan (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1778 dptr
= find_dev_from_unit (uptr
);
1780 for (i
= 0; i
< NUM_CHAN
; i
++) {
1781 if (ch2dev
[i
] == dptr
) {
1782 fprintf (st
, "channel %c", 'A' + i
);
1787 fprintf (st
, "not assigned to channel");