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