1 /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
2
3 Copyright (c) 2002-2012, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 MUX,MUXL,MUXM 12920A terminal multiplexor
27
28 10-Feb-12 JDB Deprecated DEVNO in favor of SC
29 28-Mar-11 JDB Tidied up signal handling
30 26-Oct-10 JDB Changed I/O signal handler for revised signal model
31 25-Nov-08 JDB Revised for new multiplexer library SHOW routines
32 09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16)
33 10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed
34 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach
35 27-Aug-08 JDB Added LINEORDER support
36 12-Aug-08 JDB Added BREAK deferral to allow RTE break-mode to work
37 26-Jun-08 JDB Rewrote device I/O to model backplane signals
38 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility
39 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements
40 Fixed "muxc_reset" to clear lines 16-20
41 26-Feb-07 JDB Added debug printouts
42 Fixed control card OTx to set current channel number
43 Fixed to set "muxl_ibuf" in response to a transmit interrupt
44 Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits
45 Fixed to set "mux_rchp" when a line break is received
46 Fixed incorrect "odd_par" table values
47 Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity
48 Fixed mux reset (ioCRS) to clear port parameters
49 Fixed to use PUT_DCH instead of PUT_CCH for data channel status
50 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode
51 28-Dec-06 JDB Added ioCRS state to I/O decoders
52 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init
53 22-Nov-05 RMS Revised for new terminal processing routines
54 29-Jun-05 RMS Added SET MUXLn DISCONNECT
55 07-Oct-04 JDB Allow enable/disable from any device
56 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
57 Implemented DMA SRQ (follows FLG)
58 05-Jan-04 RMS Revised for tmxr library changes
59 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny)
60 09-May-03 RMS Added network device flag
61 01-Nov-02 RMS Added 7B/8B support
62 22-Aug-02 RMS Updated for changes to sim_tmxr
63
64 Reference:
65 - 12920A Asynchronous Multiplexer Interface Kits Operating and Service Manual
66 (12920-90001, Oct-1972)
67
68
69 The 12920A was a 16-channel asynchronous terminal multiplexer. It supported
70 direct-connected terminals as well as modems at speeds up to 2400 baud. It
71 was the primary terminal multiplexer for the HP 2000 series of Time-Shared
72 BASIC systems.
73
74 The multiplexer was implemented as a three-card set consisting of a lower
75 data card, an upper data card, and a modem control card. Under simulation,
76 these are implemented by three devices:
77
78 MUXL lower data card (lines)
79 MUX upper data card (scanner)
80 MUXM control card (modem control)
81
82 The lower and upper data cards must be in adjacent I/O slots. The control
83 card may be placed in any slot, although in practice it was placed in the
84 slot above the upper data card, so that all three cards were physically
85 together.
86
87 The 12920A supported one or two control cards (two cards were used with
88 801-type automatic dialers). Under simulation, only one control card is
89 supported.
90
91 Implementation notes:
92
93 1. If a BREAK is detected during an input poll, and we are not in diagnostic
94 mode, we defer recognition until either a character is output or a second
95 successive input poll occurs. This is necessary for RTE break-mode
96 operation. Without this deferral, a BREAK during output would be ignored
97 by the RTE driver, making it impossible to stop a long listing.
98
99 The problem is due to timing differences between simulated and real time.
100 The RTE multiplexer driver is a privileged driver. Privileged drivers
101 bypass RTE to provide rapid interrupt handling. To inform RTE that an
102 operation is complete, e.g., that a line has been written, the interrupt
103 section of the driver sets a device timeout of one clock tick (10
104 milliseconds). When that timeout occurs, RTE is entered normally to
105 complete the I/O transaction. While the completion timeout is pending,
106 the driver ignores any further interrupts from the multiplexer line.
107
108 The maximum communication rate for the multiplexer is 2400 baud, or
109 approximately 4.2 milliseconds per character transferred. A typical line
110 of 20 characters would therefore take ~85 milliseconds, plus the 10
111 millisecond completion timeout, or about 95 milliseconds total. BREAK
112 recognition would be ignored for roughly 10% of that time. At lower baud
113 rates, recognition would be ignored for a correspondingly smaller
114 percentage of the time.
115
116 However, SIMH uses an optimized timing of 500 instructions per character
117 transfer, rather than the ~6600 instructions that a character transfer
118 should take, and so a typical 20-character line will take about 11,000
119 instructions. On the other hand, the clock tick is calibrated to real
120 time, and 10 milliseconds of real time takes about 420,000 instructions
121 on a 2.0 GHz PC. To be recognized, then, the BREAK key must be pressed
122 in a window that is open for about 2.5% of the time. Therefore, the
123 BREAK key will be ignored about 97.5% of the time, and RTE break-mode
124 effectively will not work.
125
126 Deferring BREAK recognition until the next character is output ensures
127 that the BREAK interrupt will be accepted (the simulator delivers input
128 interrupts before output interrupts, so the BREAK interrupt arrives
129 before the output character transmit interrupt). If an output operation
130 is not in progress, then the BREAK will be recognized at the next input
131 poll.
132 */
133
134
135 #include <ctype.h>
136
137 #include "hp2100_defs.h"
138 #include "sim_sock.h"
139 #include "sim_tmxr.h"
140
141
142 /* Unit references */
143
144 #define MUX_LINES 16 /* number of user lines */
145 #define MUX_ILINES 5 /* number of diag rcv only lines */
146
147
148 /* Service times */
149
150 #define MUXL_WAIT 500
151
152
153 /* Unit flags */
154
155 #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */
156 #define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */
157 #define UNIT_MDM (1 << UNIT_V_MDM)
158 #define UNIT_DIAG (1 << UNIT_V_DIAG)
159
160 /* Debug flags */
161
162 #define DEB_CMDS (1 << 0) /* Command initiation and completion */
163 #define DEB_CPU (1 << 1) /* CPU I/O */
164 #define DEB_XFER (1 << 2) /* Socket receive and transmit */
165
166 /* Channel number (OTA upper, LIA lower or upper) */
167
168 #define MUX_V_CHAN 10 /* channel num */
169 #define MUX_M_CHAN 037
170 #define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN)
171
172 /* OTA, lower = parameters or data */
173
174 #define OTL_P 0100000 /* parameter */
175 #define OTL_TX 0040000 /* transmit */
176 #define OTL_ENB 0020000 /* enable */
177 #define OTL_TPAR 0010000 /* xmt parity */
178 #define OTL_ECHO 0010000 /* rcv echo */
179 #define OTL_DIAG 0004000 /* diagnose */
180 #define OTL_SYNC 0004000 /* sync */
181 #define OTL_V_LNT 8 /* char length */
182 #define OTL_M_LNT 07
183 #define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT)
184 #define OTL_V_BAUD 0 /* baud rate */
185 #define OTL_M_BAUD 0377
186 #define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD)
187 #define OTL_CHAR 03777 /* char mask */
188 #define OTL_PAR 0200 /* char parity */
189
190 /* LIA, lower = received data */
191
192 #define LIL_PAR 0100000 /* parity */
193 #define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)
194 #define LIL_CHAR 01777 /* character */
195
196 /* LIA, upper = status */
197
198 #define LIU_SEEK 0100000 /* seeking NI */
199 #define LIU_DG 0000010 /* diagnose */
200 #define LIU_BRK 0000004 /* break */
201 #define LIU_LOST 0000002 /* char lost */
202 #define LIU_TR 0000001 /* trans/rcv */
203
204 /* OTA, control */
205
206 #define OTC_SCAN 0100000 /* scan */
207 #define OTC_UPD 0040000 /* update */
208 #define OTC_V_CHAN 10 /* channel */
209 #define OTC_M_CHAN 017
210 #define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN)
211 #define OTC_EC2 0000200 /* enable Cn upd */
212 #define OTC_EC1 0000100
213 #define OTC_C2 0000040 /* Cn flops */
214 #define OTC_C1 0000020
215 #define OTC_V_C 4 /* S1 to C1 */
216 #define OTC_ES2 0000010 /* enb comparison */
217 #define OTC_ES1 0000004
218 #define OTC_V_ES 2
219 #define OTC_SS2 0000002 /* SSn flops */
220 #define OTC_SS1 0000001
221 #define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)
222 #define RTS OCT_C2 /* C2 = rts */
223 #define DTR OTC_C1 /* C1 = dtr */
224
225 /* LIA, control */
226
227 #define LIC_MBO 0140000 /* always set */
228 #define LIC_V_CHAN 10 /* channel */
229 #define LIC_M_CHAN 017
230 #define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN)
231 #define LIC_I2 0001000 /* change flags */
232 #define LIC_I1 0000400
233 #define LIC_S2 0000002 /* Sn flops */
234 #define LIC_S1 0000001
235 #define LIC_V_I 8 /* S1 to I1 */
236 #define CDET LIC_S2 /* S2 = cdet */
237 #define DSR LIC_S1 /* S1 = dsr */
238
239 #define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \
240 ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
241 << LIC_V_I)
242
243
244 /* Program constants */
245
246 static const uint8 odd_par [256] = {
247 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */
248 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */
249 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */
250 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */
251 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */
252 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */
253 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */
254 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */
255 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */
256 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */
257 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */
258 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */
259 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */
260 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */
261 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */
262 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */
263 };
264
265 #define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR)
266 #define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR)
267
268
269 /* Multiplexer controller state variables */
270
271 struct {
272 FLIP_FLOP control; /* control flip-flop */
273 FLIP_FLOP flag; /* flag flip-flop */
274 FLIP_FLOP flagbuf; /* flag buffer flip-flop */
275 } muxl = { CLEAR, CLEAR, CLEAR };
276
277 uint32 muxl_ibuf = 0; /* low in: rcv data */
278 uint32 muxl_obuf = 0; /* low out: param */
279
280 uint32 muxu_ibuf = 0; /* upr in: status */
281 uint32 muxu_obuf = 0; /* upr out: chan */
282
283 struct {
284 FLIP_FLOP control; /* control flip-flop */
285 FLIP_FLOP flag; /* flag flip-flop */
286 FLIP_FLOP flagbuf; /* flag buffer flip-flop */
287 } muxc = { CLEAR, CLEAR, CLEAR };
288
289 uint32 muxc_chan = 0; /* ctrl chan */
290 uint32 muxc_scan = 0; /* ctrl scan */
291
292
293 /* Multiplexer per-line state variables */
294
295 uint16 mux_sta [MUX_LINES + MUX_ILINES]; /* line status */
296 uint16 mux_rpar [MUX_LINES + MUX_ILINES]; /* rcv param */
297 uint16 mux_xpar [MUX_LINES]; /* xmt param */
298 uint8 mux_rchp [MUX_LINES + MUX_ILINES]; /* rcv chr pend */
299 uint8 mux_xdon [MUX_LINES]; /* xmt done */
300 uint8 muxc_ota [MUX_LINES]; /* ctrl: Cn,ESn,SSn */
301 uint8 muxc_lia [MUX_LINES]; /* ctrl: Sn */
302 uint8 mux_defer [MUX_LINES]; /* break deferred flags */
303
304
305 /* Multiplexer per-line buffer variables */
306
307 uint16 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */
308 uint16 mux_xbuf[MUX_LINES]; /* xmt buf */
309
310
311 /* Multiplexer local routines */
312
313 void mux_receive (int32 ln, int32 c, t_bool diag);
314 void mux_data_int (void);
315 void mux_ctrl_int (void);
316 void mux_diag (int32 c);
317
318
319 /* Multiplexer global routines */
320
321 IOHANDLER muxlio;
322 IOHANDLER muxuio;
323 IOHANDLER muxcio;
324
325 t_stat muxi_svc (UNIT *uptr);
326 t_stat muxo_svc (UNIT *uptr);
327 t_stat muxc_reset (DEVICE *dptr);
328 t_stat mux_attach (UNIT *uptr, char *cptr);
329 t_stat mux_detach (UNIT *uptr);
330 t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);
331
332
333 /* MUXL/MUXU device information block.
334
335 The DIBs of adjacent cards must be contained in an array, so they are defined
336 here and referenced in the lower and upper card device structures.
337 */
338
339 DIB mux_dib[] = {
340 { &muxlio, MUXL },
341 { &muxuio, MUXU }
342 };
343
344 #define muxl_dib mux_dib[0]
345 #define muxu_dib mux_dib[1]
346
347
348 /* MUXL data structures.
349
350 muxl_dib MUXL device information block
351 muxl_unit MUXL unit list
352 muxl_reg MUXL register list
353 muxl_mod MUXL modifier list
354 muxl_dev MUXL device descriptor
355 */
356
357 TMXR mux_desc;
358
359 DEVICE muxl_dev;
360
361 UNIT muxl_unit[] = {
362 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
363 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
364 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
365 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
366 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
367 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
368 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
369 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
370 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
371 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
372 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
373 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
374 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
375 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
376 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT },
377 { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }
378 };
379
380 REG muxl_reg[] = {
381 { FLDATA (CTL, muxl.control, 0) },
382 { FLDATA (FLG, muxl.flag, 0) },
383 { FLDATA (FBF, muxl.flagbuf, 0) },
384 { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) },
385 { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) },
386 { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) },
387 { BRDATA (RBUF, mux_rbuf, 8, 16, MUX_LINES + MUX_ILINES) },
388 { BRDATA (XBUF, mux_xbuf, 8, 16, MUX_LINES) },
389 { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) },
390 { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) },
391 { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) },
392 { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
393 MUX_LINES, REG_NZ + PV_LEFT) },
394 { ORDATA (SC, muxl_dib.select_code, 6), REG_HRO },
395 { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO },
396 { NULL }
397 };
398
399 MTAB muxl_mod[] = {
400 { TT_MODE, TT_MODE_UC, "UC", "UC", NULL, NULL, NULL },
401 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL },
402 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL, NULL, NULL },
403 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL },
404
405 { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL, NULL, NULL },
406 { UNIT_MDM, 0, "no dataset", "NODATASET", NULL, NULL, NULL },
407
408 { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &mux_desc },
409 { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &mux_desc },
410
411 { MTAB_XTD | MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc },
412 { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev },
413 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev },
414
415 { 0 }
416 };
417
418 DEVICE muxl_dev = {
419 "MUXL", /* device name */
420 muxl_unit, /* unit array */
421 muxl_reg, /* register array */
422 muxl_mod, /* modifier array */
423 MUX_LINES, /* number of units */
424 10, /* address radix */
425 31, /* address width */
426 1, /* address increment */
427 8, /* data radix */
428 8, /* data width */
429 NULL, /* examine routine */
430 NULL, /* deposit routine */
431 &muxc_reset, /* reset routine */
432 NULL, /* boot routine */
433 NULL, /* attach routine */
434 NULL, /* detach routine */
435 &muxl_dib, /* device information block */
436 DEV_DISABLE, /* device flags */
437 0, /* debug control flags */
438 NULL, /* debug flag name table */
439 NULL, /* memory size change routine */
440 NULL }; /* logical device name */
441
442
443 /* MUXU data structures
444
445 mux_order MUX line connection order table
446 mux_ldsc MUX terminal multiplexer line descriptors
447 mux_desc MUX terminal multiplexer device descriptor
448
449 muxu_dib MUXU device information block
450 muxu_unit MUXU unit list
451 muxu_reg MUXU register list
452 muxu_mod MUXU modifier list
453 muxu_deb MUXU debug list
454 muxu_dev MUXU device descriptor
455 */
456
457 DEVICE muxu_dev;
458
459 int32 mux_order [MUX_LINES] = { -1 }; /* connection order */
460 TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */
461 TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */
462
463 UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST };
464
465 REG muxu_reg[] = {
466 { ORDATA (IBUF, muxu_ibuf, 16) },
467 { ORDATA (OBUF, muxu_obuf, 16) },
468 { ORDATA (SC, muxu_dib.select_code, 6), REG_HRO },
469 { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO },
470 { NULL }
471 };
472
473 MTAB muxu_mod[] = {
474 { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &mux_setdiag, NULL, NULL },
475 { UNIT_DIAG, 0, "terminal mode", "TERM", &mux_setdiag, NULL, NULL },
476 { UNIT_ATT, UNIT_ATT, "", NULL, NULL, &tmxr_show_summ, &mux_desc },
477
478 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINEORDER", "LINEORDER", &tmxr_set_lnorder, &tmxr_show_lnorder, &mux_desc },
479
480 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mux_desc },
481 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mux_desc },
482 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc },
483 { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev },
484 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev },
485
486 { 0 }
487 };
488
489 DEBTAB muxu_deb [] = {
490 { "CMDS", DEB_CMDS },
491 { "CPU", DEB_CPU },
492 { "XFER", DEB_XFER },
493 { NULL, 0 }
494 };
495
496 DEVICE muxu_dev = {
497 "MUX", /* device name */
498 &muxu_unit, /* unit array */
499 muxu_reg, /* register array */
500 muxu_mod, /* modifier array */
501 1, /* number of units */
502 10, /* address radix */
503 31, /* address width */
504 1, /* address increment */
505 8, /* data radix */
506 8, /* data width */
507 &tmxr_ex, /* examine routine */
508 &tmxr_dep, /* deposit routine */
509 &muxc_reset, /* reset routine */
510 NULL, /* boot routine */
511 &mux_attach, /* attach routine */
512 &mux_detach, /* detach routine */
513 &muxu_dib, /* device information block */
514 DEV_DISABLE | DEV_DEBUG, /* device flags */
515 0, /* debug control flags */
516 muxu_deb, /* debug flag name table */
517 NULL, /* memory size change routine */
518 NULL }; /* logical device name */
519
520
521 /* MUXC data structures.
522
523 muxc_dib MUXC device information block
524 muxc_unit MUXC unit list
525 muxc_reg MUXC register list
526 muxc_mod MUXC modifier list
527 muxc_dev MUXC device descriptor
528 */
529
530 DEVICE muxc_dev;
531
532 DIB muxc_dib = { &muxcio, MUXC };
533
534 UNIT muxc_unit = { UDATA (NULL, 0, 0) };
535
536 REG muxc_reg[] = {
537 { FLDATA (CTL, muxc.control, 0) },
538 { FLDATA (FLG, muxc.flag, 0) },
539 { FLDATA (FBF, muxc.flagbuf, 0) },
540 { FLDATA (SCAN, muxc_scan, 0) },
541 { ORDATA (CHAN, muxc_chan, 4) },
542 { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },
543 { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },
544 { ORDATA (SC, muxc_dib.select_code, 6), REG_HRO },
545 { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO },
546 { NULL }
547 };
548
549 MTAB muxc_mod[] = {
550 { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &muxc_dev },
551 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxc_dev },
552 { 0 }
553 };
554
555 DEVICE muxc_dev = {
556 "MUXM", /* device name */
557 &muxc_unit, /* unit array */
558 muxc_reg, /* register array */
559 muxc_mod, /* modifier array */
560 1, /* number of units */
561 10, /* address radix */
562 31, /* address width */
563 1, /* address increment */
564 8, /* data radix */
565 8, /* data width */
566 NULL, /* examine routine */
567 NULL, /* deposit routine */
568 &muxc_reset, /* reset routine */
569 NULL, /* boot routine */
570 NULL, /* attach routine */
571 NULL, /* detach routine */
572 &muxc_dib, /* device information block */
573 DEV_DISABLE, /* device flags */
574 0, /* debug control flags */
575 NULL, /* debug flag name table */
576 NULL, /* memory size change routine */
577 NULL }; /* logical device name */
578
579
580 /* Lower data card I/O signal handler.
581
582 Implementation notes:
583
584 1. The operating manual says that "at least 100 milliseconds of CLC 0s must
585 be programmed" by systems employing the multiplexer to ensure that the
586 multiplexer resets. In practice, such systems issue 128K CLC 0
587 instructions. As we provide debug logging of multiplexer resets, a CRS
588 counter is used to ensure that only one debug line is printed in response
589 to these 128K CRS invocations.
590 */
591
muxlio(DIB * dibptr,IOCYCLE signal_set,uint32 stat_data)592 uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
593 {
594 int32 ln;
595 const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
596 static uint32 crs_count = 0; /* cntr for ioCRS repeat */
597 IOSIGNAL signal;
598 IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
599
600 if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */
601 if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */
602 fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n",
603 crs_count);
604
605 crs_count = 0; /* clear counter */
606 }
607
608 while (working_set) {
609 signal = IONEXT (working_set); /* isolate next signal */
610
611 switch (signal) { /* dispatch I/O signal */
612
613 case ioCLF: /* clear flag flip-flop */
614 muxl.flag = muxl.flagbuf = CLEAR;
615
616 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
617 fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb);
618
619 mux_data_int (); /* look for new int */
620 break;
621
622
623 case ioSTF: /* set flag flip-flop */
624 case ioENF: /* enable flag */
625 muxl.flag = muxl.flagbuf = SET;
626
627 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
628 fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb);
629 break;
630
631
632 case ioSFC: /* skip if flag is clear */
633 setstdSKF (muxl);
634 break;
635
636
637 case ioSFS: /* skip if flag is set */
638 setstdSKF (muxl);
639 break;
640
641
642 case ioIOI: /* I/O data input */
643 stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */
644
645 if (DEBUG_PRI (muxu_dev, DEB_CPU))
646 fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf);
647 break;
648
649
650 case ioIOO: /* I/O data output */
651 muxl_obuf = IODATA (stat_data); /* store data */
652
653 if (DEBUG_PRI (muxu_dev, DEB_CPU)) {
654 if (muxl_obuf & OTL_P)
655 fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf);
656 else
657 fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf);
658 }
659 break;
660
661
662 case ioPOPIO: /* power-on preset to I/O */
663 muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */
664 break;
665
666
667 case ioCRS: /* control reset */
668 if (crs_count == 0) { /* first reset? */
669 muxl.control = CLEAR; /* clear control flip-flop */
670
671 for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */
672 mux_xbuf[ln] = mux_xpar[ln] = 0;
673 muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0;
674 }
675
676 for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) {
677 mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */
678 mux_sta[ln] = mux_rchp[ln] = 0;
679 }
680 }
681
682 crs_count = crs_count + 1; /* increment count */
683 break;
684
685
686 case ioCLC: /* clear control flip-flop */
687 muxl.control = CLEAR;
688
689 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
690 fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear);
691 break;
692
693
694 case ioSTC: /* set control flip-flop */
695 muxl.control = SET; /* set control */
696
697 ln = MUX_CHAN (muxu_obuf); /* get chan # */
698
699 if (muxl_obuf & OTL_TX) { /* transmit? */
700 if (ln < MUX_LINES) { /* line valid? */
701 if (muxl_obuf & OTL_P) { /* parameter? */
702 mux_xpar[ln] = muxl_obuf; /* store param value */
703 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
704 fprintf (sim_deb,
705 ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n",
706 hold_or_clear, ln, muxl_obuf);
707 }
708
709 else { /* data */
710 if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */
711 muxl_obuf = /* add parity bit */
712 muxl_obuf & ~OTL_PAR |
713 XMT_PAR(muxl_obuf);
714 mux_xbuf[ln] = muxl_obuf; /* load buffer */
715
716 if (sim_is_active (&muxl_unit[ln])) { /* still working? */
717 mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */
718 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
719 fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n",
720 hold_or_clear, ln);
721 }
722 else {
723 if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
724 mux_ldsc[ln].conn = 1; /* connect this line */
725 sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
726 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
727 fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n",
728 hold_or_clear, ln, muxl_obuf);
729 }
730 }
731 }
732 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
733 fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln);
734 }
735
736 else /* receive */
737 if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */
738 if (muxl_obuf & OTL_P) { /* parameter? */
739 mux_rpar[ln] = muxl_obuf; /* store param value */
740 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
741 fprintf (sim_deb,
742 ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n",
743 hold_or_clear, ln, muxl_obuf);
744 }
745
746 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */
747 fprintf (sim_deb,
748 ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n",
749 hold_or_clear, ln, muxl_obuf);
750 }
751
752 else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */
753 fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln);
754 break;
755
756
757 case ioSIR: /* set interrupt request */
758 setstdPRL (muxl); /* set standard PRL signal */
759 setstdIRQ (muxl); /* set standard IRQ signal */
760 setstdSRQ (muxl); /* set standard SRQ signal */
761 break;
762
763
764 case ioIAK: /* interrupt acknowledge */
765 muxl.flagbuf = CLEAR;
766 break;
767
768
769 default: /* all other signals */
770 break; /* are ignored */
771 }
772
773 working_set = working_set & ~signal; /* remove current signal from set */
774 }
775
776 return stat_data;
777 }
778
779
780 /* Upper data card I/O signal handler.
781
782 The upper data card does not have a control, flag, or flag buffer flip-flop.
783 It does not drive the IRQ or SRQ lines, so the I/O dispatcher does not handle
784 the ioSIR signal.
785
786 Implementation notes:
787
788 1. The upper and lower data card hardware takes a number of actions in
789 response to the CRS signal. Under simulation, these actions are taken by
790 the lower data card CRS handler.
791 */
792
muxuio(DIB * dibptr,IOCYCLE signal_set,uint32 stat_data)793 uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
794 {
795 IOSIGNAL signal;
796 IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
797
798 while (working_set) {
799 signal = IONEXT (working_set); /* isolate next signal */
800
801 switch (signal) { /* dispatch I/O signal */
802
803 case ioIOI: /* I/O data input */
804 stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */
805
806 if (DEBUG_PRI (muxu_dev, DEB_CPU))
807 fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n",
808 muxu_ibuf, MUX_CHAN(muxu_ibuf));
809 break;
810
811
812 case ioIOO: /* I/O data output */
813 muxu_obuf = IODATA (stat_data); /* store data */
814
815 if (DEBUG_PRI (muxu_dev, DEB_CPU))
816 fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf));
817 break;
818
819
820 default: /* all other signals */
821 break; /* are ignored */
822 }
823
824 working_set = working_set & ~signal; /* remove current signal from set */
825 }
826
827 return stat_data;
828 }
829
830
831 /* Control card I/O signal handler.
832
833 In diagnostic mode, the control signals C1 and C2 are looped back to status
834 signals S1 and S2. Changing the control signals may cause an interrupt, so a
835 test is performed after IOO processing.
836 */
837
muxcio(DIB * dibptr,IOCYCLE signal_set,uint32 stat_data)838 uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data)
839 {
840 const char *hold_or_clear = (signal_set & ioCLF ? ",C" : "");
841 uint16 data;
842 int32 ln, old;
843 IOSIGNAL signal;
844 IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */
845
846 while (working_set) {
847 signal = IONEXT (working_set); /* isolate next signal */
848
849 switch (signal) { /* dispatch I/O signal */
850
851 case ioCLF: /* clear flag flip-flop */
852 muxc.flag = muxc.flagbuf = CLEAR;
853
854 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
855 fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb);
856
857 mux_ctrl_int (); /* look for new int */
858 break;
859
860
861 case ioSTF: /* set flag flip-flop */
862 case ioENF: /* enable flag */
863 muxc.flag = muxc.flagbuf = SET;
864
865 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
866 fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb);
867 break;
868
869
870 case ioSFC: /* skip if flag is clear */
871 setstdSKF (muxc);
872 break;
873
874
875 case ioSFS: /* skip if flag is set */
876 setstdSKF (muxc);
877 break;
878
879
880 case ioIOI: /* I/O data input */
881 data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */
882 LIC_TSTI (muxc_chan) | /* I2, I1 */
883 (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
884 (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */
885
886 if (DEBUG_PRI (muxu_dev, DEB_CPU))
887 fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n",
888 hold_or_clear, data, muxc_chan);
889
890 muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
891 stat_data = IORETURN (SCPE_OK, data); /* merge in return status */
892 break;
893
894
895 case ioIOO: /* I/O data output */
896 data = IODATA (stat_data); /* clear supplied status */
897 ln = muxc_chan = OTC_CHAN (data); /* set channel */
898
899 if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */
900 else muxc_scan = 0;
901
902 if (data & OTC_UPD) { /* update? */
903 old = muxc_ota[ln]; /* save prior val */
904 muxc_ota[ln] = /* save ESn,SSn */
905 (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW);
906
907 if (data & OTC_EC2) /* if EC2, upd C2 */
908 muxc_ota[ln] =
909 (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2);
910
911 if (data & OTC_EC1) /* if EC1, upd C1 */
912 muxc_ota[ln] =
913 (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1);
914
915 if (muxu_unit.flags & UNIT_DIAG) /* loopback? */
916 muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */
917 (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) |
918 (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C;
919
920 else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
921 (old & DTR) && /* DTR drop? */
922 !(muxc_ota[ln] & DTR)) {
923 tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n");
924 tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
925 muxc_lia[ln] = 0; /* dataset off */
926 }
927 } /* end update */
928
929 if (DEBUG_PRI (muxu_dev, DEB_CPU))
930 fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n",
931 hold_or_clear, data, ln);
932
933 if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */
934 mux_ctrl_int (); /* status chg may interrupt */
935 break;
936
937
938 case ioPOPIO: /* power-on preset to I/O */
939 muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */
940 break;
941
942
943 case ioCRS: /* control reset */
944 case ioCLC: /* clear control flip-flop */
945 muxc.control = CLEAR;
946 break;
947
948
949 case ioSTC: /* set control flip-flop */
950 muxc.control = SET;
951 break;
952
953
954 case ioSIR: /* set interrupt request */
955 setstdPRL (muxc); /* set standard PRL signal */
956 setstdIRQ (muxc); /* set standard IRQ signal */
957 setstdSRQ (muxc); /* set standard SRQ signal */
958 break;
959
960
961 case ioIAK: /* interrupt acknowledge */
962 muxc.flagbuf = CLEAR;
963 break;
964
965
966 default: /* all other signals */
967 break; /* are ignored */
968 }
969
970 working_set = working_set & ~signal; /* remove current signal from set */
971 }
972
973 return stat_data;
974 }
975
976
977 /* Unit service - receive side
978
979 Poll for new connections
980 Poll all active lines for input
981 */
982
muxi_svc(UNIT * uptr)983 t_stat muxi_svc (UNIT *uptr)
984 {
985 int32 ln, c;
986 t_bool loopback;
987
988 loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */
989
990 if (!loopback) { /* terminal mode? */
991 if (uptr->wait == POLL_FIRST) /* first poll? */
992 uptr->wait = sync_poll (INITIAL); /* initial synchronization */
993 else /* not first */
994 uptr->wait = sync_poll (SERVICE); /* continue synchronization */
995
996 sim_activate (uptr, uptr->wait); /* continue polling */
997
998 ln = tmxr_poll_conn (&mux_desc); /* look for connect */
999
1000 if (ln >= 0) { /* got one? */
1001 if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
1002 (muxc_ota[ln] & DTR)) /* DTR? */
1003 muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */
1004 muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */
1005 mux_ldsc[ln].rcve = 1; /* rcv enabled */
1006 }
1007 tmxr_poll_rx (&mux_desc); /* poll for input */
1008 }
1009
1010 for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */
1011 if (mux_ldsc[ln].conn) { /* connected? */
1012 if (loopback) { /* diagnostic mode? */
1013 c = mux_xbuf[ln ^ 1] & OTL_CHAR; /* get char from xmit line */
1014 if (c == 0) /* all char bits = 0? */
1015 c = c | SCPE_BREAK; /* set break flag */
1016 mux_ldsc[ln].conn = 0; /* clear connection */
1017 }
1018
1019 else if (mux_defer[ln]) /* break deferred? */
1020 c = SCPE_BREAK; /* supply it now */
1021
1022 else
1023 c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */
1024
1025 if (c) /* valid char? */
1026 mux_receive (ln, c, loopback); /* process it */
1027 }
1028
1029 else /* not connected */
1030 if (!loopback) /* terminal mode? */
1031 muxc_lia[ln] = 0; /* line disconnected */
1032 }
1033
1034 if (!muxl.flag) mux_data_int (); /* scan for data int */
1035 if (!muxc.flag) mux_ctrl_int (); /* scan modem */
1036 return SCPE_OK;
1037 }
1038
1039
1040 /* Unit service - transmit side */
1041
muxo_svc(UNIT * uptr)1042 t_stat muxo_svc (UNIT *uptr)
1043 {
1044 int32 c, fc, ln, altln;
1045 t_bool loopback;
1046
1047 ln = uptr - muxl_unit; /* line # */
1048 altln = ln ^ 1; /* alt. line for diag mode */
1049
1050 fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */
1051 c = fc & 0377; /* Telnet character data */
1052
1053 loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */
1054
1055 if (mux_ldsc[ln].conn) { /* connected? */
1056 if (mux_ldsc[ln].xmte) { /* xmt enabled? */
1057 if (loopback) /* diagnostic mode? */
1058 mux_ldsc[ln].conn = 0; /* clear connection */
1059
1060 else if (mux_defer[ln]) /* break deferred? */
1061 mux_receive (ln, SCPE_BREAK, loopback); /* process it now */
1062
1063 if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */
1064 TMLN *lp = &mux_ldsc[ln]; /* get line */
1065 c = sim_tt_outcvt (c, TT_GET_MODE (muxl_unit[ln].flags));
1066
1067 if (mux_xpar[ln] & OTL_DIAG) /* xmt diagnose? */
1068 mux_diag (fc); /* before munge */
1069
1070 if (loopback) { /* diagnostic mode? */
1071 mux_ldsc[altln].conn = 1; /* set recv connection */
1072 sim_activate (&muxu_unit, 1); /* schedule receive */
1073 }
1074
1075 else { /* no loopback */
1076 if (c >= 0) /* valid? */
1077 tmxr_putc_ln (lp, c); /* output char */
1078 tmxr_poll_tx (&mux_desc); /* poll xmt */
1079 }
1080 }
1081
1082 mux_xdon[ln] = 1; /* set for xmit irq */
1083
1084 if (DEBUG_PRI (muxu_dev, DEB_XFER) && (loopback | (c >= 0)))
1085 fprintf (sim_deb, ">>MUXl xfer: Line %d character %s sent\n",
1086 ln, fmt_char ((uint8) (loopback ? fc : c)));
1087 }
1088
1089 else { /* buf full */
1090 tmxr_poll_tx (&mux_desc); /* poll xmt */
1091 sim_activate (uptr, muxl_unit[ln].wait); /* wait */
1092 return SCPE_OK;
1093 }
1094 }
1095
1096 if (!muxl.flag) mux_data_int (); /* scan for int */
1097 return SCPE_OK;
1098 }
1099
1100
1101 /* Process a character received from a multiplexer port */
1102
mux_receive(int32 ln,int32 c,t_bool diag)1103 void mux_receive (int32 ln, int32 c, t_bool diag)
1104 {
1105 if (c & SCPE_BREAK) { /* break? */
1106 if (mux_defer[ln] || diag) { /* break deferred or diagnostic mode? */
1107 mux_defer[ln] = 0; /* process now */
1108 mux_rbuf[ln] = 0; /* break returns NUL */
1109 mux_sta[ln] = mux_sta[ln] | LIU_BRK; /* set break status */
1110
1111 if (DEBUG_PRI (muxu_dev, DEB_XFER)) {
1112 if (diag)
1113 fputs (">>MUXl xfer: Break detected\n", sim_deb);
1114 else
1115 fputs (">>MUXl xfer: Deferred break processed\n", sim_deb);
1116 }
1117 }
1118
1119 else {
1120 mux_defer[ln] = 1; /* defer break */
1121
1122 if (DEBUG_PRI (muxu_dev, DEB_XFER))
1123 fputs (">>MUXl xfer: Break detected and deferred\n", sim_deb);
1124
1125 return;
1126 }
1127 }
1128 else { /* normal */
1129 if (mux_rchp[ln]) /* char already pending? */
1130 mux_sta[ln] = mux_sta[ln] | LIU_LOST;
1131
1132 if (!diag) { /* terminal mode? */
1133 c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags));
1134 if (mux_rpar[ln] & OTL_ECHO) { /* echo? */
1135 TMLN *lp = &mux_ldsc[ln]; /* get line */
1136 tmxr_putc_ln (lp, c); /* output char */
1137 tmxr_poll_tx (&mux_desc); /* poll xmt */
1138 }
1139 }
1140 mux_rbuf[ln] = c; /* save char */
1141 }
1142
1143 mux_rchp[ln] = 1; /* char pending */
1144
1145 if (DEBUG_PRI (muxu_dev, DEB_XFER))
1146 fprintf (sim_deb, ">>MUXl xfer: Line %d character %s received\n",
1147 ln, fmt_char ((uint8) c));
1148
1149 if (mux_rpar[ln] & OTL_DIAG) /* diagnose this line? */
1150 mux_diag (c); /* do diagnosis */
1151
1152 return;
1153 }
1154
1155
1156 /* Look for data interrupt */
1157
mux_data_int(void)1158 void mux_data_int (void)
1159 {
1160 int32 i;
1161
1162 for (i = 0; i < MUX_LINES; i++) { /* rcv lines */
1163 if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
1164 muxl_ibuf = PUT_DCH (i) | /* lo buf = char */
1165 mux_rbuf[i] & LIL_CHAR |
1166 RCV_PAR (mux_rbuf[i]);
1167 muxu_ibuf = PUT_DCH (i) | mux_sta[i]; /* hi buf = stat */
1168 mux_rchp[i] = 0; /* clr char, stat */
1169 mux_sta[i] = 0;
1170
1171 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
1172 fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i);
1173
1174 muxlio (&muxl_dib, ioENF, 0); /* interrupt */
1175 return;
1176 }
1177 }
1178 for (i = 0; i < MUX_LINES; i++) { /* xmt lines */
1179 if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */
1180 muxl_ibuf = PUT_DCH (i) | /* lo buf = last rcv char */
1181 mux_rbuf[i] & LIL_CHAR |
1182 RCV_PAR (mux_rbuf[i]);
1183 muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */
1184 mux_xdon[i] = 0; /* clr done, stat */
1185 mux_sta[i] = 0;
1186
1187 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
1188 fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i);
1189
1190 muxlio (&muxl_dib, ioENF, 0); /* interrupt */
1191 return;
1192 }
1193 }
1194 for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */
1195 if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
1196 muxl_ibuf = PUT_DCH (i) | /* lo buf = char */
1197 mux_rbuf[i] & LIL_CHAR |
1198 RCV_PAR (mux_rbuf[i]);
1199 muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */
1200 mux_rchp[i] = 0; /* clr char, stat */
1201 mux_sta[i] = 0;
1202
1203 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
1204 fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i);
1205
1206 muxlio (&muxl_dib, ioENF, 0); /* interrupt */
1207 return;
1208 }
1209 }
1210 return;
1211 }
1212
1213
1214 /* Look for control interrupt
1215
1216 If either of the incoming status bits does not match the stored status, and
1217 the corresponding mismatch is enabled, a control interrupt request is
1218 generated. Depending on the scan flag, we check either all 16 lines or just
1219 the current line. If an interrupt is requested, the channel counter
1220 indicates the interrupting channel.
1221 */
1222
mux_ctrl_int(void)1223 void mux_ctrl_int (void)
1224 {
1225 int32 i, line_count;
1226
1227 line_count = (muxc_scan ? MUX_LINES : 1); /* check one or all lines */
1228
1229 for (i = 0; i < line_count; i++) {
1230 if (muxc_scan) /* scanning? */
1231 muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */
1232 if (LIC_TSTI (muxc_chan)) { /* status change? */
1233
1234 if (DEBUG_PRI (muxu_dev, DEB_CMDS))
1235 fprintf (sim_deb,
1236 ">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n",
1237 muxc_chan, i + 1);
1238
1239 muxcio (&muxc_dib, ioENF, 0); /* set flag */
1240 break;
1241 }
1242 }
1243 return;
1244 }
1245
1246
1247 /* Set diagnostic lines for given character */
1248
mux_diag(int32 c)1249 void mux_diag (int32 c)
1250 {
1251 int32 i;
1252
1253 for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) {
1254 if (c & SCPE_BREAK) { /* break? */
1255 mux_sta[i] = mux_sta[i] | LIU_BRK;
1256 mux_rbuf[i] = 0; /* no char */
1257 }
1258 else {
1259 if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;
1260 mux_rchp[i] = 1;
1261 mux_rbuf[i] = c;
1262 }
1263 }
1264 return;
1265 }
1266
1267
1268 /* Reset an individual line */
1269
mux_reset_ln(int32 i)1270 void mux_reset_ln (int32 i)
1271 {
1272 mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */
1273 mux_rpar[i] = mux_xpar[i] = 0;
1274 mux_rchp[i] = mux_xdon[i] = 0;
1275 mux_sta[i] = mux_defer[i] = 0;
1276 muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */
1277 if (mux_ldsc[i].conn && /* connected? */
1278 ((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */
1279 muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */
1280 (muxl_unit[i].flags & UNIT_MDM? CDET: 0);
1281 sim_cancel (&muxl_unit[i]);
1282 return;
1283 }
1284
1285
1286 /* Reset routine for lower data, upper data, and control cards */
1287
muxc_reset(DEVICE * dptr)1288 t_stat muxc_reset (DEVICE *dptr)
1289 {
1290 int32 i;
1291 DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */
1292
1293 if (dptr == &muxc_dev) { /* make all consistent */
1294 hp_enbdis_pair (dptr, &muxl_dev);
1295 hp_enbdis_pair (dptr, &muxu_dev);
1296 }
1297 else if (dptr == &muxl_dev) {
1298 hp_enbdis_pair (dptr, &muxc_dev);
1299 hp_enbdis_pair (dptr, &muxu_dev);
1300 }
1301 else {
1302 hp_enbdis_pair (dptr, &muxc_dev);
1303 hp_enbdis_pair (dptr, &muxl_dev);
1304 }
1305
1306 IOPRESET (dibptr); /* PRESET device (does not use PON) */
1307
1308 muxc_chan = muxc_scan = 0; /* init modem scan */
1309
1310 if (muxu_unit.flags & UNIT_ATT) { /* master att? */
1311 muxu_unit.wait = POLL_FIRST; /* set up poll */
1312 sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */
1313 }
1314 else
1315 sim_cancel (&muxu_unit); /* else stop */
1316
1317 for (i = 0; i < MUX_LINES; i++)
1318 mux_reset_ln (i); /* reset lines 0-15 */
1319
1320 for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) /* reset lines 16-20 */
1321 mux_rbuf[i] = mux_rpar[i] = mux_sta[i] = mux_rchp[i] = 0;
1322
1323 return SCPE_OK;
1324 }
1325
1326
1327 /* Attach master unit */
1328
mux_attach(UNIT * uptr,char * cptr)1329 t_stat mux_attach (UNIT *uptr, char *cptr)
1330 {
1331 t_stat status = SCPE_OK;
1332
1333 if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */
1334 return SCPE_NOFNC; /* command not allowed */
1335
1336 status = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
1337
1338 if (status == SCPE_OK) {
1339 muxu_unit.wait = POLL_FIRST; /* set up poll */
1340 sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */
1341 }
1342
1343 return status;
1344 }
1345
1346
1347 /* Detach master unit */
1348
mux_detach(UNIT * uptr)1349 t_stat mux_detach (UNIT *uptr)
1350 {
1351 int32 i;
1352 t_stat r;
1353
1354 r = tmxr_detach (&mux_desc, uptr); /* detach */
1355 for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */
1356 sim_cancel (uptr); /* stop poll */
1357 return r;
1358 }
1359
1360
1361 /* Diagnostic/normal mode routine,
1362
1363 Diagnostic testing wants to exercise as much of the regular simulation code
1364 as possible to ensure good test coverage. Normally, input polling and output
1365 transmission only occurs on connected lines. In diagnostic mode, line
1366 connection flags are set selectively to enable processing on the lines under
1367 test. The alternative to this would require duplicating the send/receive
1368 code; the diagnostic would then test the copy but not the actual code used
1369 for normal character transfers, which is undesirable.
1370
1371 Therefore, to enable diagnostic mode, we must force a disconnect of the
1372 master socket and any connected Telnet lines, which clears the connection
1373 flags on all lines. Then we set the "transmission enabled" flags on all
1374 lines to enable output character processing for the diagnostic. (Normally,
1375 all of the flags are set when the multiplexer is first attached. Until then,
1376 the enable flags default to "not enabled," so we enable them explicitly
1377 here.)
1378 */
1379
mux_setdiag(UNIT * uptr,int32 val,char * cptr,void * desc)1380 t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)
1381 {
1382 int32 ln;
1383
1384 if (val) { /* set diag? */
1385 mux_detach (uptr); /* detach lines */
1386 for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */
1387 mux_ldsc[ln].xmte = 1; /* on all lines */
1388 }
1389 else { /* set term */
1390 for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */
1391 mux_ldsc[ln].conn = 0; /* on all lines */
1392 }
1393 return SCPE_OK;
1394 }
1395