1 /* i7094_com.c: IBM 7094 7750 communications interface simulator
2
3 Copyright (c) 2005-2010, 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 com 7750 controller
27 coml 7750 lines
28
29 12-Aug-10 RMS Major rewrite for CTSS (Dave Pitts)
30 19-Nov-08 RMS Revised for common TMXR show routines
31
32 This module implements an abstract simulator for the IBM 7750 communications
33 computer as used by the CTSS system. The 7750 supports up to 112 lines;
34 the simulator supports 33. The 7750 can handle both high-speed lines, in
35 6b and 12b mode, and normal terminals, in 12b mode only; the simulator
36 supports only terminals. The 7750 can handle many different kinds of
37 terminals; the simulator supports only a limited subset.
38
39 Input is asynchronous and line buffered. When valid input (a line or a
40 control message) is available, the 7750 sets ATN1 to signal availability of
41 input. When the 7094 issues a CTLRN, the 7750 gathers available input characters
42 into a message. The message has a 12b sequence number, followed by 12b line
43 number/character pairs, followed by end-of-medium (03777). Input characters
44 can either be control characters (bit 02000 set) or data characters. Data
45 characters are 1's complemented and are 8b wide: 7 data bits and 1 parity
46 bit (which may be 0).
47
48 Output is synchronous. When the 7094 issues a CTLWN, the 7750 interprets
49 the channel output as a message. The message has a 12b line number, followed
50 by a 12b character count, followed by characters, followed by end-of-medium.
51 If bit 02000 of the line number is set, the characters are 12b wide. If
52 bit 01000 is set, the message is a control message. 12b characters consist
53 of 7 data bits, 1 parity bit, and 1 start bit. Data characters are 1's
54 complemented. Data character 03777 is special and causes the 7750 to
55 repeat the previous bit for the number of bit times specified in the next
56 character. This is used to generate delays for positioning characters.
57
58 The 7750 supports flow control for output. To help the 7094 account for
59 usage of 7750 buffer memory, the 7750 sends 'character output completion'
60 messages for every 'n' characters output on a line, where n <= 31.
61
62 Note that the simulator console is mapped in as line n+1.
63 */
64
65 #include "i7094_defs.h"
66 #include "sim_sock.h"
67 #include "sim_tmxr.h"
68 #include <ctype.h>
69
70 #define COM_MLINES 31 /* mux lines */
71 #define COM_TLINES (COM_MLINES + 1) /* total lines */
72 #define COM_BUFSIZ 120 /* max chan transfer */
73 #define COM_PKTSIZ 16384 /* character buffer */
74
75 #define UNIT_V_2741 (TTUF_V_UF + 0) /* 2741 - ni */
76 #define UNIT_V_K35 (TTUF_V_UF + 1) /* KSR-35 */
77 #define UNIT_2741 (1 << UNIT_V_2741)
78 #define UNIT_K35 (1 << UNIT_V_K35)
79
80 #define CONN u3 /* line is connected */
81 #define NEEDID u4 /* need to send ID */
82 #define NOECHO u5 /* no echo */
83 #define INPP u6 /* input pending */
84
85 #define COM_INIT_POLL 8000 /* polling interval */
86 #define COMC_WAIT 2 /* channel delay time */
87 #define COML_WAIT 1000 /* char delay time */
88 #define COM_LBASE 4 /* start of lines */
89
90 /* Input threads */
91
92 #define COM_PLU 0 /* multiplexor poll */
93 #define COM_CIU 1 /* console input */
94 #define COM_CHU 2 /* channel transfer */
95 #define COM_SNS 3 /* sense transfer */
96
97 /* Communications input */
98
99 #define COMI_VALIDL 02000 /* valid line flag */
100 #define COMI_PARITY 00200 /* parity bit */
101 #define COMI_DIALUP 02001 /* dialup */
102 #define COMI_ENDID 02002 /* end ID */
103 #define COMI_INTR 02003 /* interrupt */
104 #define COMI_QUIT 02004 /* quit */
105 #define COMI_HANGUP 02005 /* hangup */
106 #define COMI_EOM 03777 /* end of medium */
107 #define COMI_COMP(x) ((uint16) (03000 + ((x) & COMI_CMAX)))
108 #define COMI_K35 1 /* KSR-35 ID */
109 #define COMI_K37 7 /* KSR-37 ID */
110 #define COMI_2741 8 /* 2741 ID */
111 #define COMI_CMAX 31 /* max chars returned */
112 #define COMI_BMAX 50 /* buffer max, words */
113 #define COMI_12BMAX ((3 * COMI_BMAX) - 1) /* last 12b char */
114
115 /* Communications output */
116
117 #define COMO_LIN12B 0200000000000 /* line is 12b */
118 #define COMO_LINCTL 0100000000000 /* control msg */
119 #define COMO_GETLN(x) (((uint32) ((x) >> 24)) & 0777)
120 #define COMO_CTLRST 00000 /* control reset */
121 #define COMO_BITRPT 03777 /* bit repeat */
122 #define COMO_EOM12B 07777 /* end of medium */
123 #define COMO_BMAX 94 /* buffer max, words */
124 #define COMO_12BMAX ((3 * COMO_BMAX) - 1)
125
126 /* Status word (60b) */
127
128 #define COMS_PCHK 004000000000000000000 /* prog check */
129 #define COMS_DCHK 002000000000000000000 /* data check */
130 #define COMS_EXCC 001000000000000000000 /* exc cond */
131 #define COMS_MLNT 000040000000000000000 /* message length check */
132 #define COMS_CHNH 000020000000000000000 /* channel hold */
133 #define COMS_CHNQ 000010000000000000000 /* channel queue full */
134 #define COMS_ITMO 000000100000000000000 /* interface timeout */
135 #define COMS_DATR 000000004000000000000 /* data message ready */
136 #define COMS_INBF 000000002000000000000 /* input buffer free */
137 #define COMS_SVCR 000000001000000000000 /* service message ready */
138 #define COMS_PALL 000000000000000000000
139 #define COMS_DALL 000000000000000000000
140 #define COMS_EALL 000000000000000000000
141 #define COMS_DYN 000000007000000000000
142
143 /* Report variables */
144
145 #define COMR_FQ 1 /* free queue */
146 #define COMR_IQ 2 /* input queue */
147 #define COMR_OQ 4 /* output queue */
148
149 /* List heads and entries */
150
151 typedef struct {
152 uint16 head;
153 uint16 tail;
154 } LISTHD;
155
156 typedef struct {
157 uint16 next;
158 uint16 data;
159 } LISTENT;
160
161 /* The 7750 character buffer is maintained as linked lists. The lists are:
162
163 free free list
164 inpq[ln] input queue for line n
165 outq[ln] output queue for line ln
166
167 Links are done as subscripts in array com_pkt. This allows the list
168 headers and the queues themselves to be saved and restored. */
169
170 uint32 com_ch = CH_E; /* saved channel */
171 uint32 com_enab = 0; /* 7750 enabled */
172 uint32 com_msgn = 0; /* next input msg num */
173 uint32 com_sta = 0; /* 7750 state */
174 uint32 com_stop = 0; /* channel stop */
175 uint32 com_quit = 003; /* quit code */
176 uint32 com_intr = 0; /* interrupt code */
177 uint32 com_bptr = 0; /* buffer pointer */
178 uint32 com_blim = 0; /* buffer count */
179 uint32 com_tps = 50; /* polls/second */
180 t_uint64 com_sns = 0; /* sense word */
181 t_uint64 com_chob = 0; /* chan output buf */
182 uint32 com_chob_v = 0; /* valid flag */
183 t_uint64 com_buf[COM_BUFSIZ]; /* channel buffer */
184 LISTHD com_free; /* free list */
185 uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */
186 LISTHD com_inpq[COM_TLINES] = { 0 }; /* input queues */
187 LISTHD com_outq[COM_TLINES] = { 0 }; /* output queues */
188 LISTENT com_pkt[COM_PKTSIZ]; /* character packets */
189 TMLN com_ldsc[COM_MLINES] = { 0 }; /* line descriptors */
190 TMXR com_desc = { COM_MLINES, 0, 0, com_ldsc }; /* mux descriptor */
191
192 /* Even parity truth table */
193
194 static const uint8 com_epar[128] = {
195 0, 1, 1, 0, 1, 0, 0, 1,
196 1, 0, 0, 1, 0, 1, 1, 0,
197 1, 0, 0, 1, 0, 1, 1, 0,
198 0, 1, 1, 0, 1, 0, 0, 1,
199 1, 0, 0, 1, 0, 1, 1, 0,
200 0, 1, 1, 0, 1, 0, 0, 1,
201 0, 1, 1, 0, 1, 0, 0, 1,
202 1, 0, 0, 1, 0, 1, 1, 0,
203 1, 0, 0, 1, 0, 1, 1, 0,
204 0, 1, 1, 0, 1, 0, 0, 1,
205 0, 1, 1, 0, 1, 0, 0, 1,
206 1, 0, 0, 1, 0, 1, 1, 0,
207 0, 1, 1, 0, 1, 0, 0, 1,
208 1, 0, 0, 1, 0, 1, 1, 0,
209 1, 0, 0, 1, 0, 1, 1, 0,
210 0, 1, 1, 0, 1, 0, 0, 1
211 };
212
213 extern uint32 ch_req;
214
215 t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit);
216 t_stat com_chwr (uint32 ch, t_uint64 val, uint32 flags);
217 t_stat comi_svc (UNIT *uptr);
218 t_stat comc_svc (UNIT *uptr);
219 t_stat como_svc (UNIT *uptr);
220 t_stat coms_svc (UNIT *uptr);
221 t_stat comti_svc (UNIT *uptr);
222 t_stat comto_svc (UNIT *uptr);
223 t_stat com_reset (DEVICE *dptr);
224 t_stat com_attach (UNIT *uptr, char *cptr);
225 t_stat com_detach (UNIT *uptr);
226 t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc);
227 t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc);
228 t_stat com_show_allq (FILE *st, UNIT *uptr, int32 val, void *desc);
229 t_stat com_show_oneq (FILE *st, UNIT *uptr, int32 val, void *desc);
230 void com_reset_ln (uint32 i);
231 uint16 com_get_nexti (uint32 *ln);
232 uint16 com_gethd_free (LISTHD *lh);
233 uint16 com_gethd (LISTHD *lh);
234 uint16 com_gettl_free (LISTHD *lh);
235 uint16 com_gettl (LISTHD *lh);
236 t_bool com_new_puttl (LISTHD *lh, uint16 val);
237 void com_puttl (LISTHD *lh, uint16 ent);
238 t_bool com_test_inp (void);
239 void com_set_inpp (uint32 ln);
240 t_uint64 com_getob (uint32 ch);
241 t_bool com_qdone (uint32 ch);
242 void com_end (uint32 ch, uint32 fl, uint32 st);
243 t_stat com_send_id (uint32 ln);
244 uint32 com_gen_ccmp (uint32 ln);
245 t_bool com_queue_in (uint32 ln, uint32 ch);
246 uint32 com_queue_out (uint32 ln, uint32 *c1);
247 void com_set_sns (t_uint64 stat);
248
249 /* COM data structures
250
251 com_dev COM device descriptor
252 com_unit COM unit descriptor
253 com_reg COM register list
254 com_mod COM modifiers list
255 */
256
257 DIB com_dib = { &com_chsel, &com_chwr };
258
259 UNIT com_unit[] = {
260 { UDATA (&comi_svc, UNIT_ATTABLE, 0), COM_INIT_POLL },
261 { UDATA (&comti_svc, UNIT_DIS, 0), KBD_POLL_WAIT },
262 { UDATA (&comc_svc, UNIT_DIS, 0), COMC_WAIT },
263 { UDATA (&coms_svc, UNIT_DIS, 0), COMC_WAIT }
264 };
265
266 UNIT coml_unit[] = {
267 { UDATA (&como_svc, 0, 0), COML_WAIT },
268 { UDATA (&como_svc, 0, 0), COML_WAIT },
269 { UDATA (&como_svc, 0, 0), COML_WAIT },
270 { UDATA (&como_svc, 0, 0), COML_WAIT },
271 { UDATA (&como_svc, 0, 0), COML_WAIT },
272 { UDATA (&como_svc, 0, 0), COML_WAIT },
273 { UDATA (&como_svc, 0, 0), COML_WAIT },
274 { UDATA (&como_svc, 0, 0), COML_WAIT },
275 { UDATA (&como_svc, 0, 0), COML_WAIT },
276 { UDATA (&como_svc, 0, 0), COML_WAIT },
277 { UDATA (&como_svc, 0, 0), COML_WAIT },
278 { UDATA (&como_svc, 0, 0), COML_WAIT },
279 { UDATA (&como_svc, 0, 0), COML_WAIT },
280 { UDATA (&como_svc, 0, 0), COML_WAIT },
281 { UDATA (&como_svc, 0, 0), COML_WAIT },
282 { UDATA (&como_svc, 0, 0), COML_WAIT },
283 { UDATA (&como_svc, 0, 0), COML_WAIT },
284 { UDATA (&como_svc, 0, 0), COML_WAIT },
285 { UDATA (&como_svc, 0, 0), COML_WAIT },
286 { UDATA (&como_svc, 0, 0), COML_WAIT },
287 { UDATA (&como_svc, 0, 0), COML_WAIT },
288 { UDATA (&como_svc, 0, 0), COML_WAIT },
289 { UDATA (&como_svc, 0, 0), COML_WAIT },
290 { UDATA (&como_svc, 0, 0), COML_WAIT },
291 { UDATA (&como_svc, 0, 0), COML_WAIT },
292 { UDATA (&como_svc, 0, 0), COML_WAIT },
293 { UDATA (&como_svc, 0, 0), COML_WAIT },
294 { UDATA (&como_svc, 0, 0), COML_WAIT },
295 { UDATA (&como_svc, 0, 0), COML_WAIT },
296 { UDATA (&como_svc, 0, 0), COML_WAIT },
297 { UDATA (&como_svc, 0, 0), COML_WAIT },
298 { UDATA (&comto_svc, 0, 0), COML_WAIT },
299 };
300
301 REG com_reg[] = {
302 { FLDATA (ENABLE, com_enab, 0) },
303 { ORDATA (STATE, com_sta, 6) },
304 { ORDATA (MSGNUM, com_msgn, 12) },
305 { ORDATA (SNS, com_sns, 60) },
306 { ORDATA (CHOB, com_chob, 36) },
307 { FLDATA (CHOBV, com_chob_v, 0) },
308 { FLDATA (STOP, com_stop, 0) },
309 { ORDATA (QUIT, com_quit, 7) },
310 { ORDATA (INTR, com_intr, 7) },
311 { BRDATA (BUF, com_buf, 8, 36, COM_BUFSIZ) },
312 { DRDATA (BPTR, com_bptr, 7), REG_RO },
313 { DRDATA (BLIM, com_blim, 7), REG_RO },
314 { BRDATA (NRET, com_not_ret, 10, 32, COM_TLINES), REG_RO + PV_LEFT },
315 { URDATA (NEEDID, coml_unit[0].NEEDID, 8, 1, 0, COM_TLINES, 0) },
316 { URDATA (NOECHO, coml_unit[0].NOECHO, 8, 1, 0, COM_TLINES, 0) },
317 { URDATA (INPP, coml_unit[0].INPP, 8, 1, 0, COM_TLINES, 0) },
318 { BRDATA (FREEQ, &com_free, 10, 16, 2) },
319 { BRDATA (INPQ, com_inpq, 10, 16, 2 * COM_TLINES) },
320 { BRDATA (OUTQ, com_outq, 10, 16, 2 * COM_TLINES) },
321 { BRDATA (PKTB, com_pkt, 10, 16, 2 * COM_PKTSIZ) },
322 { DRDATA (TTIME, com_unit[COM_CIU].wait, 24), REG_NZ + PV_LEFT },
323 { DRDATA (WTIME, com_unit[COM_CHU].wait, 24), REG_NZ + PV_LEFT },
324 { DRDATA (CHAN, com_ch, 3), REG_HRO },
325 { NULL }
326 };
327
328 MTAB com_mod[] = {
329 { UNIT_ATT, UNIT_ATT, "summary", NULL,
330 NULL, &tmxr_show_summ, (void *) &com_desc },
331 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
332 NULL, &tmxr_show_cstat, (void *) &com_desc },
333 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
334 NULL, &tmxr_show_cstat, (void *) &com_desc },
335 { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_FQ, "FREEQ", NULL,
336 NULL, &com_show_ctrl, 0 },
337 { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_IQ, "INPQ", NULL,
338 NULL, &com_show_ctrl, 0 },
339 { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_OQ, "OUTQ", NULL,
340 NULL, &com_show_ctrl, 0 },
341 { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL,
342 NULL, &com_show_ctrl, 0 },
343 { 0 }
344 };
345
346 DEVICE com_dev = {
347 "COM", com_unit, com_reg, com_mod,
348 3, 10, 31, 1, 16, 8,
349 &tmxr_ex, &tmxr_dep, &com_reset,
350 NULL, &com_attach, &com_detach,
351 &com_dib, DEV_NET | DEV_DIS
352 };
353
354 /* COML data structures
355
356 coml_dev COML device descriptor
357 coml_unit COML unit descriptor
358 coml_reg COML register list
359 coml_mod COML modifiers list
360 */
361
362 MTAB coml_mod[] = {
363 { UNIT_K35+UNIT_2741, 0 , "KSR-37", "KSR-37", NULL },
364 { UNIT_K35+UNIT_2741, UNIT_K35 , "KSR-35", "KSR-35", NULL },
365 // { UNIT_K35+UNIT_2741, UNIT_2741, "2741", "2741", NULL },
366 { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
367 &tmxr_dscln, NULL, (void *) &com_desc },
368 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
369 &tmxr_set_log, &tmxr_show_log, (void*) &com_desc },
370 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
371 &tmxr_set_nolog, NULL, (void *) &com_desc },
372 { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "INPQ", NULL,
373 NULL, &com_show_oneq, 0 },
374 { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "OUTQ", NULL,
375 NULL, &com_show_oneq, 0 },
376 { 0 }
377 };
378
379 REG coml_reg[] = {
380 { URDATA (TIME, coml_unit[0].wait, 10, 24, 0,
381 COM_TLINES, REG_NZ + PV_LEFT) },
382 { NULL }
383 };
384
385 DEVICE coml_dev = {
386 "COML", coml_unit, coml_reg, coml_mod,
387 COM_TLINES, 10, 31, 1, 16, 8,
388 NULL, NULL, &com_reset,
389 NULL, NULL, NULL,
390 NULL, DEV_DIS
391 };
392
393 /* COM: channel select */
394
com_chsel(uint32 ch,uint32 sel,uint32 unit)395 t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit)
396 {
397 com_ch = ch; /* save channel */
398 if (sim_is_active (&com_unit[COM_CHU]) || /* not idle? */
399 sim_is_active (&com_unit[COM_SNS])) {
400 com_end (ch, CHINT_SEQC, 0); /* end, seq check */
401 return SCPE_OK;
402 }
403
404 switch (sel) { /* case on select */
405
406 case CHSL_RDS: /* read */
407 case CHSL_WRS: /* write */
408 com_sns = 0; /* clear status */
409 sim_activate (&com_unit[COM_CHU], com_unit[COM_CHU].wait);
410 break;
411
412 case CHSL_SNS: /* sense */
413 sim_activate (&com_unit[COM_SNS], com_unit[COM_SNS].wait);
414 break;
415
416 case CHSL_CTL: /* control */
417 default: /* other */
418 return STOP_ILLIOP;
419 }
420
421 com_stop = 0; /* clear stop */
422 com_sta = sel; /* set initial state */
423 return SCPE_OK;
424 }
425
426 /* Channel write, from 7909 channel program */
427
com_chwr(uint32 ch,t_uint64 val,uint32 stopf)428 t_stat com_chwr (uint32 ch, t_uint64 val, uint32 stopf)
429 {
430 if (stopf)
431 com_stop = 1;
432 else {
433 com_chob = val; /* store data */
434 com_chob_v = 1; /* set valid */
435 }
436 return SCPE_OK;
437 }
438
439 /* Unit service - SNS */
440
coms_svc(UNIT * uptr)441 t_stat coms_svc (UNIT *uptr)
442 {
443 t_uint64 dat;
444
445 switch (com_sta) { /* case on state */
446
447 case CHSL_SNS: /* prepare data */
448 com_sns &= ~COMS_DYN; /* clear dynamic flags */
449 if (com_free.head) /* free space? */
450 com_set_sns (COMS_INBF);
451 if (com_test_inp ()) /* pending input? */
452 com_set_sns (COMS_DATR);
453 com_buf[0] = (com_sns >> 24) & DMASK; /* buffer is 2 words */
454 com_buf[1] = (com_sns << 12) & DMASK;
455 com_bptr = 0;
456 com_blim = 2;
457 com_sta = CHSL_SNS|CHSL_2ND; /* 2nd state */
458 break;
459
460 case CHSL_SNS|CHSL_2ND: /* second state */
461 if (com_bptr >= com_blim) { /* end of buffer? */
462 ch9_set_end (com_ch, 0); /* set end */
463 ch_req |= REQ_CH (com_ch); /* request channel */
464 com_sta = CHSL_SNS|CHSL_3RD; /* 3rd state */
465 sim_activate (uptr, 10 * uptr->wait); /* longer wait */
466 return SCPE_OK;
467 }
468 dat = com_buf[com_bptr++]; /* get word */
469 if (!com_stop) /* send wd to chan */
470 ch9_req_rd (com_ch, dat);
471 break;
472
473 case CHSL_SNS|CHSL_3RD: /* 3rd state */
474 if (com_qdone (com_ch)) /* done? exit */
475 return SCPE_OK;
476 com_sta = CHSL_SNS; /* repeat sequence */
477 break;
478 }
479
480 sim_activate (uptr, uptr->wait); /* sched next */
481 return SCPE_OK;
482 }
483
484 /* Unit service - channel program */
485
comc_svc(UNIT * uptr)486 t_stat comc_svc (UNIT *uptr)
487 {
488 uint32 i, j, k, ccnt, ln, uln;
489 uint16 chr, ent;
490 t_uint64 dat;
491
492 switch (com_sta) { /* case on state */
493
494 case CHSL_RDS: /* read start */
495 for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */
496 com_buf[i] = 0;
497 com_buf[0] = com_msgn; /* 1st char is msg num */
498 com_msgn = (com_msgn + 1) & 03777; /* incr msg num */
499 for (i = 1, j = 0, ln = 0; /* check all lines */
500 (ln < COM_TLINES) && (i < COMI_12BMAX); /* until buffer full */
501 ln++) {
502 chr = (uint16) com_gen_ccmp (ln); /* completion msg? */
503 if ((chr == 0) && coml_unit[ln].INPP) { /* no, line input? */
504 ent = com_gethd_free (&com_inpq[ln]); /* get first char */
505 if (ent != 0) /* any input? */
506 chr = com_pkt[ent].data; /* return char */
507 else coml_unit[i].INPP = 0; /* this line is idle */
508 } /* end if input pending */
509 if (chr != 0) { /* got something? */
510 if ((i++ % 3) == 0) /* next word? */
511 j++;
512 com_buf[j] = (com_buf[j] << 12) | /* pack line number */
513 ((t_uint64) ((ln + COM_LBASE) | COMI_VALIDL));
514 if ((i++ % 3) == 0) /* next word? */
515 j++;
516 com_buf[j] = (com_buf[j] << 12) | /* pack data */
517 ((t_uint64) (chr & 07777));
518 } /* end if char */
519 } /* end for buffer */
520 for (k = i % 3; k < 3; k++) { /* fill with EOM */
521 if (k == 0) /* next word? */
522 j++;
523 com_buf[j] = (com_buf[j] << 12) | COMI_EOM;
524 }
525 com_bptr = 0; /* init buf ptr */
526 com_blim = j + 1; /* save buf size */
527 com_sta = CHSL_RDS|CHSL_2ND; /* next state */
528 break;
529
530 case CHSL_RDS|CHSL_2ND: /* read xmit word */
531 if (com_bptr >= com_blim) /* transfer done? */
532 com_end (com_ch, 0, CHSL_RDS|CHSL_3RD); /* end, next state */
533 else { /* more to do */
534 dat = com_buf[com_bptr++]; /* get word */
535 if (!com_stop) /* give to channel */
536 ch9_req_rd (com_ch, dat);
537 }
538 break;
539
540 case CHSL_RDS|CHSL_3RD: /* read end */
541 if (com_qdone (com_ch)) { /* done? */
542 if (com_test_inp ()) /* more data waiting? */
543 ch9_set_atn (com_ch);
544 return SCPE_OK; /* exit */
545 }
546 com_sta = CHSL_RDS; /* repeat sequence */
547 break;
548
549 case CHSL_WRS: /* write start */
550 for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */
551 com_buf[i] = 0;
552 com_bptr = 0; /* init buf ptr */
553 com_sta = CHSL_WRS|CHSL_2ND; /* next state */
554 ch_req |= REQ_CH (com_ch); /* request channel */
555 com_chob = 0; /* clr, inval buf */
556 com_chob_v = 0;
557 break;
558
559 case CHSL_WRS|CHSL_2ND: /* write first word */
560 dat = com_getob (com_ch); /* get word? */
561 if (dat == 0777777777777) { /* turn on? */
562 com_enab = 1; /* enable 7750 */
563 com_msgn = 0; /* init message # */
564 com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */
565 }
566 else if (dat & COMO_LINCTL) { /* control message? */
567 ln = COMO_GETLN (dat); /* line number */
568 if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */
569 return STOP_INVLIN;
570 chr = (uint16) ((dat >> 12) & 07777); /* control message */
571 if (chr != COMO_CTLRST) /* char must be 0 */
572 return STOP_INVMSG;
573 if (ln >= COM_LBASE)
574 com_reset_ln (ln - COM_LBASE);
575 com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */
576 }
577 else { /* data message */
578 ccnt = (((uint32) dat >> 12) & 07777) + 1; /* char count plus EOM */
579 if (dat & COMO_LIN12B) /* 12b? double */
580 ccnt = ccnt << 1;
581 com_blim = (ccnt + 6 + 5) / 6; /* buffer limit */
582 if ((com_blim == 1) || (com_blim >= COMO_BMAX))
583 return STOP_INVMSG;
584 com_buf[com_bptr++] = dat; /* store word */
585 com_sta = CHSL_WRS|CHSL_3RD; /* next state */
586 ch_req |= REQ_CH (com_ch); /* request channel */
587 }
588 break;
589
590 case CHSL_WRS|CHSL_3RD: /* other words */
591 dat = com_getob (com_ch); /* get word */
592 com_buf[com_bptr++] = dat; /* store word */
593 if (com_bptr >= com_blim) { /* transfer done? */
594 ln = COMO_GETLN (com_buf[0]); /* line number */
595 if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */
596 return STOP_INVLIN;
597 if ((com_buf[0] & COMO_LIN12B) && /* 12b message? */
598 (ln >= COM_LBASE)) {
599 uln = ln - COM_LBASE; /* unit number */
600 for (i = 2, j = 0; i < COMO_12BMAX; i++) { /* unpack 12b char */
601 if ((i % 3) == 0)
602 j++;
603 chr = (uint16) (com_buf[j] >> ((2 - (i % 3)) * 12)) & 07777;
604 if (chr == COMO_EOM12B) /* EOM? */
605 break;
606 if (!com_new_puttl (&com_outq[uln], chr))
607 return STOP_NOOFREE; /* append to outq */
608 }
609 sim_activate (&coml_unit[uln], coml_unit[uln].wait);
610 }
611 com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */
612 }
613 else if (!com_stop) /* request channel */
614 ch_req |= REQ_CH (com_ch);
615 break;
616
617 case CHSL_WRS|CHSL_4TH: /* buffer done */
618 if (com_qdone (com_ch)) /* done? */
619 return SCPE_OK; /* exit */
620 com_sta = CHSL_WRS; /* repeat sequence */
621 break;
622
623 default:
624 return SCPE_IERR;
625 }
626
627 sim_activate (uptr, uptr->wait);
628 return SCPE_OK;
629 }
630
631 /* Unit service - console receive - always running, even if device is not */
632
comti_svc(UNIT * uptr)633 t_stat comti_svc (UNIT *uptr)
634 {
635 int32 c, ln = COM_MLINES;
636 uint16 ent;
637
638 sim_activate (uptr, uptr->wait); /* continue poll */
639 c = sim_poll_kbd (); /* get character */
640 if (c && !(c & (SCPE_BREAK|SCPE_KFLAG))) /* error? */
641 return c;
642 if (!com_enab || (c & SCPE_BREAK)) /* !enab, break? done */
643 return SCPE_OK;
644 if (coml_unit[ln].NEEDID) /* ID needed? */
645 return com_send_id (ln);
646 if ((c & SCPE_KFLAG) && ((c = c & 0177) != 0)) { /* char input? */
647 if ((c == 0177) || (c == '\b')) { /* delete? */
648 ent = com_gettl_free (&com_inpq[ln]); /* remove last char */
649 if (!coml_unit[ln].NOECHO)
650 sim_putchar (ent? '\b': '\a');
651 return SCPE_OK;
652 }
653 if (!com_queue_in (ln, c)) /* add to inp queue */
654 return STOP_NOIFREE;
655 if (!coml_unit[ln].NOECHO) { /* echo enabled? */
656 if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) /* printable? */
657 sim_putchar (c);
658 if (c == '\r') /* line end? */
659 sim_putchar ('\n');
660 }
661 }
662 return SCPE_OK; /* set ATN if input */
663 }
664
665 /* Unit service - receive side
666
667 Poll all active lines for input
668 Poll for new connections */
669
comi_svc(UNIT * uptr)670 t_stat comi_svc (UNIT *uptr)
671 {
672 int32 c, ln, t;
673 uint16 ent;
674
675 if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
676 return SCPE_OK;
677 t = sim_rtcn_calb (com_tps, TMR_COM); /* calibrate */
678 sim_activate (uptr, t); /* continue poll */
679 if (!com_enab) /* not enabled? exit */
680 return SCPE_OK;
681 ln = tmxr_poll_conn (&com_desc); /* look for connect */
682 if (ln >= 0) { /* got one? */
683 com_ldsc[ln].rcve = 1; /* rcv enabled */
684 coml_unit[ln].CONN = 1; /* flag connected */
685 coml_unit[ln].NEEDID = 1; /* need ID */
686 coml_unit[ln].NOECHO = 0; /* echo enabled */
687 coml_unit[ln].INPP = 0; /* no input pending */
688 }
689 tmxr_poll_rx (&com_desc); /* poll for input */
690 for (ln = 0; ln < COM_MLINES; ln++) { /* loop thru mux */
691 if (com_ldsc[ln].conn) { /* connected? */
692 if (coml_unit[ln].NEEDID)
693 return com_send_id (ln);
694 c = tmxr_getc_ln (&com_ldsc[ln]); /* get char */
695 if (c) { /* any char? */
696 c = c & 0177; /* mask to 7b */
697 if ((c == 0177) || (c == '\b')) { /* delete? */
698 ent = com_gettl_free (&com_inpq[ln]); /* remove last char */
699 if (!coml_unit[ln].NOECHO)
700 tmxr_putc_ln (&com_ldsc[ln], ent? '\b': '\a');
701 return SCPE_OK;
702 }
703 if (!com_queue_in (ln, c)) /* queue char, err? */
704 return STOP_NOIFREE;
705 if (com_ldsc[ln].xmte) { /* output enabled? */
706 if (!coml_unit[ln].NOECHO) { /* echo enabled? */
707 if (sim_tt_outcvt (c, TT_MODE_7P) >= 0)
708 tmxr_putc_ln (&com_ldsc[ln], c);
709 if (c == '\r') /* add LF after CR */
710 tmxr_putc_ln (&com_ldsc[ln], '\n');
711 }
712 tmxr_poll_tx (&com_desc); /* poll xmt */
713 } /* end if enabled */
714 } /* end if char */
715 } /* end if conn */
716 else if (coml_unit[ln].CONN) { /* not conn, was conn? */
717 coml_unit[ln].CONN = 0; /* clear connected */
718 coml_unit[ln].NEEDID = 0; /* clear need id */
719 com_set_inpp (ln); /* input pending, ATN1 */
720 if (!com_new_puttl (&com_inpq[ln], COMI_HANGUP))/* hangup message */
721 return STOP_NOIFREE;
722 }
723 } /* end for */
724 return SCPE_OK;
725 }
726
727 /* Unit service - console transmit */
728
comto_svc(UNIT * uptr)729 t_stat comto_svc (UNIT *uptr)
730 {
731 uint32 ln = COM_MLINES;
732 uint32 c, c1;
733
734 c = com_queue_out (ln, &c1); /* get character, cvt */
735 if (c) /* printable? output */
736 sim_putchar (c);
737 if (c1) /* second char? output */
738 sim_putchar (c1);
739 if (com_outq[ln].head == 0) /* line idle? */
740 ch9_set_atn (com_ch); /* set ATN1 */
741 else sim_activate (uptr, uptr->wait); /* next char */
742 return SCPE_OK;
743 }
744
745 /* Unit service - transmit side */
746
como_svc(UNIT * uptr)747 t_stat como_svc (UNIT *uptr)
748 {
749 uint32 c, c1;
750 int32 ln = uptr - coml_unit; /* line # */
751
752 if (com_ldsc[ln].conn) { /* connected? */
753 if (com_ldsc[ln].xmte) { /* output enabled? */
754 c = com_queue_out (ln, &c1); /* get character, cvt */
755 if (c) /* printable? output */
756 tmxr_putc_ln (&com_ldsc[ln], c);
757 if (c1) /* print second */
758 tmxr_putc_ln (&com_ldsc[ln], c1);
759 } /* end if */
760 tmxr_poll_tx (&com_desc); /* poll xmt */
761 if (com_outq[ln].head == 0) /* line idle? */
762 ch9_set_atn (com_ch); /* set ATN1 */
763 else sim_activate (uptr, uptr->wait); /* next char */
764 } /* end if conn */
765 return SCPE_OK;
766 }
767
768 /* Send ID sequence on input */
769
com_send_id(uint32 ln)770 t_stat com_send_id (uint32 ln)
771 {
772 com_new_puttl (&com_inpq[ln], COMI_DIALUP); /* input message: */
773 if (coml_unit[ln].flags & UNIT_K35) /* dialup, ID, endID */
774 com_new_puttl (&com_inpq[ln], COMI_K35);
775 else com_new_puttl (&com_inpq[ln], COMI_K37);
776 com_new_puttl (&com_inpq[ln], 0);
777 com_new_puttl (&com_inpq[ln], 0);
778 com_new_puttl (&com_inpq[ln], 0);
779 com_new_puttl (&com_inpq[ln], 0);
780 com_new_puttl (&com_inpq[ln], (uint16) (ln + COM_LBASE));
781 if (!com_new_puttl (&com_inpq[ln], COMI_ENDID)) /* make sure there */
782 return STOP_NOIFREE; /* was room for msg */
783 coml_unit[ln].NEEDID = 0;
784 com_set_inpp (ln); /* input pending, ATN1 */
785 return SCPE_OK;
786 }
787
788 /* Translate and queue input character */
789
com_queue_in(uint32 ln,uint32 c)790 t_bool com_queue_in (uint32 ln, uint32 c)
791 {
792 uint16 out;
793
794 if (c == com_intr) {
795 out = COMI_INTR;
796 com_set_inpp (ln);
797 }
798 else if (c == com_quit) {
799 out = COMI_QUIT;
800 com_set_inpp (ln);
801 }
802 else {
803 if (c == '\r')
804 com_set_inpp (ln);
805 if (coml_unit[ln].flags & UNIT_K35) { /* KSR-35? */
806 if (islower (c)) /* convert LC to UC */
807 c = toupper (c);
808 }
809 else c |= (com_epar[c]? COMI_PARITY: 0); /* add even parity */
810 out = (~c) & 0377; /* 1's complement */
811 }
812 return com_new_puttl (&com_inpq[ln], out); /* input message */
813 }
814
815 /* Retrieve and translate output character */
816
com_queue_out(uint32 ln,uint32 * c1)817 uint32 com_queue_out (uint32 ln, uint32 *c1)
818 {
819 uint32 c, ent, raw;
820
821 *c1 = 0; /* assume non-printing */
822 if ((ent = com_gethd_free (&com_outq[ln])) == 0) /* get character */
823 return 0; /* nothing, exit */
824 raw = com_pkt[ent].data; /* get 12b character */
825 com_not_ret[ln]++;
826 if (raw == COMO_BITRPT) { /* insert delay? */
827 if (com_gethd_free (&com_outq[ln])) /* skip next char */
828 com_not_ret[ln]++; /* and count it */
829 return 0;
830 }
831 c = (~raw >> 1) & 0177; /* remove start, parity */
832 if ((c >= 040) && (c != 0177)) { /* printable? */
833 if ((coml_unit[ln].flags & UNIT_K35) && islower (c))/* KSR-35 LC? */
834 c = toupper (c); /* cvt to UC */
835 return c;
836 }
837 switch (c) {
838
839 case '\t': case '\f': case '\b': case '\a': /* valid ctrls */
840 return c;
841
842 case '\r': /* carriage return? */
843 *c1 = '\n'; /* lf after cr */
844 return c;
845
846 case '\n': /* line feed? */
847 *c1 = '\n'; /* lf after cr */
848 return '\r';
849
850 case 022: /* DC2 */
851 coml_unit[ln].NOECHO = 1;
852 return 0;
853
854 case 024: /* DC4 */
855 coml_unit[ln].NOECHO = 0;
856 return 0;
857 }
858
859 return 0; /* ignore others */
860 }
861
862 /* Generate completion message, if needed */
863
com_gen_ccmp(uint32 ln)864 uint32 com_gen_ccmp (uint32 ln)
865 {
866 uint32 t;
867
868 if ((t = com_not_ret[ln]) != 0) { /* chars not returned? */
869 if (t > COMI_CMAX) /* limit to max */
870 t = COMI_CMAX;
871 com_not_ret[ln] -= t; /* keep count */
872 return COMI_COMP (t); /* gen completion msg */
873 }
874 return 0;
875 }
876
877 /* Read and validate output buffer */
878
com_getob(uint32 ch)879 t_uint64 com_getob (uint32 ch)
880 {
881 if (com_chob_v) /* valid? clear */
882 com_chob_v = 0;
883 else if (!com_stop) { /* not stopped? */
884 ch9_set_ioc (com_ch); /* IO check */
885 com_set_sns (COMS_ITMO); /* set sense bit */
886 }
887 return com_chob;
888 }
889
890 /* Test whether input pending */
891
com_test_inp(void)892 t_bool com_test_inp (void)
893 {
894 uint32 i;
895
896 for (i = 0; i < COM_TLINES; i++) {
897 if ((com_not_ret[i] != 0) || coml_unit[i].INPP)
898 return TRUE;
899 }
900 return FALSE;
901 }
902
903 /* Set input pending and attention */
904
com_set_inpp(uint32 ln)905 void com_set_inpp (uint32 ln)
906 {
907 coml_unit[ln].INPP = 1;
908 ch9_set_atn (com_ch);
909 return;
910 }
911
912 /* Test for done */
913
com_qdone(uint32 ch)914 t_bool com_qdone (uint32 ch)
915 {
916 if (com_stop || !ch9_qconn (ch)) { /* stop or err disc? */
917 com_sta = 0; /* ctrl is idle */
918 return TRUE;
919 }
920 return FALSE;
921 }
922
923 /* Channel end */
924
com_end(uint32 ch,uint32 fl,uint32 st)925 void com_end (uint32 ch, uint32 fl, uint32 st)
926 {
927 ch9_set_end (ch, fl); /* set end */
928 ch_req |= REQ_CH (ch);
929 com_sta = st; /* next state */
930 return;
931 }
932
933 /* List routines - remove from head and free */
934
com_gethd_free(LISTHD * lh)935 uint16 com_gethd_free (LISTHD *lh)
936 {
937 uint16 ent;
938
939 if ((ent = com_gethd (lh)) != 0)
940 com_puttl (&com_free, ent);
941 return ent;
942 }
943
944 /* Remove from tail and free */
945
com_gettl_free(LISTHD * lh)946 uint16 com_gettl_free (LISTHD *lh)
947 {
948 uint16 ent;
949
950 if ((ent = com_gethd (lh)) != 0)
951 com_puttl (&com_free, ent);
952 return ent;
953 }
954
955 /* Get free entry and insert at tail */
956
com_new_puttl(LISTHD * lh,uint16 val)957 t_bool com_new_puttl (LISTHD *lh, uint16 val)
958 {
959 uint16 ent;
960
961 if ((ent = com_gethd (&com_free)) != 0) {
962 com_pkt[ent].data = val;
963 com_puttl (lh, ent);
964 return TRUE;
965 }
966 return FALSE;
967 }
968
969 /* Remove from head */
970
com_gethd(LISTHD * lh)971 uint16 com_gethd (LISTHD *lh)
972 {
973 uint16 ent;
974
975 if ((ent = lh->head) != 0) {
976 lh->head = com_pkt[ent].next;
977 if (lh->head == 0)
978 lh->tail = 0;
979 }
980 else lh->tail = 0;
981 return ent;
982 }
983
984 /* Remove from tail */
985
com_gettl(LISTHD * lh)986 uint16 com_gettl (LISTHD *lh)
987 {
988 uint16 ent, next;
989 uint32 i;
990
991 ent = lh->tail;
992 if (lh->head == lh->tail) {
993 lh->head = lh->tail = 0;
994 return ent;
995 }
996 next = lh->head;
997 for (i = 0; i < COM_PKTSIZ; i++) {
998 if (com_pkt[next].next == ent) {
999 com_pkt[next].next = 0;
1000 lh->tail = next;
1001 return ent;
1002 }
1003 }
1004 return 0;
1005 }
1006
1007 /* Insert at tail */
1008
com_puttl(LISTHD * lh,uint16 ent)1009 void com_puttl (LISTHD *lh, uint16 ent)
1010 {
1011 if (lh->tail == 0)
1012 lh->head = ent;
1013 else com_pkt[lh->tail].next = ent;
1014 com_pkt[ent].next = 0;
1015 lh->tail = ent;
1016 return;
1017 }
1018
1019 /* Set flag in sense */
1020
com_set_sns(t_uint64 stat)1021 void com_set_sns (t_uint64 stat)
1022 {
1023 com_sns |= stat;
1024 com_sns &= ~(COMS_PCHK|COMS_DCHK|COMS_EXCC);
1025 if (com_sns & COMS_PALL)
1026 com_sns |= COMS_PCHK;
1027 if (com_sns & COMS_DALL)
1028 com_sns |= COMS_DCHK;
1029 if (com_sns & COMS_EALL)
1030 com_sns |= COMS_EXCC;
1031 return;
1032 }
1033
1034 /* Reset routine */
1035
com_reset(DEVICE * dptr)1036 t_stat com_reset (DEVICE *dptr)
1037 {
1038 uint32 i;
1039
1040 if (dptr->flags & DEV_DIS) { /* disabled? */
1041 com_dev.flags = com_dev.flags | DEV_DIS; /* disable lines */
1042 coml_dev.flags = coml_dev.flags | DEV_DIS;
1043 }
1044 else {
1045 com_dev.flags = com_dev.flags & ~DEV_DIS; /* enable lines */
1046 coml_dev.flags = coml_dev.flags & ~DEV_DIS;
1047 }
1048 sim_activate (&com_unit[COM_CIU], com_unit[COM_CIU].wait); /* console */
1049 sim_cancel (&com_unit[COM_PLU]);
1050 sim_cancel (&com_unit[COM_CHU]);
1051 if (com_unit[COM_PLU].flags & UNIT_ATT) { /* master att? */
1052 int32 t = sim_rtcn_init (com_unit[COM_PLU].wait, TMR_COM);
1053 sim_activate (&com_unit[COM_PLU], t);
1054 }
1055 com_enab = 0;
1056 com_sns = 0;
1057 com_msgn = 0;
1058 com_sta = 0;
1059 com_chob = 0;
1060 com_chob_v = 0;
1061 com_stop = 0;
1062 com_bptr = 0;
1063 com_blim = 0;
1064 for (i = 0; i < COM_BUFSIZ; i++)
1065 com_buf[i] = 0;
1066 for (i = 0; i < COM_TLINES; i++) { /* init lines */
1067 com_inpq[i].head = 0;
1068 com_inpq[i].tail = 0;
1069 com_outq[i].head = 0;
1070 com_outq[i].tail = 0;
1071 com_reset_ln (i);
1072 }
1073 com_pkt[0].next = 0; /* init free list */
1074 for (i = 1; i < COM_PKTSIZ; i++) {
1075 com_pkt[i].next = i + 1;
1076 com_pkt[i].data = 0;
1077 }
1078 com_pkt[COM_PKTSIZ - 1].next = 0; /* end of free list */
1079 com_free.head = 1;
1080 com_free.tail = COM_PKTSIZ - 1;
1081 coml_unit[COM_MLINES].CONN = 1; /* console always conn */
1082 coml_unit[COM_MLINES].NEEDID = 1;
1083 return SCPE_OK;
1084 }
1085
1086 /* Attach master unit */
1087
com_attach(UNIT * uptr,char * cptr)1088 t_stat com_attach (UNIT *uptr, char *cptr)
1089 {
1090 t_stat r;
1091
1092 r = tmxr_attach (&com_desc, uptr, cptr); /* attach */
1093 if (r != SCPE_OK) /* error */
1094 return r;
1095 sim_rtcn_init (uptr->wait, TMR_COM);
1096 sim_activate (uptr, 100); /* quick poll */
1097 return SCPE_OK;
1098 }
1099
1100 /* Detach master unit */
1101
com_detach(UNIT * uptr)1102 t_stat com_detach (UNIT *uptr)
1103 {
1104 uint32 i;
1105 t_stat r;
1106
1107 r = tmxr_detach (&com_desc, uptr); /* detach */
1108 for (i = 0; i < COM_MLINES; i++) /* disable rcv */
1109 com_ldsc[i].rcve = 0;
1110 sim_cancel (uptr); /* stop poll */
1111 return r;
1112 }
1113
1114 /* Reset an individual line */
1115
com_reset_ln(uint32 ln)1116 void com_reset_ln (uint32 ln)
1117 {
1118 while (com_gethd_free (&com_inpq[ln])) ;
1119 while (com_gethd_free (&com_outq[ln])) ;
1120 com_not_ret[ln] = 0;
1121 coml_unit[ln].NEEDID = 0;
1122 coml_unit[ln].NOECHO = 0;
1123 coml_unit[ln].INPP = 0;
1124 sim_cancel (&coml_unit[ln]);
1125 if ((ln < COM_MLINES) && (com_ldsc[ln].conn == 0))
1126 coml_unit[ln].CONN = 0;
1127 return;
1128 }
1129
1130 /* Special show commands */
1131
com_show_qsumm(FILE * st,LISTHD * lh,char * name)1132 uint32 com_show_qsumm (FILE *st, LISTHD *lh, char *name)
1133 {
1134 uint32 i, next;
1135
1136 next = lh->head;
1137 for (i = 0; i < COM_PKTSIZ; i++) {
1138 if (next == 0) {
1139 if (i == 0)
1140 fprintf (st, "%s is empty\n", name);
1141 else if (i == 1)
1142 fprintf (st, "%s has 1 entry\n", name);
1143 else fprintf (st, "%s has %d entries\n", name, i);
1144 return i;
1145 }
1146 next = com_pkt[next].next;
1147 }
1148 fprintf (st, "%s is corrupt\n", name);
1149 return 0;
1150 }
1151
com_show_char(FILE * st,uint32 ch)1152 void com_show_char (FILE *st, uint32 ch)
1153 {
1154 uint32 c;
1155
1156 fprintf (st, "%03o", ch);
1157 c = (~ch) & 0177;
1158 if (((ch & 07400) == 0) && (c >= 040) && (c != 0177))
1159 fprintf (st, "[%c]", c);
1160 return;
1161 }
1162
com_show_freeq(FILE * st,UNIT * uptr,int32 val,void * desc)1163 t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc)
1164 {
1165 com_show_qsumm (st, &com_free, "Free queue");
1166 return SCPE_OK;
1167 }
1168
com_show_oneq(FILE * st,UNIT * uptr,int32 val,void * desc)1169 t_stat com_show_oneq (FILE *st, UNIT *uptr, int32 val, void *desc)
1170 {
1171 uint32 entc, ln, i, next;
1172 LISTHD *lh;
1173 char name[20];
1174
1175 ln = uptr - coml_dev.units;
1176 sprintf (name, val? "Output queue %d": "Input queue %d", ln);
1177 lh = val? &com_outq[ln]: &com_inpq[ln];
1178 if ((entc = com_show_qsumm (st, lh, name))) {
1179 for (i = 0, next = lh->head; next != 0;
1180 i++, next = com_pkt[next].next) {
1181 if ((i % 8) == 0)
1182 fprintf (st, "%d:\t", i);
1183 com_show_char (st, com_pkt[next].data >> (val? 1: 0));
1184 fputc ((((i % 8) == 7)? '\n': '\t'), st);
1185 }
1186 if (i % 8)
1187 fputc ('\n', st);
1188 }
1189 return SCPE_OK;
1190 }
1191
com_show_allq(FILE * st,UNIT * uptr,int32 val,void * desc)1192 t_stat com_show_allq (FILE *st, UNIT *uptr, int32 val, void *desc)
1193 {
1194 uint32 i;
1195
1196 for (i = 0; i < COM_TLINES; i++)
1197 com_show_oneq (st, coml_dev.units + i, val, desc);
1198 return SCPE_OK;
1199 }
1200
com_show_ctrl(FILE * st,UNIT * uptr,int32 val,void * desc)1201 t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc)
1202 {
1203 if (!com_enab)
1204 fprintf (st, "Controller is not initialized\n");
1205 if (val & COMR_FQ)
1206 com_show_freeq (st, uptr, 0, desc);
1207 if (val & COMR_IQ)
1208 com_show_allq (st, uptr, 0, desc);
1209 if (val & COMR_OQ)
1210 com_show_allq (st, uptr, 1, desc);
1211 return SCPE_OK;
1212 }
1213