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