Commit | Line | Data |
---|---|---|
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 | |
63 | extern 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 | |
68 | extern 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 | |
73 | extern 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 | |
142 | extern int32 IREQ (HLVL);\r | |
143 | extern int32 sim_switches;\r | |
144 | extern FILE *sim_log;\r | |
145 | extern int32 tmxr_poll; /* calibrated delay */\r | |
146 | \r | |
147 | uint16 dz_csr[DZ_MUXES] = { 0 }; /* csr */\r | |
148 | uint16 dz_rbuf[DZ_MUXES] = { 0 }; /* rcv buffer */\r | |
149 | uint16 dz_lpr[DZ_MUXES] = { 0 }; /* line param */\r | |
150 | uint16 dz_tcr[DZ_MUXES] = { 0 }; /* xmit control */\r | |
151 | uint16 dz_msr[DZ_MUXES] = { 0 }; /* modem status */\r | |
152 | uint16 dz_tdr[DZ_MUXES] = { 0 }; /* xmit data */\r | |
153 | uint8 dz_sae[DZ_MUXES] = { 0 }; /* silo alarm enabled */\r | |
154 | uint32 dz_rxi = 0; /* rcv interrupts */\r | |
155 | uint32 dz_txi = 0; /* xmt interrupts */\r | |
156 | int32 dz_mctl = 0; /* modem ctrl enabled */\r | |
157 | int32 dz_auto = 0; /* autodiscon enabled */\r | |
158 | TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */\r | |
159 | TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */\r | |
160 | \r | |
161 | DEVICE dz_dev;\r | |
162 | t_stat dz_rd (int32 *data, int32 PA, int32 access);\r | |
163 | t_stat dz_wr (int32 data, int32 PA, int32 access);\r | |
164 | int32 dz_rxinta (void);\r | |
165 | int32 dz_txinta (void);\r | |
166 | t_stat dz_svc (UNIT *uptr);\r | |
167 | t_stat dz_reset (DEVICE *dptr);\r | |
168 | t_stat dz_attach (UNIT *uptr, char *cptr);\r | |
169 | t_stat dz_detach (UNIT *uptr);\r | |
170 | t_stat dz_clear (int32 dz, t_bool flag);\r | |
171 | int32 dz_getc (int32 dz);\r | |
172 | void dz_update_rcvi (void);\r | |
173 | void dz_update_xmti (void);\r | |
174 | void dz_clr_rxint (int32 dz);\r | |
175 | void dz_set_rxint (int32 dz);\r | |
176 | void dz_clr_txint (int32 dz);\r | |
177 | void dz_set_txint (int32 dz);\r | |
178 | t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
179 | t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
180 | t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);\r | |
181 | t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
182 | t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
183 | t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc);\r | |
184 | t_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 | |
193 | DIB 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 | |
198 | UNIT dz_unit = { UDATA (&dz_svc, UNIT_IDLE|UNIT_ATTABLE|DZ_8B_DFLT, 0) };\r | |
199 | \r | |
200 | REG dz_nlreg = { DRDATA (NLINES, dz_desc.lines, 6), PV_LEFT };\r | |
201 | \r | |
202 | REG 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 | |
219 | MTAB 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 | |
249 | DEVICE 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 | |
259 | t_stat dz_rd (int32 *data, int32 PA, int32 access)\r | |
260 | {\r | |
261 | int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */\r | |
262 | \r | |
263 | switch ((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 | |
293 | return SCPE_OK;\r | |
294 | }\r | |
295 | \r | |
296 | t_stat dz_wr (int32 data, int32 PA, int32 access)\r | |
297 | {\r | |
298 | int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */\r | |
299 | int32 i, c, line;\r | |
300 | TMLN *lp;\r | |
301 | \r | |
302 | switch ((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 | |
377 | return 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 | |
391 | t_stat dz_svc (UNIT *uptr)\r | |
392 | {\r | |
393 | int32 dz, t, newln;\r | |
394 | \r | |
395 | for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */\r | |
396 | t = t | (dz_csr[dz] & CSR_MSE);\r | |
397 | if (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 | |
411 | return SCPE_OK;\r | |
412 | }\r | |
413 | \r | |
414 | /* Get first available character for mux, if any */\r | |
415 | \r | |
416 | int32 dz_getc (int32 dz)\r | |
417 | {\r | |
418 | uint32 i, line, c;\r | |
419 | \r | |
420 | for (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 | |
426 | return c;\r | |
427 | }\r | |
428 | \r | |
429 | /* Update receive interrupts */\r | |
430 | \r | |
431 | void dz_update_rcvi (void)\r | |
432 | {\r | |
433 | int32 i, dz, line, scnt[DZ_MUXES];\r | |
434 | TMLN *lp;\r | |
435 | \r | |
436 | for (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 | |
446 | for (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 | |
461 | return;\r | |
462 | }\r | |
463 | \r | |
464 | /* Update transmit interrupts */\r | |
465 | \r | |
466 | void dz_update_xmti (void)\r | |
467 | {\r | |
468 | int32 dz, linemask, i, j, line;\r | |
469 | \r | |
470 | for (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 | |
487 | return;\r | |
488 | }\r | |
489 | \r | |
490 | /* Interrupt routines */\r | |
491 | \r | |
492 | void dz_clr_rxint (int32 dz)\r | |
493 | {\r | |
494 | dz_rxi = dz_rxi & ~(1 << dz); /* clr mux rcv int */\r | |
495 | if (dz_rxi == 0) CLR_INT (DZRX); /* all clr? */\r | |
496 | else SET_INT (DZRX); /* no, set intr */\r | |
497 | return;\r | |
498 | }\r | |
499 | \r | |
500 | void dz_set_rxint (int32 dz)\r | |
501 | {\r | |
502 | dz_rxi = dz_rxi | (1 << dz); /* set mux rcv int */\r | |
503 | SET_INT (DZRX); /* set master intr */\r | |
504 | return;\r | |
505 | }\r | |
506 | \r | |
507 | int32 dz_rxinta (void)\r | |
508 | {\r | |
509 | int32 dz;\r | |
510 | \r | |
511 | for (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 | |
517 | return 0;\r | |
518 | }\r | |
519 | \r | |
520 | void dz_clr_txint (int32 dz)\r | |
521 | {\r | |
522 | dz_txi = dz_txi & ~(1 << dz); /* clr mux xmt int */\r | |
523 | if (dz_txi == 0) CLR_INT (DZTX); /* all clr? */\r | |
524 | else SET_INT (DZTX); /* no, set intr */\r | |
525 | return;\r | |
526 | }\r | |
527 | \r | |
528 | void dz_set_txint (int32 dz)\r | |
529 | {\r | |
530 | dz_txi = dz_txi | (1 << dz); /* set mux xmt int */\r | |
531 | SET_INT (DZTX); /* set master intr */\r | |
532 | return;\r | |
533 | }\r | |
534 | \r | |
535 | int32 dz_txinta (void)\r | |
536 | {\r | |
537 | int32 dz;\r | |
538 | \r | |
539 | for (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 | |
545 | return 0;\r | |
546 | }\r | |
547 | \r | |
548 | /* Device reset */\r | |
549 | \r | |
550 | t_stat dz_clear (int32 dz, t_bool flag)\r | |
551 | {\r | |
552 | int32 i, line;\r | |
553 | \r | |
554 | dz_csr[dz] = 0; /* clear CSR */\r | |
555 | dz_rbuf[dz] = 0; /* silo empty */\r | |
556 | dz_lpr[dz] = 0; /* no params */\r | |
557 | if (flag) dz_tcr[dz] = 0; /* INIT? clr all */\r | |
558 | else dz_tcr[dz] &= ~0377; /* else save dtr */\r | |
559 | dz_tdr[dz] = 0;\r | |
560 | dz_sae[dz] = 1; /* alarm on */\r | |
561 | dz_clr_rxint (dz); /* clear int */\r | |
562 | dz_clr_txint (dz);\r | |
563 | for (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 | |
568 | return SCPE_OK;\r | |
569 | }\r | |
570 | \r | |
571 | t_stat dz_reset (DEVICE *dptr)\r | |
572 | {\r | |
573 | int32 i, ndev;\r | |
574 | \r | |
575 | for (i = 0; i < DZ_MUXES; i++) dz_clear (i, TRUE); /* init muxes */\r | |
576 | dz_rxi = dz_txi = 0; /* clr master int */\r | |
577 | CLR_INT (DZRX);\r | |
578 | CLR_INT (DZTX);\r | |
579 | sim_cancel (&dz_unit); /* stop poll */\r | |
580 | ndev = ((dptr->flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));\r | |
581 | return auto_config (dptr->name, ndev); /* auto config */\r | |
582 | }\r | |
583 | \r | |
584 | /* Attach */\r | |
585 | \r | |
586 | t_stat dz_attach (UNIT *uptr, char *cptr)\r | |
587 | {\r | |
588 | t_stat r;\r | |
589 | extern int32 sim_switches;\r | |
590 | \r | |
591 | dz_mctl = dz_auto = 0; /* modem ctl off */\r | |
592 | r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */\r | |
593 | if (r != SCPE_OK) return r; /* error? */\r | |
594 | if (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 | |
604 | return SCPE_OK;\r | |
605 | }\r | |
606 | \r | |
607 | /* Detach */\r | |
608 | \r | |
609 | t_stat dz_detach (UNIT *uptr)\r | |
610 | {\r | |
611 | return tmxr_detach (&dz_desc, uptr);\r | |
612 | }\r | |
613 | \r | |
614 | /* Show summary processor */\r | |
615 | \r | |
616 | t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
617 | {\r | |
618 | int32 i, t;\r | |
619 | \r | |
620 | for (i = t = 0; i < dz_desc.lines; i++) { /* get num conn */\r | |
621 | if (dz_ldsc[i].conn) t = t + 1;\r | |
622 | }\r | |
623 | if (t == 1) fprintf (st, "1 connection");\r | |
624 | else fprintf (st, "%d connections", t);\r | |
625 | return SCPE_OK;\r | |
626 | }\r | |
627 | \r | |
628 | /* SHOW CONN/STAT processor */\r | |
629 | \r | |
630 | t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
631 | {\r | |
632 | int32 i, t;\r | |
633 | \r | |
634 | for (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 | |
641 | if (t == 0) fprintf (st, "all disconnected\n");\r | |
642 | return SCPE_OK;\r | |
643 | }\r | |
644 | \r | |
645 | /* SET LINES processor */\r | |
646 | \r | |
647 | t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
648 | {\r | |
649 | int32 newln, i, t, ndev;\r | |
650 | t_stat r;\r | |
651 | \r | |
652 | if (cptr == NULL) return SCPE_ARG;\r | |
653 | newln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r | |
654 | if ((r != SCPE_OK) || (newln == dz_desc.lines)) return r;\r | |
655 | if ((newln == 0) || (newln % DZ_LINES)) return SCPE_ARG;\r | |
656 | if (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 | |
669 | dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */\r | |
670 | dz_desc.lines = newln;\r | |
671 | ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES));\r | |
672 | return auto_config (dz_dev.name, ndev); /* auto config */\r | |
673 | }\r | |
674 | \r | |
675 | /* SHOW VECTOR processor */\r | |
676 | \r | |
677 | t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
678 | {\r | |
679 | return show_vec (st, uptr, ((dz_desc.lines * 2) / DZ_LINES), desc);\r | |
680 | }\r | |
681 | \r | |
682 | /* SET LOG processor */\r | |
683 | \r | |
684 | t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
685 | {\r | |
686 | char *tptr;\r | |
687 | t_stat r;\r | |
688 | int32 ln;\r | |
689 | \r | |
690 | if (cptr == NULL) return SCPE_ARG;\r | |
691 | tptr = strchr (cptr, '=');\r | |
692 | if ((tptr == NULL) || (*tptr == 0)) return SCPE_ARG;\r | |
693 | *tptr++ = 0;\r | |
694 | ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r | |
695 | if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;\r | |
696 | return tmxr_set_log (NULL, ln, tptr, desc);\r | |
697 | }\r | |
698 | \r | |
699 | /* SET NOLOG processor */\r | |
700 | \r | |
701 | t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc)\r | |
702 | {\r | |
703 | t_stat r;\r | |
704 | int32 ln;\r | |
705 | \r | |
706 | if (cptr == NULL) return SCPE_ARG;\r | |
707 | ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r);\r | |
708 | if ((r != SCPE_OK) || (ln >= dz_desc.lines)) return SCPE_ARG;\r | |
709 | return tmxr_set_nolog (NULL, ln, NULL, desc);\r | |
710 | }\r | |
711 | \r | |
712 | /* SHOW LOG processor */\r | |
713 | \r | |
714 | t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc)\r | |
715 | {\r | |
716 | int32 i;\r | |
717 | \r | |
718 | for (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 | |
723 | return SCPE_OK;\r | |
724 | }\r | |
725 | \r | |
726 | \r | |
727 | \r |