1 /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
3 Copyright (c) 2002-2008, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 mux,muxl,muxc 12920A terminal multiplexor
28 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility
29 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements
30 Fixed "muxc_reset" to clear lines 16-20
31 26-Feb-07 JDB Added debug printouts
32 Fixed control card OTx to set current channel number
33 Fixed to set "muxl_ibuf" in response to a transmit interrupt
34 Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits
35 Fixed to set "mux_rchp" when a line break is received
36 Fixed incorrect "odd_par" table values
37 Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity
38 Fixed mux reset (ioCRS) to clear port parameters
39 Fixed to use PUT_DCH instead of PUT_CCH for data channel status
40 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode
41 28-Dec-06 JDB Added ioCRS state to I/O decoders
42 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init
43 22-Nov-05 RMS Revised for new terminal processing routines
44 29-Jun-05 RMS Added SET MUXLn DISCONNECT
45 07-Oct-04 JDB Allow enable/disable from any device
46 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
47 Implemented DMA SRQ (follows FLG)
48 05-Jan-04 RMS Revised for tmxr library changes
49 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny)
50 09-May-03 RMS Added network device flag
51 01-Nov-02 RMS Added 7B/8B support
52 22-Aug-02 RMS Updated for changes to sim_tmxr
54 The 12920A consists of three separate devices
56 mux scanner (upper data card)
57 muxl lines (lower data card)
58 muxm modem control (control card)
60 The lower data card has no CMD flop; the control card has no CMD flop.
61 The upper data card has none of the usual flops.
64 - 12920A Asynchronous Multiplexer Interface Kits Operating and Service
65 Manual (12920-90001, Oct-1972)
68 #include "hp2100_defs.h"
73 #define MUX_LINES 16 /* user lines */
74 #define MUX_ILINES 5 /* diag rcv only */
75 #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */
76 #define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */
77 #define UNIT_MDM (1 << UNIT_V_MDM)
78 #define UNIT_DIAG (1 << UNIT_V_DIAG)
81 /* Channel number (OTA upper, LIA lower or upper) */
83 #define MUX_V_CHAN 10 /* channel num */
84 #define MUX_M_CHAN 037
85 #define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN)
87 /* OTA, lower = parameters or data */
89 #define OTL_P 0100000 /* parameter */
90 #define OTL_TX 0040000 /* transmit */
91 #define OTL_ENB 0020000 /* enable */
92 #define OTL_TPAR 0010000 /* xmt parity */
93 #define OTL_ECHO 0010000 /* rcv echo */
94 #define OTL_DIAG 0004000 /* diagnose */
95 #define OTL_SYNC 0004000 /* sync */
96 #define OTL_V_LNT 8 /* char length */
98 #define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT)
99 #define OTL_V_BAUD 0 /* baud rate */
100 #define OTL_M_BAUD 0377
101 #define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD)
102 #define OTL_CHAR 03777 /* char mask */
103 #define OTL_PAR 0200 /* char parity */
105 /* LIA, lower = received data */
107 #define LIL_PAR 0100000 /* parity */
108 #define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)
109 #define LIL_CHAR 01777 /* character */
111 /* LIA, upper = status */
113 #define LIU_SEEK 0100000 /* seeking NI */
114 #define LIU_DG 0000010 /* diagnose */
115 #define LIU_BRK 0000004 /* break */
116 #define LIU_LOST 0000002 /* char lost */
117 #define LIU_TR 0000001 /* trans/rcv */
121 #define OTC_SCAN 0100000 /* scan */
122 #define OTC_UPD 0040000 /* update */
123 #define OTC_V_CHAN 10 /* channel */
124 #define OTC_M_CHAN 017
125 #define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN)
126 #define OTC_EC2 0000200 /* enable Cn upd */
127 #define OTC_EC1 0000100
128 #define OTC_C2 0000040 /* Cn flops */
129 #define OTC_C1 0000020
130 #define OTC_V_C 4 /* S1 to C1 */
131 #define OTC_ES2 0000010 /* enb comparison */
132 #define OTC_ES1 0000004
134 #define OTC_SS2 0000002 /* SSn flops */
135 #define OTC_SS1 0000001
136 #define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)
137 #define RTS OCT_C2 /* C2 = rts */
138 #define DTR OTC_C1 /* C1 = dtr */
142 #define LIC_MBO 0140000 /* always set */
143 #define LIC_V_CHAN 10 /* channel */
144 #define LIC_M_CHAN 017
145 #define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN)
146 #define LIC_I2 0001000 /* change flags */
147 #define LIC_I1 0000400
148 #define LIC_S2 0000002 /* Sn flops */
149 #define LIC_S1 0000001
150 #define LIC_V_I 8 /* S1 to I1 */
151 #define CDET LIC_S2 /* S2 = cdet */
152 #define DSR LIC_S1 /* S1 = dsr */
154 #define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \
155 ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
160 #define DEB_CMDS (1 << 0) /* Command initiation and completion */
161 #define DEB_CPU (1 << 1) /* CPU I/O */
162 #define DEB_XFER (1 << 2) /* Socket receive and transmit */
165 extern uint32 dev_cmd
[2], dev_ctl
[2], dev_flg
[2], dev_fbf
[2], dev_srq
[2];
166 extern FILE *sim_deb
;
168 uint16 mux_sta
[MUX_LINES
+ MUX_ILINES
]; /* line status */
169 uint16 mux_rpar
[MUX_LINES
+ MUX_ILINES
]; /* rcv param */
170 uint16 mux_xpar
[MUX_LINES
]; /* xmt param */
171 uint16 mux_rbuf
[MUX_LINES
+ MUX_ILINES
]; /* rcv buf */
172 uint16 mux_xbuf
[MUX_LINES
]; /* xmt buf */
173 uint8 mux_rchp
[MUX_LINES
+ MUX_ILINES
]; /* rcv chr pend */
174 uint8 mux_xdon
[MUX_LINES
]; /* xmt done */
175 uint8 muxc_ota
[MUX_LINES
]; /* ctrl: Cn,ESn,SSn */
176 uint8 muxc_lia
[MUX_LINES
]; /* ctrl: Sn */
177 uint32 muxl_ibuf
= 0; /* low in: rcv data */
178 uint32 muxl_obuf
= 0; /* low out: param */
179 uint32 muxu_ibuf
= 0; /* upr in: status */
180 uint32 muxu_obuf
= 0; /* upr out: chan */
181 uint32 muxc_chan
= 0; /* ctrl chan */
182 uint32 muxc_scan
= 0; /* ctrl scan */
184 TMLN mux_ldsc
[MUX_LINES
] = { { 0 } }; /* line descriptors */
185 TMXR mux_desc
= { MUX_LINES
, 0, 0, mux_ldsc
}; /* mux descriptor */
187 DEVICE muxl_dev
, muxu_dev
, muxc_dev
;
188 int32
muxlio (int32 inst
, int32 IR
, int32 dat
);
189 int32
muxuio (int32 inst
, int32 IR
, int32 dat
);
190 int32
muxcio (int32 inst
, int32 IR
, int32 dat
);
191 t_stat
muxi_svc (UNIT
*uptr
);
192 t_stat
muxo_svc (UNIT
*uptr
);
193 t_stat
muxc_reset (DEVICE
*dptr
);
194 t_stat
mux_attach (UNIT
*uptr
, char *cptr
);
195 t_stat
mux_detach (UNIT
*uptr
);
196 t_stat
mux_setdiag (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
197 t_stat
mux_summ (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
198 t_stat
mux_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
199 void mux_data_int (void);
200 void mux_ctrl_int (void);
201 void mux_diag (int32 c
);
203 static uint8 odd_par
[256] = {
204 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */
205 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */
206 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */
207 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */
208 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */
209 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */
210 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */
211 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */
212 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */
213 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */
214 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */
215 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */
216 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */
217 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */
218 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */
219 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */
222 #define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR)
223 #define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR)
225 /* Debug flags table */
228 { "CMDS", DEB_CMDS
},
230 { "XFER", DEB_XFER
},
234 { MUXL
, 0, 0, 0, 0, 0, &muxlio
},
235 { MUXU
, 0, 0, 0, 0, 0, &muxuio
}
238 #define muxl_dib mux_dib[0]
239 #define muxu_dib mux_dib[1]
241 /* MUX data structures
243 muxu_dev MUX device descriptor
244 muxu_unit MUX unit descriptor
245 muxu_reg MUX register list
246 muxu_mod MUX modifiers list
249 UNIT muxu_unit
= { UDATA (&muxi_svc
, UNIT_ATTABLE
, 0), POLL_WAIT
};
252 { ORDATA (IBUF
, muxu_ibuf
, 16) },
253 { ORDATA (OBUF
, muxu_obuf
, 16) },
254 { FLDATA (CMD
, muxu_dib
.cmd
, 0), REG_HRO
},
255 { FLDATA (CTL
, muxu_dib
.ctl
, 0), REG_HRO
},
256 { FLDATA (FLG
, muxu_dib
.flg
, 0), REG_HRO
},
257 { FLDATA (FBF
, muxu_dib
.fbf
, 0), REG_HRO
},
258 { FLDATA (SRQ
, muxu_dib
.srq
, 0), REG_HRO
},
259 { ORDATA (DEVNO
, muxu_dib
.devno
, 6), REG_HRO
},
264 { UNIT_DIAG
, UNIT_DIAG
, "diagnostic mode", "DIAG", &mux_setdiag
},
265 { UNIT_DIAG
, 0, "terminal mode", "TERM", &mux_setdiag
},
266 { UNIT_ATT
, UNIT_ATT
, "connections", NULL
, NULL
, &mux_summ
},
267 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 1, "CONNECTIONS", NULL
,
268 NULL
, &mux_show
, NULL
},
269 { MTAB_XTD
| MTAB_VDV
| MTAB_NMO
, 0, "STATISTICS", NULL
,
270 NULL
, &mux_show
, NULL
},
271 { MTAB_XTD
|MTAB_VDV
, 1, "DEVNO", "DEVNO",
272 &hp_setdev
, &hp_showdev
, &muxl_dev
},
273 { MTAB_XTD
| MTAB_VDV
, 1, NULL
, "DISCONNECT",
274 &tmxr_dscln
, NULL
, &mux_desc
},
279 "MUX", &muxu_unit
, muxu_reg
, muxu_mod
,
281 &tmxr_ex
, &tmxr_dep
, &muxc_reset
,
282 NULL
, &mux_attach
, &mux_detach
,
283 &muxu_dib
, DEV_NET
| DEV_DISABLE
| DEV_DEBUG
,
284 0, mux_deb
, NULL
, NULL
287 /* MUXL data structures
289 muxl_dev MUXL device descriptor
290 muxl_unit MUXL unit descriptor
291 muxl_reg MUXL register list
292 muxl_mod MUXL modifiers list
296 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
297 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
298 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
299 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
300 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
301 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
302 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
303 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
304 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
305 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
306 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
307 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
308 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
309 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
310 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
311 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
},
312 { UDATA (&muxo_svc
, TT_MODE_UC
, 0), MUXL_WAIT
}
316 { TT_MODE
, TT_MODE_UC
, "UC", "UC", NULL
},
317 { TT_MODE
, TT_MODE_7B
, "7b", "7B", NULL
},
318 { TT_MODE
, TT_MODE_8B
, "8b", "8B", NULL
},
319 { TT_MODE
, TT_MODE_7P
, "7p", "7P", NULL
},
320 { UNIT_MDM
, 0, "no dataset", "NODATASET", NULL
},
321 { UNIT_MDM
, UNIT_MDM
, "dataset", "DATASET", NULL
},
322 { MTAB_XTD
|MTAB_VUN
, 0, NULL
, "DISCONNECT",
323 &tmxr_dscln
, NULL
, &mux_desc
},
324 { MTAB_XTD
|MTAB_VUN
|MTAB_NC
, 0, "LOG", "LOG",
325 &tmxr_set_log
, &tmxr_show_log
, &mux_desc
},
326 { MTAB_XTD
|MTAB_VUN
|MTAB_NC
, 0, NULL
, "NOLOG",
327 &tmxr_set_nolog
, NULL
, &mux_desc
},
328 { MTAB_XTD
|MTAB_VDV
, 1, "DEVNO", "DEVNO",
329 &hp_setdev
, &hp_showdev
, &muxl_dev
},
334 { FLDATA (CMD
, muxl_dib
.cmd
, 0), REG_HRO
},
335 { FLDATA (CTL
, muxl_dib
.ctl
, 0) },
336 { FLDATA (FLG
, muxl_dib
.flg
, 0) },
337 { FLDATA (FBF
, muxl_dib
.fbf
, 0) },
338 { FLDATA (SRQ
, muxl_dib
.srq
, 0) },
339 { BRDATA (STA
, mux_sta
, 8, 16, MUX_LINES
+ MUX_ILINES
) },
340 { BRDATA (RPAR
, mux_rpar
, 8, 16, MUX_LINES
+ MUX_ILINES
) },
341 { BRDATA (XPAR
, mux_xpar
, 8, 16, MUX_LINES
) },
342 { BRDATA (RBUF
, mux_rbuf
, 8, 16, MUX_LINES
+ MUX_ILINES
) },
343 { BRDATA (XBUF
, mux_xbuf
, 8, 16, MUX_LINES
) },
344 { BRDATA (RCHP
, mux_rchp
, 8, 1, MUX_LINES
+ MUX_ILINES
) },
345 { BRDATA (XDON
, mux_xdon
, 8, 1, MUX_LINES
) },
346 { URDATA (TIME
, muxl_unit
[0].wait
, 10, 24, 0,
347 MUX_LINES
, REG_NZ
+ PV_LEFT
) },
348 { ORDATA (DEVNO
, muxl_dib
.devno
, 6), REG_HRO
},
353 "MUXL", muxl_unit
, muxl_reg
, muxl_mod
,
354 MUX_LINES
, 10, 31, 1, 8, 8,
355 NULL
, NULL
, &muxc_reset
,
357 &muxl_dib
, DEV_DISABLE
360 /* MUXM data structures
362 muxc_dev MUXM device descriptor
363 muxc_unit MUXM unit descriptor
364 muxc_reg MUXM register list
365 muxc_mod MUXM modifiers list
368 DIB muxc_dib
= { MUXC
, 0, 0, 0, 0, 0, &muxcio
};
370 UNIT muxc_unit
= { UDATA (NULL
, 0, 0) };
373 { FLDATA (CMD
, muxc_dib
.cmd
, 0), REG_HRO
},
374 { FLDATA (CTL
, muxc_dib
.ctl
, 0) },
375 { FLDATA (FLG
, muxc_dib
.flg
, 0) },
376 { FLDATA (FBF
, muxc_dib
.fbf
, 0) },
377 { FLDATA (SRQ
, muxc_dib
.srq
, 0) },
378 { FLDATA (SCAN
, muxc_scan
, 0) },
379 { ORDATA (CHAN
, muxc_chan
, 4) },
380 { BRDATA (DSO
, muxc_ota
, 8, 6, MUX_LINES
) },
381 { BRDATA (DSI
, muxc_lia
, 8, 2, MUX_LINES
) },
382 { ORDATA (DEVNO
, muxc_dib
.devno
, 6), REG_HRO
},
387 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO",
388 &hp_setdev
, &hp_showdev
, &muxc_dev
},
393 "MUXM", &muxc_unit
, muxc_reg
, muxc_mod
,
395 NULL
, NULL
, &muxc_reset
,
397 &muxc_dib
, DEV_DISABLE
400 /* I/O instructions: data cards
402 Implementation note: the operating manual says that "at least 100
403 milliseconds of CLC 0s must be programmed" by systems employing the
404 multiplexer to ensure that the multiplexer resets. In practice, such systems
405 issue 128K CLC 0 instructions. As we provide debug logging of multiplexer
406 resets, a CRS counter is used to ensure that only one debug line is printed
407 in response to these 128K CRS invocations.
410 int32
muxlio (int32 inst
, int32 IR
, int32 dat
)
414 static uint32 crs_count
= 0; /* cntr for crs repeat */
416 dev
= IR
& I_DEVMASK
; /* get device no */
419 switch (inst
) { /* case on opcode */
421 case ioFLG
: /* flag clear/set */
422 if ((IR
& I_HC
) == 0) { setFSR (dev
); } /* STF */
425 case ioSFC
: /* skip flag clear */
426 if (FLG (dev
) == 0) PC
= (PC
+ 1) & VAMASK
;
429 case ioSFS
: /* skip flag set */
430 if (FLG (dev
) != 0) PC
= (PC
+ 1) & VAMASK
;
433 case ioOTX
: /* output */
434 muxl_obuf
= dat
; /* store data */
436 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
438 fprintf (sim_deb
, ">>MUXl OTx: Parameter = %06o\n", dat
);
440 fprintf (sim_deb
, ">>MUXl OTx: Data = %06o\n", dat
);
443 case ioLIX
: /* load */
446 case ioMIX
: /* merge */
447 dat
= dat
| muxl_ibuf
;
449 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
450 fprintf (sim_deb
, ">>MUXl LIx: Data = %06o\n", dat
);
453 case ioCRS
: /* control reset */
456 if (crs_count
) /* already reset? */
457 break; /* skip redundant clear */
459 for (ln
= 0; ln
< MUX_LINES
; ln
++) { /* clear transmit info */
460 mux_xbuf
[ln
] = mux_xpar
[ln
] = 0;
461 muxc_ota
[ln
] = muxc_lia
[ln
] = mux_xdon
[ln
] = 0;
464 for (ln
= 0; ln
< (MUX_LINES
+ MUX_ILINES
); ln
++) {
465 mux_rbuf
[ln
] = mux_rpar
[ln
] = 0; /* clear receive info */
466 mux_sta
[ln
] = mux_rchp
[ln
] = 0;
467 } /* fall into CLC SC */
469 case ioCTL
: /* control clear/set */
470 if (IR
& I_CTL
) { /* CLC */
473 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
474 fprintf (sim_deb
, ">>MUXl CLC: Data interrupt inhibited\n");
477 setCTL (dev
); /* set ctl */
478 ln
= MUX_CHAN (muxu_obuf
); /* get chan # */
480 if (muxl_obuf
& OTL_TX
) { /* transmit? */
481 if (ln
< MUX_LINES
) { /* line valid? */
482 if (muxl_obuf
& OTL_P
) { /* parameter? */
483 mux_xpar
[ln
] = muxl_obuf
; /* store param value */
484 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
486 ">>MUXl STC: Transmit channel %d parameter %06o stored\n",
491 if (mux_xpar
[ln
] & OTL_TPAR
) /* parity requested? */
492 muxl_obuf
= /* add parity bit */
493 muxl_obuf
& ~OTL_PAR
|
495 mux_xbuf
[ln
] = muxl_obuf
; /* load buffer */
497 if (sim_is_active (&muxl_unit
[ln
])) { /* still working? */
498 mux_sta
[ln
] = mux_sta
[ln
] | LIU_LOST
; /* char lost */
499 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
501 ">>MUXl STC: Transmit channel %d data overrun\n", ln
);
504 if (muxu_unit
.flags
& UNIT_DIAG
) /* loopback? */
505 mux_ldsc
[ln
].conn
= 1; /* connect this line */
506 sim_activate (&muxl_unit
[ln
], muxl_unit
[ln
].wait
);
507 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
509 ">>MUXl STC: Transmit channel %d data %06o scheduled\n",
514 else if (DEBUG_PRI (muxu_dev
, DEB_CMDS
)) /* line invalid */
515 fprintf (sim_deb
, ">>MUXl STC: Transmit channel %d invalid\n", ln
);
519 if (ln
< (MUX_LINES
+ MUX_ILINES
)) { /* line valid? */
520 if (muxl_obuf
& OTL_P
) { /* parameter? */
521 mux_rpar
[ln
] = muxl_obuf
; /* store param value */
522 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
524 ">>MUXl STC: Receive channel %d parameter %06o stored\n",
528 else if (DEBUG_PRI (muxu_dev
, DEB_CMDS
)) /* data (invalid action) */
530 ">>MUXl STC: Receive channel %d parameter %06o invalid action\n",
534 else if (DEBUG_PRI (muxu_dev
, DEB_CMDS
)) /* line invalid */
535 fprintf (sim_deb
, ">>MUXl STC: Receive channel %d invalid\n", ln
);
543 if (is_crs
) /* control reset? */
544 crs_count
= crs_count
+ 1; /* increment count */
546 else if (crs_count
) { /* something else */
547 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
)) /* report reset count */
549 ">>MUXl CRS: Multiplexer reset %d times\n", crs_count
);
550 crs_count
= 0; /* clear counter */
553 if (IR
& I_HC
) { /* H/C option */
554 clrFSR (dev
); /* clear flag */
555 mux_data_int (); /* look for new int */
560 int32
muxuio (int32 inst
, int32 IR
, int32 dat
)
562 switch (inst
) { /* case on opcode */
564 case ioOTX
: /* output */
565 muxu_obuf
= dat
; /* store data */
567 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
568 fprintf (sim_deb
, ">>MUXu OTx: Data channel = %d\n", MUX_CHAN(dat
));
571 case ioLIX
: /* load */
574 case ioMIX
: /* merge */
575 dat
= dat
| muxu_ibuf
;
577 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
578 fprintf (sim_deb
, ">>MUXu LIx: Status = %06o, channel = %d\n", dat
, MUX_CHAN(dat
));
588 /* I/O instructions: control card
590 In diagnostic mode, the control signals C1 and C2 are looped back to status
591 signals S1 and S2. Changing the control signals may cause an interrupt, so a
592 test is performed after OTx processing.
595 int32
muxcio (int32 inst
, int32 IR
, int32 dat
)
597 int32 dev
, ln
, t
, old
;
599 dev
= IR
& I_DEVMASK
; /* get device no */
600 switch (inst
) { /* case on opcode */
602 case ioFLG
: /* flag clear/set */
603 if ((IR
& I_HC
) == 0) { setFSR (dev
); } /* STF */
606 case ioSFC
: /* skip flag clear */
607 if (FLG (dev
) == 0) PC
= (PC
+ 1) & VAMASK
;
610 case ioSFS
: /* skip flag set */
611 if (FLG (dev
) != 0) PC
= (PC
+ 1) & VAMASK
;
614 case ioOTX
: /* output */
615 ln
= muxc_chan
= OTC_CHAN (dat
); /* set channel */
617 if (dat
& OTC_SCAN
) muxc_scan
= 1; /* set scan flag */
620 if (dat
& OTC_UPD
) { /* update? */
621 old
= muxc_ota
[ln
]; /* save prior val */
622 muxc_ota
[ln
] = /* save ESn,SSn */
623 (muxc_ota
[ln
] & ~OTC_RW
) | (dat
& OTC_RW
);
625 if (dat
& OTC_EC2
) /* if EC2, upd C2 */
627 (muxc_ota
[ln
] & ~OTC_C2
) | (dat
& OTC_C2
);
629 if (dat
& OTC_EC1
) /* if EC1, upd C1 */
631 (muxc_ota
[ln
] & ~OTC_C1
) | (dat
& OTC_C1
);
633 if (muxu_unit
.flags
& UNIT_DIAG
) /* loopback? */
634 muxc_lia
[ln
^ 1] = /* set S1, S2 to C1, C2 */
635 (muxc_lia
[ln
^ 1] & ~(LIC_S2
| LIC_S1
)) |
636 (muxc_ota
[ln
] & (OTC_C1
| OTC_C2
)) >> OTC_V_C
;
638 else if ((muxl_unit
[ln
].flags
& UNIT_MDM
) && /* modem ctrl? */
639 (old
& DTR
) && /* DTR drop? */
640 !(muxc_ota
[ln
] & DTR
)) {
641 tmxr_linemsg (&mux_ldsc
[ln
], "\r\nLine hangup\r\n");
642 tmxr_reset_ln (&mux_ldsc
[ln
]); /* reset line */
643 muxc_lia
[ln
] = 0; /* dataset off */
647 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
648 fprintf (sim_deb
, ">>MUXc OTx: Parameter = %06o, channel = %d\n",
651 if ((muxu_unit
.flags
& UNIT_DIAG
) && /* loopback? */
652 (!FLG(muxc_dib
.devno
))) /* flag clear? */
653 mux_ctrl_int (); /* status chg may interrupt */
656 case ioLIX
: /* load */
659 case ioMIX
: /* merge */
660 t
= LIC_MBO
| PUT_CCH (muxc_chan
) | /* mbo, chan num */
661 LIC_TSTI (muxc_chan
) | /* I2, I1 */
662 (muxc_ota
[muxc_chan
] & (OTC_ES2
| OTC_ES1
)) | /* ES2, ES1 */
663 (muxc_lia
[muxc_chan
] & (LIC_S2
| LIC_S1
)); /* S2, S1 */
664 dat
= dat
| t
; /* return status */
666 if (DEBUG_PRI (muxu_dev
, DEB_CPU
))
667 fprintf (sim_deb
, ">>MUXc LIx: Status = %06o, channel = %d\n",
670 muxc_chan
= (muxc_chan
+ 1) & LIC_M_CHAN
; /* incr channel */
673 case ioCRS
: /* control reset */
674 case ioCTL
: /* ctrl clear/set */
675 if (IR
& I_CTL
) { clrCTL (dev
); } /* CLC */
676 else { setCTL (dev
); } /* STC */
683 if (IR
& I_HC
) { /* H/C option */
684 clrFSR (dev
); /* clear flag */
685 mux_ctrl_int (); /* look for new int */
690 /* Unit service - receive side
692 Poll for new connections
693 Poll all active lines for input
696 t_stat
muxi_svc (UNIT
*uptr
)
701 loopback
= ((muxu_unit
.flags
& UNIT_DIAG
) != 0); /* diagnostic mode? */
703 if (!loopback
) { /* terminal mode? */
704 if ((uptr
->flags
& UNIT_ATT
) == 0) return SCPE_OK
; /* attached? */
705 muxu_unit
.wait
= sync_poll (SERVICE
); /* synchronize poll */
706 sim_activate (uptr
, muxu_unit
.wait
); /* continue poll */
707 ln
= tmxr_poll_conn (&mux_desc
); /* look for connect */
708 if (ln
>= 0) { /* got one? */
709 if ((muxl_unit
[ln
].flags
& UNIT_MDM
) && /* modem ctrl? */
710 (muxc_ota
[ln
] & DTR
)) /* DTR? */
711 muxc_lia
[ln
] = muxc_lia
[ln
] | CDET
; /* set cdet */
712 muxc_lia
[ln
] = muxc_lia
[ln
] | DSR
; /* set dsr */
713 mux_ldsc
[ln
].rcve
= 1; /* rcv enabled */
715 tmxr_poll_rx (&mux_desc
); /* poll for input */
718 for (ln
= 0; ln
< MUX_LINES
; ln
++) { /* loop thru lines */
719 if (mux_ldsc
[ln
].conn
) { /* connected? */
720 if (loopback
) { /* diagnostic mode? */
721 c
= mux_xbuf
[ln
^ 1] & OTL_CHAR
; /* get char from xmit line */
722 if (c
== 0) /* all char bits = 0? */
723 c
= c
| SCPE_BREAK
; /* set break flag */
724 mux_ldsc
[ln
].conn
= 0; /* clear connection */
728 c
= tmxr_getc_ln (&mux_ldsc
[ln
]); /* get char from Telnet */
730 if (c
) { /* valid char? */
731 if (c
& SCPE_BREAK
) { /* break? */
732 mux_sta
[ln
] = mux_sta
[ln
] | LIU_BRK
;
733 mux_rbuf
[ln
] = 0; /* no char */
736 if (mux_rchp
[ln
]) /* char already pending? */
737 mux_sta
[ln
] = mux_sta
[ln
] | LIU_LOST
;
739 if (!loopback
) { /* terminal mode? */
740 c
= sim_tt_inpcvt (c
, TT_GET_MODE (muxl_unit
[ln
].flags
));
741 if (mux_rpar
[ln
] & OTL_ECHO
) { /* echo? */
742 TMLN
*lp
= &mux_ldsc
[ln
]; /* get line */
743 tmxr_putc_ln (lp
, c
); /* output char */
744 tmxr_poll_tx (&mux_desc
); /* poll xmt */
747 mux_rbuf
[ln
] = c
; /* save char */
750 mux_rchp
[ln
] = 1; /* char pending */
752 if (DEBUG_PRI (muxu_dev
, DEB_XFER
))
753 fprintf (sim_deb
, ">>MUXi svc: Line %d character %06o received\n",
756 if (mux_rpar
[ln
] & OTL_DIAG
) mux_diag (c
); /* rcv diag? */
758 } /* end if connected */
760 else /* not connected */
761 if (!loopback
) /* terminal mode? */
762 muxc_lia
[ln
] = 0; /* line disconnected */
764 if (!FLG (muxl_dib
.devno
)) mux_data_int (); /* scan for data int */
765 if (!FLG (muxc_dib
.devno
)) mux_ctrl_int (); /* scan modem */
769 /* Unit service - transmit side */
771 t_stat
muxo_svc (UNIT
*uptr
)
773 int32 c
, fc
, ln
, altln
;
776 ln
= uptr
- muxl_unit
; /* line # */
777 altln
= ln
^ 1; /* alt. line for diag mode */
779 fc
= mux_xbuf
[ln
] & OTL_CHAR
; /* full character data */
780 c
= fc
& 0377; /* Telnet character data */
782 loopback
= ((muxu_unit
.flags
& UNIT_DIAG
) != 0); /* diagnostic mode? */
784 if (mux_ldsc
[ln
].conn
) { /* connected? */
785 if (mux_ldsc
[ln
].xmte
) { /* xmt enabled? */
786 if (loopback
) /* diagnostic mode? */
787 mux_ldsc
[ln
].conn
= 0; /* clear connection */
789 if ((mux_xbuf
[ln
] & OTL_SYNC
) == 0) { /* start bit 0? */
790 TMLN
*lp
= &mux_ldsc
[ln
]; /* get line */
791 c
= sim_tt_outcvt (c
, TT_GET_MODE (muxl_unit
[ln
].flags
));
793 if (mux_xpar
[ln
] & OTL_DIAG
) /* xmt diagnose? */
794 mux_diag (fc
); /* before munge */
796 if (loopback
) { /* diagnostic mode? */
797 mux_ldsc
[altln
].conn
= 1; /* set recv connection */
798 sim_activate (&muxu_unit
, 1); /* schedule receive */
801 else { /* no loopback */
802 if (c
>= 0) /* valid? */
803 tmxr_putc_ln (lp
, c
); /* output char */
804 tmxr_poll_tx (&mux_desc
); /* poll xmt */
808 mux_xdon
[ln
] = 1; /* set for xmit irq */
810 if (DEBUG_PRI (muxu_dev
, DEB_XFER
) && (loopback
| (c
>= 0)))
811 fprintf (sim_deb
, ">>MUXo svc: Line %d character %06o sent\n",
812 ln
, (loopback
? fc
: c
));
815 else { /* buf full */
816 tmxr_poll_tx (&mux_desc
); /* poll xmt */
817 sim_activate (uptr
, muxl_unit
[ln
].wait
); /* wait */
822 if (!FLG (muxl_dib
.devno
)) mux_data_int (); /* scan for int */
826 /* Look for data interrupt */
828 void mux_data_int (void)
832 for (i
= 0; i
< MUX_LINES
; i
++) { /* rcv lines */
833 if ((mux_rpar
[i
] & OTL_ENB
) && mux_rchp
[i
]) { /* enabled, char? */
834 muxl_ibuf
= PUT_DCH (i
) | /* lo buf = char */
835 mux_rbuf
[i
] & LIL_CHAR
|
836 RCV_PAR (mux_rbuf
[i
]);
837 muxu_ibuf
= PUT_DCH (i
) | mux_sta
[i
]; /* hi buf = stat */
838 mux_rchp
[i
] = 0; /* clr char, stat */
841 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
842 fprintf (sim_deb
, ">>MUXd irq: Receive channel %d interrupt requested\n", i
);
844 setFSR (muxl_dib
.devno
); /* interrupt */
848 for (i
= 0; i
< MUX_LINES
; i
++) { /* xmt lines */
849 if ((mux_xpar
[i
] & OTL_ENB
) && mux_xdon
[i
]) { /* enabled, done? */
850 muxl_ibuf
= PUT_DCH (i
) | /* lo buf = last rcv char */
851 mux_rbuf
[i
] & LIL_CHAR
|
852 RCV_PAR (mux_rbuf
[i
]);
853 muxu_ibuf
= PUT_DCH (i
) | mux_sta
[i
] | LIU_TR
; /* hi buf = stat */
854 mux_xdon
[i
] = 0; /* clr done, stat */
857 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
858 fprintf (sim_deb
, ">>MUXd irq: Transmit channel %d interrupt requested\n", i
);
860 setFSR (muxl_dib
.devno
); /* interrupt */
864 for (i
= MUX_LINES
; i
< (MUX_LINES
+ MUX_ILINES
); i
++) { /* diag lines */
865 if ((mux_rpar
[i
] & OTL_ENB
) && mux_rchp
[i
]) { /* enabled, char? */
866 muxl_ibuf
= PUT_DCH (i
) | /* lo buf = char */
867 mux_rbuf
[i
] & LIL_CHAR
|
868 RCV_PAR (mux_rbuf
[i
]);
869 muxu_ibuf
= PUT_DCH (i
) | mux_sta
[i
] | LIU_DG
; /* hi buf = stat */
870 mux_rchp
[i
] = 0; /* clr char, stat */
873 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
874 fprintf (sim_deb
, ">>MUXd irq: Receive channel %d interrupt requested\n", i
);
876 setFSR (muxl_dib
.devno
);
883 /* Look for control interrupt
885 If either of the incoming status bits does not match the stored status, and
886 the corresponding mismatch is enabled, a control interrupt request is
887 generated. Depending on the scan flag, we check either all 16 lines or just
888 the current line. If an interrupt is requested, the channel counter
889 indicates the interrupting channel.
892 void mux_ctrl_int (void)
896 line_count
= (muxc_scan
? MUX_LINES
: 1); /* check one or all lines */
898 for (i
= 0; i
< line_count
; i
++) {
899 if (muxc_scan
) /* scanning? */
900 muxc_chan
= (muxc_chan
+ 1) & LIC_M_CHAN
; /* step channel */
901 if (LIC_TSTI (muxc_chan
)) { /* status change? */
903 if (DEBUG_PRI (muxu_dev
, DEB_CMDS
))
905 ">>MUXc irq: Control channel %d interrupt requested (poll = %d)\n",
908 setFSR (muxc_dib
.devno
); /* set flag */
915 /* Set diagnostic lines for given character */
917 void mux_diag (int32 c
)
921 for (i
= MUX_LINES
; i
< (MUX_LINES
+ MUX_ILINES
); i
++) {
922 if (c
& SCPE_BREAK
) { /* break? */
923 mux_sta
[i
] = mux_sta
[i
] | LIU_BRK
;
924 mux_rbuf
[i
] = 0; /* no char */
927 if (mux_rchp
[i
]) mux_sta
[i
] = mux_sta
[i
] | LIU_LOST
;
935 /* Reset an individual line */
937 void mux_reset_ln (int32 i
)
939 mux_rbuf
[i
] = mux_xbuf
[i
] = 0; /* clear state */
940 mux_rpar
[i
] = mux_xpar
[i
] = 0;
941 mux_rchp
[i
] = mux_xdon
[i
] = 0;
943 muxc_ota
[i
] = muxc_lia
[i
] = 0; /* clear modem */
944 if (mux_ldsc
[i
].conn
&& /* connected? */
945 ((muxu_unit
.flags
& UNIT_DIAG
) == 0)) /* term mode? */
946 muxc_lia
[i
] = muxc_lia
[i
] | DSR
| /* cdet, dsr */
947 (muxl_unit
[i
].flags
& UNIT_MDM
? CDET
: 0);
948 sim_cancel (&muxl_unit
[i
]);
954 t_stat
muxc_reset (DEVICE
*dptr
)
958 if (dptr
== &muxc_dev
) { /* make all consistent */
959 hp_enbdis_pair (dptr
, &muxl_dev
);
960 hp_enbdis_pair (dptr
, &muxu_dev
);
962 else if (dptr
== &muxl_dev
) {
963 hp_enbdis_pair (dptr
, &muxc_dev
);
964 hp_enbdis_pair (dptr
, &muxu_dev
);
967 hp_enbdis_pair (dptr
, &muxc_dev
);
968 hp_enbdis_pair (dptr
, &muxl_dev
);
970 muxl_dib
.cmd
= muxl_dib
.ctl
= 0; /* init lower */
971 muxl_dib
.flg
= muxl_dib
.fbf
= muxl_dib
.srq
= 1;
972 muxu_dib
.cmd
= muxu_dib
.ctl
= 0; /* upper not */
973 muxu_dib
.flg
= muxu_dib
.fbf
= muxu_dib
.srq
= 0; /* implemented */
974 muxc_dib
.cmd
= muxc_dib
.ctl
= 0; /* init ctrl */
975 muxc_dib
.flg
= muxc_dib
.fbf
= muxc_dib
.srq
= 1;
976 muxc_chan
= muxc_scan
= 0; /* init modem scan */
977 if (muxu_unit
.flags
& UNIT_ATT
) { /* master att? */
978 if (!sim_is_active (&muxu_unit
)) {
979 muxu_unit
.wait
= sync_poll (INITIAL
); /* synchronize poll */
980 sim_activate (&muxu_unit
, muxu_unit
.wait
); /* activate */
983 else sim_cancel (&muxu_unit
); /* else stop */
984 for (i
= 0; i
< MUX_LINES
; i
++) mux_reset_ln (i
); /* reset lines 0-15 */
985 for (i
= MUX_LINES
; i
< (MUX_LINES
+ MUX_ILINES
); i
++) /* reset lines 16-20 */
986 mux_rbuf
[i
] = mux_rpar
[i
] = mux_sta
[i
] = mux_rchp
[i
] = 0;
990 /* Attach master unit */
992 t_stat
mux_attach (UNIT
*uptr
, char *cptr
)
996 if (muxu_unit
.flags
& UNIT_DIAG
) /* diag mode? */
997 return SCPE_NOFNC
; /* command not allowed */
999 r
= tmxr_attach (&mux_desc
, uptr
, cptr
); /* attach */
1000 if (r
!= SCPE_OK
) return r
; /* error */
1001 muxu_unit
.wait
= sync_poll (INITIAL
); /* synchronize poll */
1002 sim_activate (uptr
, muxu_unit
.wait
); /* start poll */
1006 /* Detach master unit */
1008 t_stat
mux_detach (UNIT
*uptr
)
1013 r
= tmxr_detach (&mux_desc
, uptr
); /* detach */
1014 for (i
= 0; i
< MUX_LINES
; i
++) mux_ldsc
[i
].rcve
= 0; /* disable rcv */
1015 sim_cancel (uptr
); /* stop poll */
1019 /* Diagnostic/normal mode routine
1021 Diagnostic testing wants to exercise as much of the regular simulation code
1022 as possible to ensure good test coverage. Normally, input polling and output
1023 transmission only occurs on connected lines. In diagnostic mode, line
1024 connection flags are set selectively to enable processing on the lines under
1025 test. The alternative to this would require duplicating the send/receive
1026 code; the diagnostic would then test the copy but not the actual code used
1027 for normal character transfers, which is undesirable.
1029 Therefore, to enable diagnostic mode, we must force a disconnect of the
1030 master socket and any connected Telnet lines, which clears the connection
1031 flags on all lines. Then we set the "transmission enabled" flags on all
1032 lines to enable output character processing for the diagnostic. (Normally,
1033 all of the flags are set when the multiplexer is first attached. Until then,
1034 the enable flags default to "not enabled," so we enable them explicitly
1038 t_stat
mux_setdiag (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
1042 if (val
) { /* set diag? */
1043 mux_detach (uptr
); /* detach lines */
1044 for (ln
= 0; ln
< MUX_LINES
; ln
++) /* enable transmission */
1045 mux_ldsc
[ln
].xmte
= 1; /* on all lines */
1047 else { /* set term */
1048 for (ln
= 0; ln
< MUX_LINES
; ln
++) /* clear connections */
1049 mux_ldsc
[ln
].conn
= 0; /* on all lines */
1054 /* Show summary processor */
1056 t_stat
mux_summ (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1060 if (muxu_unit
.flags
& UNIT_DIAG
) /* diag mode? */
1061 return SCPE_NOFNC
; /* command not allowed */
1063 for (i
= t
= 0; i
< MUX_LINES
; i
++) t
= t
+ (mux_ldsc
[i
].conn
!= 0);
1064 if (t
== 1) fprintf (st
, "1 connection");
1065 else fprintf (st
, "%d connections", t
);
1069 /* SHOW CONN/STAT processor */
1071 t_stat
mux_show (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
1075 if (muxu_unit
.flags
& UNIT_DIAG
) /* diag mode? */
1076 return SCPE_NOFNC
; /* command not allowed */
1078 for (i
= t
= 0; i
< MUX_LINES
; i
++) t
= t
+ (mux_ldsc
[i
].conn
!= 0);
1080 for (i
= 0; i
< MUX_LINES
; i
++) {
1081 if (mux_ldsc
[i
].conn
) {
1082 if (val
) tmxr_fconns (st
, &mux_ldsc
[i
], i
);
1083 else tmxr_fstats (st
, &mux_ldsc
[i
], i
);
1087 else fprintf (st
, "all disconnected\n");