First Commit of my working state
[simh.git] / PDP11 / pdp11_dz.c
CommitLineData
196ba1fc
PH
1/* pdp11_dz.c: DZ11 terminal multiplexor simulator\r
2\r
3 Copyright (c) 2001-2007, 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 dz DZ11 terminal multiplexor\r
27\r
28 18-Jun-07 RMS Added UNIT_IDLE flag\r
29 29-Oct-06 RMS Synced poll and clock\r
30 22-Nov-05 RMS Revised for new terminal processing routines\r
31 07-Jul-05 RMS Removed extraneous externs\r
32 15-Jun-05 RMS Revised for new autoconfigure interface\r
33 04-Apr-04 RMS Added per-line logging\r
34 05-Jan-04 RMS Revised for tmxr library changes\r
35 19-May-03 RMS Revised for new conditional compilation scheme\r
36 09-May-03 RMS Added network device flag\r
37 22-Dec-02 RMS Added break (framing error) support\r
38 31-Oct-02 RMS Added 8b support\r
39 12-Oct-02 RMS Added autoconfigure support\r
40 29-Sep-02 RMS Fixed bug in set number of lines routine\r
41 Added variable vector support\r
42 New data structures\r
43 22-Apr-02 RMS Updated for changes in sim_tmxr\r
44 28-Apr-02 RMS Fixed interrupt acknowledge, fixed SHOW DZ ADDRESS\r
45 14-Jan-02 RMS Added multiboard support\r
46 30-Dec-01 RMS Added show statistics, set disconnect\r
47 Removed statistics registers\r
48 03-Dec-01 RMS Modified for extended SET/SHOW\r
49 09-Nov-01 RMS Added VAX support\r
50 20-Oct-01 RMS Moved getchar from sim_tmxr, changed interrupt\r
51 logic to use tmxr_rqln\r
52 06-Oct-01 RMS Fixed bug in carrier detect logic\r
53 03-Oct-01 RMS Added support for BSD-style "ringless" modems\r
54 27-Sep-01 RMS Fixed bug in xmte initialization\r
55 17-Sep-01 RMS Added separate autodisconnect switch\r
56 16-Sep-01 RMS Fixed modem control bit offsets\r
57*/\r
58\r
59#if defined (VM_PDP10) /* PDP10 version */\r
60#include "pdp10_defs.h"\r
61#define RANK_DZ 0 /* no autoconfig */\r
62#define DZ_8B_DFLT 0\r
63extern int32 int_req;\r
64\r
65#elif defined (VM_VAX) /* VAX version */\r
66#include "vax_defs.h"\r
67#define DZ_8B_DFLT TT_MODE_8B\r
68extern int32 int_req[IPL_HLVL];\r
69\r
70#else /* PDP-11 version */\r
71#include "pdp11_defs.h"\r
72#define DZ_8B_DFLT TT_MODE_8B\r
73extern int32 int_req[IPL_HLVL];\r
74#endif\r
75\r
76#include "sim_sock.h"\r
77#include "sim_tmxr.h"\r
78\r
79#if !defined (DZ_MUXES)\r
80#define DZ_MUXES 1\r
81#endif\r
82#if !defined (DZ_LINES)\r
83#define DZ_LINES 8\r
84#endif\r
85\r
86#define DZ_MNOMASK (DZ_MUXES - 1) /* mask for mux no */\r
87#define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */\r
88#define DZ_LMASK ((1 << DZ_LINES) - 1) /* mask of lines */\r
89#define DZ_SILO_ALM 16 /* silo alarm level */\r
90\r
91/* DZCSR - 160100 - control/status register */\r
92\r
93#define CSR_MAINT 0000010 /* maint - NI */\r
94#define CSR_CLR 0000020 /* clear */\r
95#define CSR_MSE 0000040 /* master scan enb */\r
96#define CSR_RIE 0000100 /* rcv int enb */\r
97#define CSR_RDONE 0000200 /* rcv done - RO */\r
98#define CSR_V_TLINE 8 /* xmit line - RO */\r
99#define CSR_TLINE (DZ_LNOMASK << CSR_V_TLINE)\r
100#define CSR_SAE 0010000 /* silo alm enb */\r
101#define CSR_SA 0020000 /* silo alm - RO */\r
102#define CSR_TIE 0040000 /* xmit int enb */\r
103#define CSR_TRDY 0100000 /* xmit rdy - RO */\r
104#define CSR_RW (CSR_MSE | CSR_RIE | CSR_SAE | CSR_TIE)\r
105#define CSR_MBZ (0004003 | CSR_CLR | CSR_MAINT)\r
106\r
107#define CSR_GETTL(x) (((x) >> CSR_V_TLINE) & DZ_LNOMASK)\r
108#define CSR_PUTTL(x,y) x = ((x) & ~CSR_TLINE) | (((y) & DZ_LNOMASK) << CSR_V_TLINE)\r
109\r
110/* DZRBUF - 160102 - receive buffer, read only */\r
111\r
112#define RBUF_CHAR 0000377 /* rcv char */\r
113#define RBUF_V_RLINE 8 /* rcv line */\r
114#define RBUF_PARE 0010000 /* parity err - NI */\r
115#define RBUF_FRME 0020000 /* frame err */\r
116#define RBUF_OVRE 0040000 /* overrun err - NI */\r
117#define RBUF_VALID 0100000 /* rcv valid */\r
118#define RBUF_MBZ 0004000\r
119\r
120/* DZLPR - 160102 - line parameter register, write only, word access only */\r
121\r
122#define LPR_V_LINE 0 /* line */\r
123#define LPR_LPAR 0007770 /* line pars - NI */\r
124#define LPR_RCVE 0010000 /* receive enb */\r
125#define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LNOMASK)\r
126\r
127/* DZTCR - 160104 - transmission control register */\r
128\r
129#define TCR_V_XMTE 0 /* xmit enables */\r
130#define TCR_V_DTR 8 /* DTRs */\r
131\r
132/* DZMSR - 160106 - modem status register, read only */\r
133\r
134#define MSR_V_RI 0 /* ring indicators */\r
135#define MSR_V_CD 8 /* carrier detect */\r
136\r
137/* DZTDR - 160106 - transmit data, write only */\r
138\r
139#define TDR_CHAR 0000377 /* xmit char */\r
140#define TDR_V_TBR 8 /* xmit break - NI */\r
141\r
142extern int32 IREQ (HLVL);\r
143extern int32 sim_switches;\r
144extern FILE *sim_log;\r
145extern int32 tmxr_poll; /* calibrated delay */\r
146\r
147uint16 dz_csr[DZ_MUXES] = { 0 }; /* csr */\r
148uint16 dz_rbuf[DZ_MUXES] = { 0 }; /* rcv buffer */\r
149uint16 dz_lpr[DZ_MUXES] = { 0 }; /* line param */\r
150uint16 dz_tcr[DZ_MUXES] = { 0 }; /* xmit control */\r
151uint16 dz_msr[DZ_MUXES] = { 0 }; /* modem status */\r
152uint16 dz_tdr[DZ_MUXES] = { 0 }; /* xmit data */\r
153uint8 dz_sae[DZ_MUXES] = { 0 }; /* silo alarm enabled */\r
154uint32 dz_rxi = 0; /* rcv interrupts */\r
155uint32 dz_txi = 0; /* xmt interrupts */\r
156int32 dz_mctl = 0; /* modem ctrl enabled */\r
157int32 dz_auto = 0; /* autodiscon enabled */\r
158TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */\r
159TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */\r
160\r
161DEVICE dz_dev;\r
162t_stat dz_rd (int32 *data, int32 PA, int32 access);\r
163t_stat dz_wr (int32 data, int32 PA, int32 access);\r
164int32 dz_rxinta (void);\r
165int32 dz_txinta (void);\r
166t_stat dz_svc (UNIT *uptr);\r
167t_stat dz_reset (DEVICE *dptr);\r
168t_stat dz_attach (UNIT *uptr, char *cptr);\r
169t_stat dz_detach (UNIT *uptr);\r
170t_stat dz_clear (int32 dz, t_bool flag);\r
171int32 dz_getc (int32 dz);\r
172void dz_update_rcvi (void);\r
173void dz_update_xmti (void);\r
174void dz_clr_rxint (int32 dz);\r
175void dz_set_rxint (int32 dz);\r
176void dz_clr_txint (int32 dz);\r
177void dz_set_txint (int32 dz);\r
178t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc);\r
179t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r
180t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);\r
181t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc);\r
182t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc);\r
183t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc);\r
184t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc);\r
185\r
186/* DZ data structures\r
187\r
188 dz_dev DZ device descriptor\r
189 dz_unit DZ unit list\r
190 dz_reg DZ register list\r
191*/\r
192\r
193DIB dz_dib = {\r
194 IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr,\r
195 2, IVCL (DZRX), VEC_DZRX, { &dz_rxinta, &dz_txinta }\r
196 };\r
197\r
198UNIT dz_unit = { UDATA (&dz_svc, UNIT_IDLE|UNIT_ATTABLE|DZ_8B_DFLT, 0) };\r
199\r
200REG dz_nlreg = { DRDATA (NLINES, dz_desc.lines, 6), PV_LEFT };\r
201\r
202REG dz_reg[] = {\r
203 { BRDATA (CSR, dz_csr, DEV_RDX, 16, DZ_MUXES) },\r
204 { BRDATA (RBUF, dz_rbuf, DEV_RDX, 16, DZ_MUXES) },\r
205 { BRDATA (LPR, dz_lpr, DEV_RDX, 16, DZ_MUXES) },\r
206 { BRDATA (TCR, dz_tcr, DEV_RDX, 16, DZ_MUXES) },\r
207 { BRDATA (MSR, dz_msr, DEV_RDX, 16, DZ_MUXES) },\r
208 { BRDATA (TDR, dz_tdr, DEV_RDX, 16, DZ_MUXES) },\r
209 { BRDATA (SAENB, dz_sae, DEV_RDX, 1, DZ_MUXES) },\r
210 { GRDATA (RXINT, dz_rxi, DEV_RDX, DZ_MUXES, 0) },\r
211 { GRDATA (TXINT, dz_txi, DEV_RDX, DZ_MUXES, 0) },\r
212 { FLDATA (MDMCTL, dz_mctl, 0) },\r
213 { FLDATA (AUTODS, dz_auto, 0) },\r
214 { GRDATA (DEVADDR, dz_dib.ba, DEV_RDX, 32, 0), REG_HRO },\r
215 { GRDATA (DEVVEC, dz_dib.vec, DEV_RDX, 16, 0), REG_HRO },\r
216 { NULL }\r
217 };\r
218\r
219MTAB dz_mod[] = {\r
220 { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },\r
221 { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },\r
222 { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },\r
223 { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",\r
224 &tmxr_dscln, NULL, &dz_desc },\r
225 { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dz_summ },\r
226 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,\r
227 NULL, &dz_show, NULL },\r
228 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,\r
229 NULL, &dz_show, NULL },\r
230 { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS",\r
231 &set_addr, &show_addr, NULL },\r
232 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r
233 &set_vec, &dz_show_vec, NULL },\r
234#if !defined (VM_PDP10)\r
235 { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",\r
236 &set_addr_flt, NULL, NULL },\r
237#endif\r
238 { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES",\r
239 &dz_setnl, NULL, &dz_nlreg },\r
240 { MTAB_XTD | MTAB_VDV, 0, NULL, "LOG",\r
241 &dz_set_log, NULL, &dz_desc },\r
242 { MTAB_XTD | MTAB_VDV, 0, NULL, "NOLOG",\r
243 &dz_set_nolog, NULL, &dz_desc },\r
244 { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LOG", NULL,\r
245 NULL, &dz_show_log, &dz_desc },\r
246 { 0 }\r
247 };\r
248\r
249DEVICE dz_dev = {\r
250 "DZ", &dz_unit, dz_reg, dz_mod,\r
251 1, DEV_RDX, 8, 1, DEV_RDX, 8,\r
252 &tmxr_ex, &tmxr_dep, &dz_reset,\r
253 NULL, &dz_attach, &dz_detach,\r
254 &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_UBUS | DEV_QBUS\r
255 };\r
256\r
257/* IO dispatch routines, I/O addresses 177601x0 - 177601x7 */\r
258\r
259t_stat dz_rd (int32 *data, int32 PA, int32 access)\r
260{\r
261int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */\r
262\r
263switch ((PA >> 1) & 03) { /* case on PA<2:1> */\r
264\r
265 case 00: /* CSR */\r
266 *data = dz_csr[dz] = dz_csr[dz] & ~CSR_MBZ;\r
267 break;\r
268\r
269 case 01: /* RBUF */\r
270 dz_csr[dz] = dz_csr[dz] & ~CSR_SA; /* clr silo alarm */\r
271 if (dz_csr[dz] & CSR_MSE) { /* scanner on? */\r
272 dz_rbuf[dz] = dz_getc (dz); /* get top of silo */\r
273 if (!dz_rbuf[dz]) dz_sae[dz] = 1; /* empty? re-enable */\r
274 tmxr_poll_rx (&dz_desc); /* poll input */\r
275 dz_update_rcvi (); /* update rx intr */\r
276 }\r
277 else {\r
278 dz_rbuf[dz] = 0; /* no data */\r
279 dz_update_rcvi (); /* no rx intr */\r
280 }\r
281 *data = dz_rbuf[dz];\r
282 break;\r
283\r
284 case 02: /* TCR */\r
285 *data = dz_tcr[dz];\r
286 break;\r
287\r
288 case 03: /* MSR */\r
289 *data = dz_msr[dz];\r
290 break;\r
291 }\r
292\r
293return SCPE_OK;\r
294}\r
295\r
296t_stat dz_wr (int32 data, int32 PA, int32 access)\r
297{\r
298int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */\r
299int32 i, c, line;\r
300TMLN *lp;\r
301\r
302switch ((PA >> 1) & 03) { /* case on PA<2:1> */\r
303\r
304 case 00: /* CSR */\r
305 if (access == WRITEB) data = (PA & 1)? /* byte? merge */\r
306 (dz_csr[dz] & 0377) | (data << 8):\r
307 (dz_csr[dz] & ~0377) | data;\r
308 if (data & CSR_CLR) dz_clear (dz, FALSE); /* clr? reset */\r
309 if (data & CSR_MSE) /* MSE? start poll */\r
310 sim_activate (&dz_unit, clk_cosched (tmxr_poll));\r
311 else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY);\r
312 if ((data & CSR_RIE) == 0) dz_clr_rxint (dz); /* RIE = 0? */\r
313 else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */\r
314 ((dz_csr[dz] & CSR_SAE)?\r
315 (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE)))\r
316 dz_set_rxint (dz);\r
317 if ((data & CSR_TIE) == 0) dz_clr_txint (dz); /* TIE = 0? */\r
318 else if (((dz_csr[dz] & CSR_TIE) == 0) && (dz_csr[dz] & CSR_TRDY))\r
319 dz_set_txint (dz);\r
320 dz_csr[dz] = (dz_csr[dz] & ~CSR_RW) | (data & CSR_RW);\r
321 break;\r
322\r
323 case 01: /* LPR */\r
324 dz_lpr[dz] = data;\r
325 line = (dz * DZ_LINES) + LPR_GETLN (data); /* get line num */\r
326 lp = &dz_ldsc[line]; /* get line desc */\r
327 if (dz_lpr[dz] & LPR_RCVE) lp->rcve = 1; /* rcv enb? on */\r
328 else lp->rcve = 0; /* else line off */\r
329 tmxr_poll_rx (&dz_desc); /* poll input */\r
330 dz_update_rcvi (); /* update rx intr */\r
331 break;\r
332\r
333 case 02: /* TCR */\r
334 if (access == WRITEB) data = (PA & 1)? /* byte? merge */\r
335 (dz_tcr[dz] & 0377) | (data << 8):\r
336 (dz_tcr[dz] & ~0377) | data;\r
337 if (dz_mctl) { /* modem ctl? */\r
338 dz_msr[dz] |= ((data & 0177400) & /* dcd |= dtr & ring */\r
339 ((dz_msr[dz] & DZ_LMASK) << MSR_V_CD));\r
340 dz_msr[dz] &= ~(data >> TCR_V_DTR); /* ring &= ~dtr */\r
341 if (dz_auto) { /* auto disconnect? */\r
342 int32 drop;\r
343 drop = (dz_tcr[dz] & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */\r
344 for (i = 0; i < DZ_LINES; i++) { /* drop hangups */\r
345 line = (dz * DZ_LINES) + i; /* get line num */\r
346 lp = &dz_ldsc[line]; /* get line desc */\r
347 if (lp->conn && (drop & (1 << i))) {\r
348 tmxr_linemsg (lp, "\r\nLine hangup\r\n");\r
349 tmxr_reset_ln (lp); /* reset line, cdet */\r
350 dz_msr[dz] &= ~(1 << (i + MSR_V_CD));\r
351 } /* end if drop */\r
352 } /* end for */\r
353 } /* end if auto */\r
354 } /* end if modem */\r
355 dz_tcr[dz] = data;\r
356 tmxr_poll_tx (&dz_desc); /* poll output */\r
357 dz_update_xmti (); /* update int */\r
358 break;\r
359\r
360 case 03: /* TDR */\r
361 if (PA & 1) { /* odd byte? */\r
362 dz_tdr[dz] = (dz_tdr[dz] & 0377) | (data << 8); /* just save */\r
363 break;\r
364 }\r
365 dz_tdr[dz] = data;\r
366 if (dz_csr[dz] & CSR_MSE) { /* enabled? */\r
367 line = (dz * DZ_LINES) + CSR_GETTL (dz_csr[dz]);\r
368 lp = &dz_ldsc[line]; /* get line desc */\r
369 c = sim_tt_outcvt (dz_tdr[dz], TT_GET_MODE (dz_unit.flags));\r
370 if (c >= 0) tmxr_putc_ln (lp, c); /* store char */\r
371 tmxr_poll_tx (&dz_desc); /* poll output */\r
372 dz_update_xmti (); /* update int */\r
373 }\r
374 break;\r
375 }\r
376\r
377return SCPE_OK;\r
378}\r
379\r
380/* Unit service routine\r
381\r
382 The DZ11 polls to see if asynchronous activity has occurred and now\r
383 needs to be processed. The polling interval is controlled by the clock\r
384 simulator, so for most environments, it is calibrated to real time.\r
385 Typical polling intervals are 50-60 times per second.\r
386\r
387 The simulator assumes that software enables all of the multiplexors,\r
388 or none of them.\r
389*/\r
390\r
391t_stat dz_svc (UNIT *uptr)\r
392{\r
393int32 dz, t, newln;\r
394\r
395for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */\r
396 t = t | (dz_csr[dz] & CSR_MSE);\r
397if (t) { /* any enabled? */\r
398 newln = tmxr_poll_conn (&dz_desc); /* poll connect */\r
399 if ((newln >= 0) && dz_mctl) { /* got a live one? */\r
400 dz = newln / DZ_LINES; /* get mux num */\r
401 if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */\r
402 dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */\r
403 else dz_msr[dz] |= (1 << newln); /* set ring */\r
404 }\r
405 tmxr_poll_rx (&dz_desc); /* poll input */\r
406 dz_update_rcvi (); /* upd rcv intr */\r
407 tmxr_poll_tx (&dz_desc); /* poll output */\r
408 dz_update_xmti (); /* upd xmt intr */\r
409 sim_activate (uptr, tmxr_poll); /* reactivate */\r
410 }\r
411return SCPE_OK;\r
412}\r
413\r
414/* Get first available character for mux, if any */\r
415\r
416int32 dz_getc (int32 dz)\r
417{\r
418uint32 i, line, c;\r
419\r
420for (i = c = 0; (i < DZ_LINES) && (c == 0); i++) { /* loop thru lines */\r
421 line = (dz * DZ_LINES) + i; /* get line num */\r
422 c = tmxr_getc_ln (&dz_ldsc[line]); /* test for input */\r
423 if (c & SCPE_BREAK) c = RBUF_VALID | RBUF_FRME; /* break? frame err */\r
424 if (c) c = c | (i << RBUF_V_RLINE); /* or in line # */\r
425 } /* end for */\r
426return c;\r
427}\r
428\r
429/* Update receive interrupts */\r
430\r
431void dz_update_rcvi (void)\r
432{\r
433int32 i, dz, line, scnt[DZ_MUXES];\r
434TMLN *lp;\r
435\r
436for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */\r
437 scnt[dz] = 0; /* clr input count */\r
438 for (i = 0; i < DZ_LINES; i++) { /* poll lines */\r
439 line = (dz * DZ_LINES) + i; /* get line num */\r
440 lp = &dz_ldsc[line]; /* get line desc */\r
441 scnt[dz] = scnt[dz] + tmxr_rqln (lp); /* sum buffers */\r
442 if (dz_mctl && !lp->conn) /* if disconn */\r
443 dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); /* reset car det */\r
444 }\r
445 }\r
446for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */\r
447 if (scnt[dz] && (dz_csr[dz] & CSR_MSE)) { /* input & enabled? */\r
448 dz_csr[dz] |= CSR_RDONE; /* set done */\r
449 if (dz_sae[dz] && (scnt[dz] >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */\r
450 dz_csr[dz] |= CSR_SA; /* set status */\r
451 dz_sae[dz] = 0; /* disable alarm */\r
452 }\r
453 }\r
454 else dz_csr[dz] &= ~CSR_RDONE; /* no, clear done */\r
455 if ((dz_csr[dz] & CSR_RIE) && /* int enable */\r
456 ((dz_csr[dz] & CSR_SAE)?\r
457 (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE)))\r
458 dz_set_rxint (dz); /* and alm/done? */\r
459 else dz_clr_rxint (dz); /* no, clear int */\r
460 }\r
461return;\r
462}\r
463\r
464/* Update transmit interrupts */\r
465\r
466void dz_update_xmti (void)\r
467{\r
468int32 dz, linemask, i, j, line;\r
469\r
470for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */\r
471 linemask = dz_tcr[dz] & DZ_LMASK; /* enabled lines */\r
472 dz_csr[dz] &= ~CSR_TRDY; /* assume not rdy */\r
473 j = CSR_GETTL (dz_csr[dz]); /* start at current */\r
474 for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */\r
475 j = (j + 1) & DZ_LNOMASK; /* next line */\r
476 line = (dz * DZ_LINES) + j; /* get line num */\r
477 if ((linemask & (1 << j)) && dz_ldsc[line].xmte) {\r
478 CSR_PUTTL (dz_csr[dz], j); /* put ln in csr */\r
479 dz_csr[dz] |= CSR_TRDY; /* set xmt rdy */\r
480 break;\r
481 }\r
482 }\r
483 if ((dz_csr[dz] & CSR_TIE) && (dz_csr[dz] & CSR_TRDY)) /* ready plus int? */\r
484 dz_set_txint (dz);\r
485 else dz_clr_txint (dz); /* no int req */\r
486 }\r
487return;\r
488}\r
489\r
490/* Interrupt routines */\r
491\r
492void dz_clr_rxint (int32 dz)\r
493{\r
494dz_rxi = dz_rxi & ~(1 << dz); /* clr mux rcv int */\r
495if (dz_rxi == 0) CLR_INT (DZRX); /* all clr? */\r
496else SET_INT (DZRX); /* no, set intr */\r
497return;\r
498}\r
499\r
500void dz_set_rxint (int32 dz)\r
501{\r
502dz_rxi = dz_rxi | (1 << dz); /* set mux rcv int */\r
503SET_INT (DZRX); /* set master intr */\r
504return;\r
505}\r
506\r
507int32 dz_rxinta (void)\r
508{\r
509int32 dz;\r
510\r
511for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */\r
512 if (dz_rxi & (1 << dz)) {\r
513 dz_clr_rxint (dz); /* clear intr */\r
514 return (dz_dib.vec + (dz * 010)); /* return vector */\r
515 }\r
516 }\r
517return 0;\r
518}\r
519\r
520void dz_clr_txint (int32 dz)\r
521{\r
522dz_txi = dz_txi & ~(1 << dz); /* clr mux xmt int */\r
523if (dz_txi == 0) CLR_INT (DZTX); /* all clr? */\r
524else SET_INT (DZTX); /* no, set intr */\r
525return;\r
526}\r
527\r
528void dz_set_txint (int32 dz)\r
529{\r
530dz_txi = dz_txi | (1 << dz); /* set mux xmt int */\r
531SET_INT (DZTX); /* set master intr */\r
532return;\r
533}\r
534\r
535int32 dz_txinta (void)\r
536{\r
537int32 dz;\r
538\r
539for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */\r
540 if (dz_txi & (1 << dz)) {\r
541 dz_clr_txint (dz); /* clear intr */\r
542 return (dz_dib.vec + 4 + (dz * 010)); /* return vector */\r
543 }\r
544 }\r
545return 0;\r
546}\r
547\r
548/* Device reset */\r
549\r
550t_stat dz_clear (int32 dz, t_bool flag)\r
551{\r
552int32 i, line;\r
553\r
554dz_csr[dz] = 0; /* clear CSR */\r
555dz_rbuf[dz] = 0; /* silo empty */\r
556dz_lpr[dz] = 0; /* no params */\r
557if (flag) dz_tcr[dz] = 0; /* INIT? clr all */\r
558else dz_tcr[dz] &= ~0377; /* else save dtr */\r
559dz_tdr[dz] = 0;\r
560dz_sae[dz] = 1; /* alarm on */\r
561dz_clr_rxint (dz); /* clear int */\r
562dz_clr_txint (dz);\r
563for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */\r
564 line = (dz * DZ_LINES) + i;\r
565 if (!dz_ldsc[line].conn) dz_ldsc[line].xmte = 1; /* set xmt enb */\r
566 dz_ldsc[line].rcve = 0; /* clr rcv enb */\r
567 }\r
568return SCPE_OK;\r
569}\r
570\r
571t_stat dz_reset (DEVICE *dptr)\r
572{\r
573int32 i, ndev;\r
574\r
575for (i = 0; i < DZ_MUXES; i++) dz_clear (i, TRUE); /* init muxes */\r
576dz_rxi = dz_txi = 0; /* clr master int */\r
577CLR_INT (DZRX);\r
578CLR_INT (DZTX);\r
579sim_cancel (&dz_unit); /* stop poll */\r
580ndev = ((dptr->flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));\r
581return auto_config (dptr->name, ndev); /* auto config */\r
582}\r
583\r
584/* Attach */\r
585\r
586t_stat dz_attach (UNIT *uptr, char *cptr)\r
587{\r
588t_stat r;\r
589extern int32 sim_switches;\r
590\r
591dz_mctl = dz_auto = 0; /* modem ctl off */\r
592r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */\r
593if (r != SCPE_OK) return r; /* error? */\r
594if (sim_switches & SWMASK ('M')) { /* modem control? */\r
595 dz_mctl = 1;\r
596 printf ("Modem control activated\n");\r
597 if (sim_log) fprintf (sim_log, "Modem control activated\n");\r
598 if (sim_switches & SWMASK ('A')) { /* autodisconnect? */\r
599 dz_auto = 1;\r
600 printf ("Auto disconnect activated\n");\r
601 if (sim_log) fprintf (sim_log, "Auto disconnect activated\n");\r
602 }\r
603 }\r
604return SCPE_OK;\r
605}\r
606\r
607/* Detach */\r
608\r
609t_stat dz_detach (UNIT *uptr)\r
610{\r
611return tmxr_detach (&dz_desc, uptr);\r
612}\r
613\r
614/* Show summary processor */\r
615\r
616t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc)\r
617{\r
618int32 i, t;\r
619\r
620for (i = t = 0; i < dz_desc.lines; i++) { /* get num conn */\r
621 if (dz_ldsc[i].conn) t = t + 1;\r
622 }\r
623if (t == 1) fprintf (st, "1 connection");\r
624else fprintf (st, "%d connections", t);\r
625return SCPE_OK;\r
626}\r
627\r
628/* SHOW CONN/STAT processor */\r
629\r
630t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r
631{\r
632int32 i, t;\r
633\r
634for (i = t = 0; i < dz_desc.lines; i++) { /* loop thru conn */\r
635 if (dz_ldsc[i].conn) {\r
636 t = 1; \r
637 if (val) tmxr_fconns (st, &dz_ldsc[i], i);\r
638 else tmxr_fstats (st, &dz_ldsc[i], i);\r
639 }\r
640 }\r
641if (t == 0) fprintf (st, "all disconnected\n");\r
642return SCPE_OK;\r
643}\r
644\r
645/* SET LINES processor */\r
646\r
647t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc)\r
648{\r
649int32 newln, i, t, ndev;\r
650t_stat r;\r
651\r
652if (cptr == NULL) return SCPE_ARG;\r
653newln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r
654if ((r != SCPE_OK) || (newln == dz_desc.lines)) return r;\r
655if ((newln == 0) || (newln % DZ_LINES)) return SCPE_ARG;\r
656if (newln < dz_desc.lines) {\r
657 for (i = newln, t = 0; i < dz_desc.lines; i++) t = t | dz_ldsc[i].conn;\r
658 if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))\r
659 return SCPE_OK;\r
660 for (i = newln; i < dz_desc.lines; i++) {\r
661 if (dz_ldsc[i].conn) {\r
662 tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n");\r
663 tmxr_reset_ln (&dz_ldsc[i]); /* reset line */\r
664 }\r
665 if ((i % DZ_LINES) == (DZ_LINES - 1))\r
666 dz_clear (i / DZ_LINES, TRUE); /* reset mux */\r
667 }\r
668 }\r
669dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */\r
670dz_desc.lines = newln;\r
671ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));\r
672return auto_config (dz_dev.name, ndev); /* auto config */\r
673}\r
674\r
675/* SHOW VECTOR processor */\r
676\r
677t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)\r
678{\r
679return show_vec (st, uptr, ((dz_desc.lines * 2) / DZ_LINES), desc);\r
680}\r
681\r
682/* SET LOG processor */\r
683\r
684t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)\r
685{\r
686char *tptr;\r
687t_stat r;\r
688int32 ln;\r
689\r
690if (cptr == NULL) return SCPE_ARG;\r
691tptr = strchr (cptr, '=');\r
692if ((tptr == NULL) || (*tptr == 0)) return SCPE_ARG;\r
693*tptr++ = 0;\r
694ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r
695if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;\r
696return tmxr_set_log (NULL, ln, tptr, desc);\r
697}\r
698\r
699/* SET NOLOG processor */\r
700\r
701t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)\r
702{\r
703t_stat r;\r
704int32 ln;\r
705\r
706if (cptr == NULL) return SCPE_ARG;\r
707ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r
708if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;\r
709return tmxr_set_nolog (NULL, ln, NULL, desc);\r
710}\r
711\r
712/* SHOW LOG processor */\r
713\r
714t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)\r
715{\r
716int32 i;\r
717\r
718for (i = 0; i < dz_desc.lines; i++) {\r
719 fprintf (st, "line %d: ", i);\r
720 tmxr_show_log (st, NULL, i, desc);\r
721 fprintf (st, "\n");\r
722 }\r
723return SCPE_OK;\r
724}\r
725\r
726\r
727\r