First Commit of my working state
[simh.git] / HP2100 / hp2100_mux.c
CommitLineData
196ba1fc
PH
1/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator\r
2\r
3 Copyright (c) 2002-2008, 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 mux,muxl,muxc 12920A terminal multiplexor\r
27\r
28 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility\r
29 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements\r
30 Fixed "muxc_reset" to clear lines 16-20\r
31 26-Feb-07 JDB Added debug printouts\r
32 Fixed control card OTx to set current channel number\r
33 Fixed to set "muxl_ibuf" in response to a transmit interrupt\r
34 Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits\r
35 Fixed to set "mux_rchp" when a line break is received\r
36 Fixed incorrect "odd_par" table values\r
37 Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity\r
38 Fixed mux reset (ioCRS) to clear port parameters\r
39 Fixed to use PUT_DCH instead of PUT_CCH for data channel status\r
40 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode\r
41 28-Dec-06 JDB Added ioCRS state to I/O decoders\r
42 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init\r
43 22-Nov-05 RMS Revised for new terminal processing routines\r
44 29-Jun-05 RMS Added SET MUXLn DISCONNECT\r
45 07-Oct-04 JDB Allow enable/disable from any device\r
46 26-Apr-04 RMS Fixed SFS x,C and SFC x,C\r
47 Implemented DMA SRQ (follows FLG)\r
48 05-Jan-04 RMS Revised for tmxr library changes\r
49 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny)\r
50 09-May-03 RMS Added network device flag\r
51 01-Nov-02 RMS Added 7B/8B support\r
52 22-Aug-02 RMS Updated for changes to sim_tmxr\r
53\r
54 The 12920A consists of three separate devices\r
55\r
56 mux scanner (upper data card)\r
57 muxl lines (lower data card)\r
58 muxm modem control (control card)\r
59\r
60 The lower data card has no CMD flop; the control card has no CMD flop.\r
61 The upper data card has none of the usual flops.\r
62\r
63 Reference:\r
64 - 12920A Asynchronous Multiplexer Interface Kits Operating and Service\r
65 Manual (12920-90001, Oct-1972)\r
66*/\r
67\r
68#include "hp2100_defs.h"\r
69#include "sim_sock.h"\r
70#include "sim_tmxr.h"\r
71#include <ctype.h>\r
72\r
73#define MUX_LINES 16 /* user lines */\r
74#define MUX_ILINES 5 /* diag rcv only */\r
75#define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */\r
76#define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */\r
77#define UNIT_MDM (1 << UNIT_V_MDM)\r
78#define UNIT_DIAG (1 << UNIT_V_DIAG)\r
79#define MUXL_WAIT 500\r
80\r
81/* Channel number (OTA upper, LIA lower or upper) */\r
82\r
83#define MUX_V_CHAN 10 /* channel num */\r
84#define MUX_M_CHAN 037\r
85#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN)\r
86\r
87/* OTA, lower = parameters or data */\r
88\r
89#define OTL_P 0100000 /* parameter */\r
90#define OTL_TX 0040000 /* transmit */\r
91#define OTL_ENB 0020000 /* enable */\r
92#define OTL_TPAR 0010000 /* xmt parity */\r
93#define OTL_ECHO 0010000 /* rcv echo */\r
94#define OTL_DIAG 0004000 /* diagnose */\r
95#define OTL_SYNC 0004000 /* sync */\r
96#define OTL_V_LNT 8 /* char length */\r
97#define OTL_M_LNT 07\r
98#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT)\r
99#define OTL_V_BAUD 0 /* baud rate */\r
100#define OTL_M_BAUD 0377\r
101#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD)\r
102#define OTL_CHAR 03777 /* char mask */\r
103#define OTL_PAR 0200 /* char parity */\r
104\r
105/* LIA, lower = received data */\r
106\r
107#define LIL_PAR 0100000 /* parity */\r
108#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)\r
109#define LIL_CHAR 01777 /* character */\r
110\r
111/* LIA, upper = status */\r
112\r
113#define LIU_SEEK 0100000 /* seeking NI */\r
114#define LIU_DG 0000010 /* diagnose */\r
115#define LIU_BRK 0000004 /* break */\r
116#define LIU_LOST 0000002 /* char lost */\r
117#define LIU_TR 0000001 /* trans/rcv */\r
118\r
119/* OTA, control */\r
120\r
121#define OTC_SCAN 0100000 /* scan */\r
122#define OTC_UPD 0040000 /* update */\r
123#define OTC_V_CHAN 10 /* channel */\r
124#define OTC_M_CHAN 017\r
125#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN)\r
126#define OTC_EC2 0000200 /* enable Cn upd */\r
127#define OTC_EC1 0000100\r
128#define OTC_C2 0000040 /* Cn flops */\r
129#define OTC_C1 0000020\r
130#define OTC_V_C 4 /* S1 to C1 */\r
131#define OTC_ES2 0000010 /* enb comparison */\r
132#define OTC_ES1 0000004\r
133#define OTC_V_ES 2\r
134#define OTC_SS2 0000002 /* SSn flops */\r
135#define OTC_SS1 0000001\r
136#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)\r
137#define RTS OCT_C2 /* C2 = rts */\r
138#define DTR OTC_C1 /* C1 = dtr */\r
139\r
140/* LIA, control */\r
141\r
142#define LIC_MBO 0140000 /* always set */\r
143#define LIC_V_CHAN 10 /* channel */\r
144#define LIC_M_CHAN 017\r
145#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN)\r
146#define LIC_I2 0001000 /* change flags */\r
147#define LIC_I1 0000400\r
148#define LIC_S2 0000002 /* Sn flops */\r
149#define LIC_S1 0000001\r
150#define LIC_V_I 8 /* S1 to I1 */\r
151#define CDET LIC_S2 /* S2 = cdet */\r
152#define DSR LIC_S1 /* S1 = dsr */\r
153\r
154#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \\r
155 ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \\r
156 << LIC_V_I)\r
157\r
158/* Debug flags */\r
159\r
160#define DEB_CMDS (1 << 0) /* Command initiation and completion */\r
161#define DEB_CPU (1 << 1) /* CPU I/O */\r
162#define DEB_XFER (1 << 2) /* Socket receive and transmit */\r
163\r
164extern uint32 PC;\r
165extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];\r
166extern FILE *sim_deb;\r
167\r
168uint16 mux_sta[MUX_LINES + MUX_ILINES]; /* line status */\r
169uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */\r
170uint16 mux_xpar[MUX_LINES]; /* xmt param */\r
171uint16 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */\r
172uint16 mux_xbuf[MUX_LINES]; /* xmt buf */\r
173uint8 mux_rchp[MUX_LINES + MUX_ILINES]; /* rcv chr pend */\r
174uint8 mux_xdon[MUX_LINES]; /* xmt done */\r
175uint8 muxc_ota[MUX_LINES]; /* ctrl: Cn,ESn,SSn */\r
176uint8 muxc_lia[MUX_LINES]; /* ctrl: Sn */\r
177uint32 muxl_ibuf = 0; /* low in: rcv data */\r
178uint32 muxl_obuf = 0; /* low out: param */\r
179uint32 muxu_ibuf = 0; /* upr in: status */\r
180uint32 muxu_obuf = 0; /* upr out: chan */\r
181uint32 muxc_chan = 0; /* ctrl chan */\r
182uint32 muxc_scan = 0; /* ctrl scan */\r
183\r
184TMLN mux_ldsc[MUX_LINES] = { { 0 } }; /* line descriptors */\r
185TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */\r
186\r
187DEVICE muxl_dev, muxu_dev, muxc_dev;\r
188int32 muxlio (int32 inst, int32 IR, int32 dat);\r
189int32 muxuio (int32 inst, int32 IR, int32 dat);\r
190int32 muxcio (int32 inst, int32 IR, int32 dat);\r
191t_stat muxi_svc (UNIT *uptr);\r
192t_stat muxo_svc (UNIT *uptr);\r
193t_stat muxc_reset (DEVICE *dptr);\r
194t_stat mux_attach (UNIT *uptr, char *cptr);\r
195t_stat mux_detach (UNIT *uptr);\r
196t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);\r
197t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc);\r
198t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r
199void mux_data_int (void);\r
200void mux_ctrl_int (void);\r
201void mux_diag (int32 c);\r
202\r
203static uint8 odd_par[256] = {\r
204 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */\r
205 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */\r
206 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */\r
207 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */\r
208 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */\r
209 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */\r
210 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */\r
211 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */\r
212 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */\r
213 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */\r
214 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */\r
215 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */\r
216 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */\r
217 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */\r
218 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */\r
219 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */\r
220 };\r
221\r
222#define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR)\r
223#define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR)\r
224\r
225/* Debug flags table */\r
226\r
227DEBTAB mux_deb[] = {\r
228 { "CMDS", DEB_CMDS },\r
229 { "CPU", DEB_CPU },\r
230 { "XFER", DEB_XFER },\r
231 { NULL, 0 } };\r
232\r
233DIB mux_dib[] = {\r
234 { MUXL, 0, 0, 0, 0, 0, &muxlio },\r
235 { MUXU, 0, 0, 0, 0, 0, &muxuio }\r
236 };\r
237\r
238#define muxl_dib mux_dib[0]\r
239#define muxu_dib mux_dib[1]\r
240\r
241/* MUX data structures\r
242\r
243 muxu_dev MUX device descriptor\r
244 muxu_unit MUX unit descriptor\r
245 muxu_reg MUX register list\r
246 muxu_mod MUX modifiers list\r
247*/\r
248\r
249UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_WAIT };\r
250\r
251REG muxu_reg[] = {\r
252 { ORDATA (IBUF, muxu_ibuf, 16) },\r
253 { ORDATA (OBUF, muxu_obuf, 16) },\r
254 { FLDATA (CMD, muxu_dib.cmd, 0), REG_HRO },\r
255 { FLDATA (CTL, muxu_dib.ctl, 0), REG_HRO },\r
256 { FLDATA (FLG, muxu_dib.flg, 0), REG_HRO },\r
257 { FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO },\r
258 { FLDATA (SRQ, muxu_dib.srq, 0), REG_HRO },\r
259 { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO },\r
260 { NULL }\r
261 };\r
262\r
263MTAB muxu_mod[] = {\r
264 { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &mux_setdiag },\r
265 { UNIT_DIAG, 0, "terminal mode", "TERM", &mux_setdiag },\r
266 { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &mux_summ },\r
267 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,\r
268 NULL, &mux_show, NULL },\r
269 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,\r
270 NULL, &mux_show, NULL },\r
271 { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",\r
272 &hp_setdev, &hp_showdev, &muxl_dev },\r
273 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",\r
274 &tmxr_dscln, NULL, &mux_desc },\r
275 { 0 }\r
276 };\r
277\r
278DEVICE muxu_dev = {\r
279 "MUX", &muxu_unit, muxu_reg, muxu_mod,\r
280 1, 10, 31, 1, 8, 8,\r
281 &tmxr_ex, &tmxr_dep, &muxc_reset,\r
282 NULL, &mux_attach, &mux_detach,\r
283 &muxu_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG,\r
284 0, mux_deb, NULL, NULL\r
285 };\r
286\r
287/* MUXL data structures\r
288\r
289 muxl_dev MUXL device descriptor\r
290 muxl_unit MUXL unit descriptor\r
291 muxl_reg MUXL register list\r
292 muxl_mod MUXL modifiers list\r
293*/\r
294\r
295UNIT muxl_unit[] = {\r
296 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
297 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
298 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
299 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
300 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
301 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
302 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
303 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
304 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
305 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
306 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
307 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
308 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
309 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
310 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
311 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },\r
312 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }\r
313 };\r
314\r
315MTAB muxl_mod[] = {\r
316 { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },\r
317 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },\r
318 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },\r
319 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },\r
320 { UNIT_MDM, 0, "no dataset", "NODATASET", NULL },\r
321 { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL },\r
322 { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",\r
323 &tmxr_dscln, NULL, &mux_desc },\r
324 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",\r
325 &tmxr_set_log, &tmxr_show_log, &mux_desc },\r
326 { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",\r
327 &tmxr_set_nolog, NULL, &mux_desc },\r
328 { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",\r
329 &hp_setdev, &hp_showdev, &muxl_dev },\r
330 { 0 }\r
331 };\r
332\r
333REG muxl_reg[] = {\r
334 { FLDATA (CMD, muxl_dib.cmd, 0), REG_HRO },\r
335 { FLDATA (CTL, muxl_dib.ctl, 0) },\r
336 { FLDATA (FLG, muxl_dib.flg, 0) },\r
337 { FLDATA (FBF, muxl_dib.fbf, 0) },\r
338 { FLDATA (SRQ, muxl_dib.srq, 0) },\r
339 { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) },\r
340 { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) },\r
341 { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) },\r
342 { BRDATA (RBUF, mux_rbuf, 8, 16, MUX_LINES + MUX_ILINES) },\r
343 { BRDATA (XBUF, mux_xbuf, 8, 16, MUX_LINES) },\r
344 { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) },\r
345 { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) },\r
346 { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,\r
347 MUX_LINES, REG_NZ + PV_LEFT) },\r
348 { ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO },\r
349 { NULL }\r
350 };\r
351\r
352DEVICE muxl_dev = {\r
353 "MUXL", muxl_unit, muxl_reg, muxl_mod,\r
354 MUX_LINES, 10, 31, 1, 8, 8,\r
355 NULL, NULL, &muxc_reset,\r
356 NULL, NULL, NULL,\r
357 &muxl_dib, DEV_DISABLE\r
358 };\r
359\r
360/* MUXM data structures\r
361\r
362 muxc_dev MUXM device descriptor\r
363 muxc_unit MUXM unit descriptor\r
364 muxc_reg MUXM register list\r
365 muxc_mod MUXM modifiers list\r
366*/\r
367\r
368DIB muxc_dib = { MUXC, 0, 0, 0, 0, 0, &muxcio };\r
369\r
370UNIT muxc_unit = { UDATA (NULL, 0, 0) };\r
371\r
372REG muxc_reg[] = {\r
373 { FLDATA (CMD, muxc_dib.cmd, 0), REG_HRO },\r
374 { FLDATA (CTL, muxc_dib.ctl, 0) },\r
375 { FLDATA (FLG, muxc_dib.flg, 0) },\r
376 { FLDATA (FBF, muxc_dib.fbf, 0) },\r
377 { FLDATA (SRQ, muxc_dib.srq, 0) },\r
378 { FLDATA (SCAN, muxc_scan, 0) },\r
379 { ORDATA (CHAN, muxc_chan, 4) },\r
380 { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },\r
381 { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },\r
382 { ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO },\r
383 { NULL }\r
384 };\r
385\r
386MTAB muxc_mod[] = {\r
387 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
388 &hp_setdev, &hp_showdev, &muxc_dev },\r
389 { 0 }\r
390 };\r
391\r
392DEVICE muxc_dev = {\r
393 "MUXM", &muxc_unit, muxc_reg, muxc_mod,\r
394 1, 10, 31, 1, 8, 8,\r
395 NULL, NULL, &muxc_reset,\r
396 NULL, NULL, NULL,\r
397 &muxc_dib, DEV_DISABLE\r
398 };\r
399\r
400/* I/O instructions: data cards\r
401\r
402 Implementation note: the operating manual says that "at least 100\r
403 milliseconds of CLC 0s must be programmed" by systems employing the\r
404 multiplexer to ensure that the multiplexer resets. In practice, such systems\r
405 issue 128K CLC 0 instructions. As we provide debug logging of multiplexer\r
406 resets, a CRS counter is used to ensure that only one debug line is printed\r
407 in response to these 128K CRS invocations.\r
408*/\r
409\r
410int32 muxlio (int32 inst, int32 IR, int32 dat)\r
411{\r
412int32 dev, ln;\r
413t_bool is_crs;\r
414static uint32 crs_count = 0; /* cntr for crs repeat */\r
415\r
416dev = IR & I_DEVMASK; /* get device no */\r
417is_crs = FALSE;\r
418\r
419switch (inst) { /* case on opcode */\r
420\r
421 case ioFLG: /* flag clear/set */\r
422 if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */\r
423 break;\r
424\r
425 case ioSFC: /* skip flag clear */\r
426 if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;\r
427 break;\r
428\r
429 case ioSFS: /* skip flag set */\r
430 if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;\r
431 break;\r
432\r
433 case ioOTX: /* output */\r
434 muxl_obuf = dat; /* store data */\r
435\r
436 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
437 if (dat & OTL_P)\r
438 fprintf (sim_deb, ">>MUXl OTx: Parameter = %06o\n", dat);\r
439 else\r
440 fprintf (sim_deb, ">>MUXl OTx: Data = %06o\n", dat);\r
441 break;\r
442\r
443 case ioLIX: /* load */\r
444 dat = 0;\r
445\r
446 case ioMIX: /* merge */\r
447 dat = dat | muxl_ibuf;\r
448\r
449 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
450 fprintf (sim_deb, ">>MUXl LIx: Data = %06o\n", dat);\r
451 break;\r
452\r
453 case ioCRS: /* control reset */\r
454 is_crs = TRUE;\r
455\r
456 if (crs_count) /* already reset? */\r
457 break; /* skip redundant clear */\r
458\r
459 for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */\r
460 mux_xbuf[ln] = mux_xpar[ln] = 0;\r
461 muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0;\r
462 }\r
463\r
464 for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) {\r
465 mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */\r
466 mux_sta[ln] = mux_rchp[ln] = 0;\r
467 } /* fall into CLC SC */\r
468\r
469 case ioCTL: /* control clear/set */\r
470 if (IR & I_CTL) { /* CLC */\r
471 clrCTL (dev);\r
472\r
473 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
474 fprintf (sim_deb, ">>MUXl CLC: Data interrupt inhibited\n");\r
475 }\r
476 else { /* STC */\r
477 setCTL (dev); /* set ctl */\r
478 ln = MUX_CHAN (muxu_obuf); /* get chan # */\r
479\r
480 if (muxl_obuf & OTL_TX) { /* transmit? */\r
481 if (ln < MUX_LINES) { /* line valid? */\r
482 if (muxl_obuf & OTL_P) { /* parameter? */\r
483 mux_xpar[ln] = muxl_obuf; /* store param value */\r
484 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
485 fprintf (sim_deb,\r
486 ">>MUXl STC: Transmit channel %d parameter %06o stored\n",\r
487 ln, muxl_obuf);\r
488 }\r
489\r
490 else { /* data */\r
491 if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */\r
492 muxl_obuf = /* add parity bit */\r
493 muxl_obuf & ~OTL_PAR |\r
494 XMT_PAR(muxl_obuf);\r
495 mux_xbuf[ln] = muxl_obuf; /* load buffer */\r
496\r
497 if (sim_is_active (&muxl_unit[ln])) { /* still working? */\r
498 mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */\r
499 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
500 fprintf (sim_deb,\r
501 ">>MUXl STC: Transmit channel %d data overrun\n", ln);\r
502 }\r
503 else {\r
504 if (muxu_unit.flags & UNIT_DIAG) /* loopback? */\r
505 mux_ldsc[ln].conn = 1; /* connect this line */\r
506 sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);\r
507 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
508 fprintf (sim_deb,\r
509 ">>MUXl STC: Transmit channel %d data %06o scheduled\n",\r
510 ln, muxl_obuf);\r
511 }\r
512 }\r
513 }\r
514 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */\r
515 fprintf (sim_deb, ">>MUXl STC: Transmit channel %d invalid\n", ln);\r
516 }\r
517\r
518 else /* receive */\r
519 if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */\r
520 if (muxl_obuf & OTL_P) { /* parameter? */\r
521 mux_rpar[ln] = muxl_obuf; /* store param value */\r
522 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
523 fprintf (sim_deb,\r
524 ">>MUXl STC: Receive channel %d parameter %06o stored\n",\r
525 ln, muxl_obuf);\r
526 }\r
527\r
528 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */\r
529 fprintf (sim_deb,\r
530 ">>MUXl STC: Receive channel %d parameter %06o invalid action\n",\r
531 ln, muxl_obuf);\r
532 }\r
533\r
534 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */\r
535 fprintf (sim_deb, ">>MUXl STC: Receive channel %d invalid\n", ln);\r
536 } /* end STC */\r
537 break;\r
538\r
539 default:\r
540 break;\r
541 }\r
542\r
543if (is_crs) /* control reset? */\r
544 crs_count = crs_count + 1; /* increment count */\r
545\r
546else if (crs_count) { /* something else */\r
547 if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */\r
548 fprintf (sim_deb,\r
549 ">>MUXl CRS: Multiplexer reset %d times\n", crs_count);\r
550 crs_count = 0; /* clear counter */\r
551 }\r
552\r
553if (IR & I_HC) { /* H/C option */\r
554 clrFSR (dev); /* clear flag */\r
555 mux_data_int (); /* look for new int */\r
556 }\r
557return dat;\r
558}\r
559\r
560int32 muxuio (int32 inst, int32 IR, int32 dat)\r
561{\r
562switch (inst) { /* case on opcode */\r
563\r
564 case ioOTX: /* output */\r
565 muxu_obuf = dat; /* store data */\r
566\r
567 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
568 fprintf (sim_deb, ">>MUXu OTx: Data channel = %d\n", MUX_CHAN(dat));\r
569 break;\r
570\r
571 case ioLIX: /* load */\r
572 dat = 0;\r
573\r
574 case ioMIX: /* merge */\r
575 dat = dat | muxu_ibuf;\r
576\r
577 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
578 fprintf (sim_deb, ">>MUXu LIx: Status = %06o, channel = %d\n", dat, MUX_CHAN(dat));\r
579 break;\r
580\r
581 default:\r
582 break;\r
583 }\r
584\r
585return dat;\r
586}\r
587\r
588/* I/O instructions: control card\r
589\r
590 In diagnostic mode, the control signals C1 and C2 are looped back to status\r
591 signals S1 and S2. Changing the control signals may cause an interrupt, so a\r
592 test is performed after OTx processing.\r
593*/\r
594\r
595int32 muxcio (int32 inst, int32 IR, int32 dat)\r
596{\r
597int32 dev, ln, t, old;\r
598\r
599dev = IR & I_DEVMASK; /* get device no */\r
600switch (inst) { /* case on opcode */\r
601\r
602 case ioFLG: /* flag clear/set */\r
603 if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */\r
604 break;\r
605\r
606 case ioSFC: /* skip flag clear */\r
607 if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;\r
608 break;\r
609\r
610 case ioSFS: /* skip flag set */\r
611 if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;\r
612 break;\r
613\r
614 case ioOTX: /* output */\r
615 ln = muxc_chan = OTC_CHAN (dat); /* set channel */\r
616\r
617 if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */\r
618 else muxc_scan = 0;\r
619\r
620 if (dat & OTC_UPD) { /* update? */\r
621 old = muxc_ota[ln]; /* save prior val */\r
622 muxc_ota[ln] = /* save ESn,SSn */\r
623 (muxc_ota[ln] & ~OTC_RW) | (dat & OTC_RW);\r
624\r
625 if (dat & OTC_EC2) /* if EC2, upd C2 */\r
626 muxc_ota[ln] =\r
627 (muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2);\r
628\r
629 if (dat & OTC_EC1) /* if EC1, upd C1 */\r
630 muxc_ota[ln] =\r
631 (muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1);\r
632\r
633 if (muxu_unit.flags & UNIT_DIAG) /* loopback? */\r
634 muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */\r
635 (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) |\r
636 (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C;\r
637\r
638 else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */\r
639 (old & DTR) && /* DTR drop? */\r
640 !(muxc_ota[ln] & DTR)) {\r
641 tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");\r
642 tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */\r
643 muxc_lia[ln] = 0; /* dataset off */\r
644 }\r
645 } /* end update */\r
646\r
647 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
648 fprintf (sim_deb, ">>MUXc OTx: Parameter = %06o, channel = %d\n",\r
649 dat, ln);\r
650\r
651 if ((muxu_unit.flags & UNIT_DIAG) && /* loopback? */\r
652 (!FLG(muxc_dib.devno))) /* flag clear? */\r
653 mux_ctrl_int (); /* status chg may interrupt */\r
654 break;\r
655\r
656 case ioLIX: /* load */\r
657 dat = 0;\r
658\r
659 case ioMIX: /* merge */\r
660 t = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */\r
661 LIC_TSTI (muxc_chan) | /* I2, I1 */\r
662 (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */\r
663 (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */\r
664 dat = dat | t; /* return status */\r
665\r
666 if (DEBUG_PRI (muxu_dev, DEB_CPU))\r
667 fprintf (sim_deb, ">>MUXc LIx: Status = %06o, channel = %d\n",\r
668 dat, muxc_chan);\r
669\r
670 muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */\r
671 break;\r
672\r
673 case ioCRS: /* control reset */\r
674 case ioCTL: /* ctrl clear/set */\r
675 if (IR & I_CTL) { clrCTL (dev); } /* CLC */\r
676 else { setCTL (dev); } /* STC */\r
677 break;\r
678\r
679 default:\r
680 break;\r
681 }\r
682\r
683if (IR & I_HC) { /* H/C option */\r
684 clrFSR (dev); /* clear flag */\r
685 mux_ctrl_int (); /* look for new int */\r
686 }\r
687return dat;\r
688}\r
689\r
690/* Unit service - receive side\r
691\r
692 Poll for new connections\r
693 Poll all active lines for input\r
694*/\r
695\r
696t_stat muxi_svc (UNIT *uptr)\r
697{\r
698int32 ln, c;\r
699t_bool loopback;\r
700\r
701loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */\r
702\r
703if (!loopback) { /* terminal mode? */\r
704 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */\r
705 muxu_unit.wait = sync_poll (SERVICE); /* synchronize poll */\r
706 sim_activate (uptr, muxu_unit.wait); /* continue poll */\r
707 ln = tmxr_poll_conn (&mux_desc); /* look for connect */\r
708 if (ln >= 0) { /* got one? */\r
709 if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */\r
710 (muxc_ota[ln] & DTR)) /* DTR? */\r
711 muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */\r
712 muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */\r
713 mux_ldsc[ln].rcve = 1; /* rcv enabled */\r
714 }\r
715 tmxr_poll_rx (&mux_desc); /* poll for input */\r
716}\r
717\r
718for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */\r
719 if (mux_ldsc[ln].conn) { /* connected? */\r
720 if (loopback) { /* diagnostic mode? */\r
721 c = mux_xbuf[ln ^ 1] & OTL_CHAR; /* get char from xmit line */\r
722 if (c == 0) /* all char bits = 0? */\r
723 c = c | SCPE_BREAK; /* set break flag */\r
724 mux_ldsc[ln].conn = 0; /* clear connection */\r
725 }\r
726\r
727 else\r
728 c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */\r
729\r
730 if (c) { /* valid char? */\r
731 if (c & SCPE_BREAK) { /* break? */\r
732 mux_sta[ln] = mux_sta[ln] | LIU_BRK;\r
733 mux_rbuf[ln] = 0; /* no char */\r
734 }\r
735 else { /* normal */\r
736 if (mux_rchp[ln]) /* char already pending? */\r
737 mux_sta[ln] = mux_sta[ln] | LIU_LOST;\r
738\r
739 if (!loopback) { /* terminal mode? */\r
740 c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags));\r
741 if (mux_rpar[ln] & OTL_ECHO) { /* echo? */\r
742 TMLN *lp = &mux_ldsc[ln]; /* get line */\r
743 tmxr_putc_ln (lp, c); /* output char */\r
744 tmxr_poll_tx (&mux_desc); /* poll xmt */\r
745 }\r
746 }\r
747 mux_rbuf[ln] = c; /* save char */\r
748 }\r
749\r
750 mux_rchp[ln] = 1; /* char pending */\r
751\r
752 if (DEBUG_PRI (muxu_dev, DEB_XFER))\r
753 fprintf (sim_deb, ">>MUXi svc: Line %d character %06o received\n",\r
754 ln, c);\r
755\r
756 if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */\r
757 } /* end if char */\r
758 } /* end if connected */\r
759\r
760 else /* not connected */\r
761 if (!loopback) /* terminal mode? */\r
762 muxc_lia[ln] = 0; /* line disconnected */\r
763 } /* end for */\r
764if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */\r
765if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */\r
766return SCPE_OK;\r
767}\r
768\r
769/* Unit service - transmit side */\r
770\r
771t_stat muxo_svc (UNIT *uptr)\r
772{\r
773int32 c, fc, ln, altln;\r
774t_bool loopback;\r
775\r
776ln = uptr - muxl_unit; /* line # */\r
777altln = ln ^ 1; /* alt. line for diag mode */\r
778\r
779fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */\r
780c = fc & 0377; /* Telnet character data */\r
781\r
782loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */\r
783\r
784if (mux_ldsc[ln].conn) { /* connected? */\r
785 if (mux_ldsc[ln].xmte) { /* xmt enabled? */\r
786 if (loopback) /* diagnostic mode? */\r
787 mux_ldsc[ln].conn = 0; /* clear connection */\r
788\r
789 if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */\r
790 TMLN *lp = &mux_ldsc[ln]; /* get line */\r
791 c = sim_tt_outcvt (c, TT_GET_MODE (muxl_unit[ln].flags));\r
792\r
793 if (mux_xpar[ln] & OTL_DIAG) /* xmt diagnose? */\r
794 mux_diag (fc); /* before munge */\r
795\r
796 if (loopback) { /* diagnostic mode? */\r
797 mux_ldsc[altln].conn = 1; /* set recv connection */\r
798 sim_activate (&muxu_unit, 1); /* schedule receive */\r
799 }\r
800\r
801 else { /* no loopback */\r
802 if (c >= 0) /* valid? */\r
803 tmxr_putc_ln (lp, c); /* output char */\r
804 tmxr_poll_tx (&mux_desc); /* poll xmt */\r
805 }\r
806 }\r
807\r
808 mux_xdon[ln] = 1; /* set for xmit irq */\r
809\r
810 if (DEBUG_PRI (muxu_dev, DEB_XFER) && (loopback | (c >= 0)))\r
811 fprintf (sim_deb, ">>MUXo svc: Line %d character %06o sent\n",\r
812 ln, (loopback ? fc : c));\r
813 }\r
814\r
815 else { /* buf full */\r
816 tmxr_poll_tx (&mux_desc); /* poll xmt */\r
817 sim_activate (uptr, muxl_unit[ln].wait); /* wait */\r
818 return SCPE_OK;\r
819 }\r
820 }\r
821\r
822if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */\r
823return SCPE_OK;\r
824}\r
825\r
826/* Look for data interrupt */\r
827\r
828void mux_data_int (void)\r
829{\r
830int32 i;\r
831\r
832for (i = 0; i < MUX_LINES; i++) { /* rcv lines */\r
833 if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */\r
834 muxl_ibuf = PUT_DCH (i) | /* lo buf = char */\r
835 mux_rbuf[i] & LIL_CHAR |\r
836 RCV_PAR (mux_rbuf[i]);\r
837 muxu_ibuf = PUT_DCH (i) | mux_sta[i]; /* hi buf = stat */\r
838 mux_rchp[i] = 0; /* clr char, stat */\r
839 mux_sta[i] = 0;\r
840\r
841 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
842 fprintf (sim_deb, ">>MUXd irq: Receive channel %d interrupt requested\n", i);\r
843\r
844 setFSR (muxl_dib.devno); /* interrupt */\r
845 return;\r
846 }\r
847 }\r
848for (i = 0; i < MUX_LINES; i++) { /* xmt lines */\r
849 if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */\r
850 muxl_ibuf = PUT_DCH (i) | /* lo buf = last rcv char */\r
851 mux_rbuf[i] & LIL_CHAR |\r
852 RCV_PAR (mux_rbuf[i]);\r
853 muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */\r
854 mux_xdon[i] = 0; /* clr done, stat */\r
855 mux_sta[i] = 0;\r
856\r
857 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
858 fprintf (sim_deb, ">>MUXd irq: Transmit channel %d interrupt requested\n", i);\r
859\r
860 setFSR (muxl_dib.devno); /* interrupt */\r
861 return;\r
862 }\r
863 }\r
864for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */\r
865 if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */\r
866 muxl_ibuf = PUT_DCH (i) | /* lo buf = char */\r
867 mux_rbuf[i] & LIL_CHAR |\r
868 RCV_PAR (mux_rbuf[i]);\r
869 muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */\r
870 mux_rchp[i] = 0; /* clr char, stat */\r
871 mux_sta[i] = 0;\r
872\r
873 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
874 fprintf (sim_deb, ">>MUXd irq: Receive channel %d interrupt requested\n", i);\r
875\r
876 setFSR (muxl_dib.devno);\r
877 return;\r
878 }\r
879 }\r
880return;\r
881}\r
882\r
883/* Look for control interrupt\r
884\r
885 If either of the incoming status bits does not match the stored status, and\r
886 the corresponding mismatch is enabled, a control interrupt request is\r
887 generated. Depending on the scan flag, we check either all 16 lines or just\r
888 the current line. If an interrupt is requested, the channel counter\r
889 indicates the interrupting channel.\r
890*/\r
891\r
892void mux_ctrl_int (void)\r
893{\r
894int32 i, line_count;\r
895\r
896line_count = (muxc_scan ? MUX_LINES : 1); /* check one or all lines */\r
897\r
898for (i = 0; i < line_count; i++) {\r
899 if (muxc_scan) /* scanning? */\r
900 muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */\r
901 if (LIC_TSTI (muxc_chan)) { /* status change? */\r
902\r
903 if (DEBUG_PRI (muxu_dev, DEB_CMDS))\r
904 fprintf (sim_deb,\r
905 ">>MUXc irq: Control channel %d interrupt requested (poll = %d)\n",\r
906 muxc_chan, i + 1);\r
907\r
908 setFSR (muxc_dib.devno); /* set flag */\r
909 break;\r
910 }\r
911 }\r
912return;\r
913}\r
914\r
915/* Set diagnostic lines for given character */\r
916\r
917void mux_diag (int32 c)\r
918{\r
919int32 i;\r
920\r
921for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) {\r
922 if (c & SCPE_BREAK) { /* break? */\r
923 mux_sta[i] = mux_sta[i] | LIU_BRK;\r
924 mux_rbuf[i] = 0; /* no char */\r
925 }\r
926 else {\r
927 if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;\r
928 mux_rchp[i] = 1;\r
929 mux_rbuf[i] = c;\r
930 }\r
931 }\r
932return;\r
933}\r
934\r
935/* Reset an individual line */\r
936\r
937void mux_reset_ln (int32 i)\r
938{\r
939mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */\r
940mux_rpar[i] = mux_xpar[i] = 0;\r
941mux_rchp[i] = mux_xdon[i] = 0;\r
942mux_sta[i] = 0;\r
943muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */\r
944if (mux_ldsc[i].conn && /* connected? */\r
945 ((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */\r
946 muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */\r
947 (muxl_unit[i].flags & UNIT_MDM? CDET: 0);\r
948sim_cancel (&muxl_unit[i]);\r
949return;\r
950}\r
951\r
952/* Reset routine */\r
953\r
954t_stat muxc_reset (DEVICE *dptr)\r
955{\r
956int32 i;\r
957\r
958if (dptr == &muxc_dev) { /* make all consistent */\r
959 hp_enbdis_pair (dptr, &muxl_dev);\r
960 hp_enbdis_pair (dptr, &muxu_dev);\r
961 }\r
962else if (dptr == &muxl_dev) {\r
963 hp_enbdis_pair (dptr, &muxc_dev);\r
964 hp_enbdis_pair (dptr, &muxu_dev);\r
965 }\r
966else {\r
967 hp_enbdis_pair (dptr, &muxc_dev);\r
968 hp_enbdis_pair (dptr, &muxl_dev);\r
969 }\r
970muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */\r
971muxl_dib.flg = muxl_dib.fbf = muxl_dib.srq = 1;\r
972muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */\r
973muxu_dib.flg = muxu_dib.fbf = muxu_dib.srq = 0; /* implemented */\r
974muxc_dib.cmd = muxc_dib.ctl = 0; /* init ctrl */\r
975muxc_dib.flg = muxc_dib.fbf = muxc_dib.srq = 1;\r
976muxc_chan = muxc_scan = 0; /* init modem scan */\r
977if (muxu_unit.flags & UNIT_ATT) { /* master att? */\r
978 if (!sim_is_active (&muxu_unit)) {\r
979 muxu_unit.wait = sync_poll (INITIAL); /* synchronize poll */\r
980 sim_activate (&muxu_unit, muxu_unit.wait); /* activate */\r
981 }\r
982 }\r
983else sim_cancel (&muxu_unit); /* else stop */\r
984for (i = 0; i < MUX_LINES; i++) mux_reset_ln (i); /* reset lines 0-15 */\r
985for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) /* reset lines 16-20 */\r
986 mux_rbuf[i] = mux_rpar[i] = mux_sta[i] = mux_rchp[i] = 0;\r
987return SCPE_OK;\r
988}\r
989\r
990/* Attach master unit */\r
991\r
992t_stat mux_attach (UNIT *uptr, char *cptr)\r
993{\r
994t_stat r;\r
995\r
996if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */\r
997 return SCPE_NOFNC; /* command not allowed */\r
998\r
999r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */\r
1000if (r != SCPE_OK) return r; /* error */\r
1001muxu_unit.wait = sync_poll (INITIAL); /* synchronize poll */\r
1002sim_activate (uptr, muxu_unit.wait); /* start poll */\r
1003return SCPE_OK;\r
1004}\r
1005\r
1006/* Detach master unit */\r
1007\r
1008t_stat mux_detach (UNIT *uptr)\r
1009{\r
1010int32 i;\r
1011t_stat r;\r
1012\r
1013r = tmxr_detach (&mux_desc, uptr); /* detach */\r
1014for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */\r
1015sim_cancel (uptr); /* stop poll */\r
1016return r;\r
1017}\r
1018\r
1019/* Diagnostic/normal mode routine\r
1020\r
1021 Diagnostic testing wants to exercise as much of the regular simulation code\r
1022 as possible to ensure good test coverage. Normally, input polling and output\r
1023 transmission only occurs on connected lines. In diagnostic mode, line\r
1024 connection flags are set selectively to enable processing on the lines under\r
1025 test. The alternative to this would require duplicating the send/receive\r
1026 code; the diagnostic would then test the copy but not the actual code used\r
1027 for normal character transfers, which is undesirable.\r
1028\r
1029 Therefore, to enable diagnostic mode, we must force a disconnect of the\r
1030 master socket and any connected Telnet lines, which clears the connection\r
1031 flags on all lines. Then we set the "transmission enabled" flags on all\r
1032 lines to enable output character processing for the diagnostic. (Normally,\r
1033 all of the flags are set when the multiplexer is first attached. Until then,\r
1034 the enable flags default to "not enabled," so we enable them explicitly\r
1035 here.)\r
1036*/\r
1037\r
1038t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1039{\r
1040int32 ln;\r
1041\r
1042if (val) { /* set diag? */\r
1043 mux_detach (uptr); /* detach lines */\r
1044 for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */\r
1045 mux_ldsc[ln].xmte = 1; /* on all lines */\r
1046 }\r
1047else { /* set term */\r
1048 for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */\r
1049 mux_ldsc[ln].conn = 0; /* on all lines */\r
1050 }\r
1051return SCPE_OK;\r
1052}\r
1053\r
1054/* Show summary processor */\r
1055\r
1056t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1057{\r
1058int32 i, t;\r
1059\r
1060if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */\r
1061 return SCPE_NOFNC; /* command not allowed */\r
1062\r
1063for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0);\r
1064if (t == 1) fprintf (st, "1 connection");\r
1065else fprintf (st, "%d connections", t);\r
1066return SCPE_OK;\r
1067}\r
1068\r
1069/* SHOW CONN/STAT processor */\r
1070\r
1071t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r
1072{\r
1073int32 i, t;\r
1074\r
1075if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */\r
1076 return SCPE_NOFNC; /* command not allowed */\r
1077\r
1078for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0);\r
1079if (t) {\r
1080 for (i = 0; i < MUX_LINES; i++) {\r
1081 if (mux_ldsc[i].conn) {\r
1082 if (val) tmxr_fconns (st, &mux_ldsc[i], i);\r
1083 else tmxr_fstats (st, &mux_ldsc[i], i);\r
1084 }\r
1085 }\r
1086 }\r
1087else fprintf (st, "all disconnected\n");\r
1088return SCPE_OK;\r
1089}\r