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